Friday Dec 11, 2009

Portable Global JNDI names

The introduction of dependency injection in JavaEE5 did reduce the need for doing a JNDI lookup. However, there are times when the users / clients had to rely on the good old JNDI lookup to acquire EJB references. Typical examples of such clients performing lookup of EJBs include (a) a JavaEE component from a different application and (b) a Java SE client.

The problem was such clients had to use “global” jndi name to lookup the target bean. All along the ejb specifications had been silent about portability of such global jndi names. This allowed each vendor to assign a global jndi names to EJBs in a vendor specific way. This meant that the client code that performed a lookup using global JNDI names were inherently non portable across appserver vendor implementations.

For example, the following code (part of a non JavaEE client) assumes that FooBean has been mapped to the global jndi name: "_app1_mod1_FooBean"



public static void main(String[] args)
    throws Exception {

    InitialContext ic = new InitialContext();
    FooBean fooBean = (FooBean)
            ic.lookup("_app1_mod1_FooBean");

    //Use fooBean
}


This code might break if the target bean was deployed to a different JavaEE server.

Portable Global JNDI name in EJB 3.1

EJB 3.1 solves the above problem by mandating that every container must assign (at least one) well defined global JNDI names to EJBs.
The general syntax of a (portable) global JNDI name of an EJB is of the form:

java:global/[<application-name>]/<module-name>/<bean-name>!<fully-qualified-bean-interface-name>

In addition to the above name, if the EJB exposes just a single client view (that is it implements just one interface or the no interface view), the container is also mandated to map the bean to


java:global/[<application-name>]/<module-name>/<bean-name>

Where

  1. <aplication-name> defaults to the bundle name (.ear file name) without the bundle extension. This can be overridden in application.xml. Also, <application-name> is applicable only if the bean is packaged inside a .ear file.
  2. <module-name> defaults to bundle name (.war or .jar) without the bundle extension. Again, this can be overridden in ejb-jar.xml.
  3. <bean-name> defaults to the unqualified class name of the bean. However, if @Stateful or @Stateless or @Singleton uses the name attribute, then the value specified there will be used as the bean name.

Example 1:




Assuming that the following classes and interfaces are packaged inside hello.jar and deployed as a stand alone module


package com.acme;
@Local
public interface Hello {
    public String sayHello();
}

package com.acme;
@Local
public interface GoodBye {
    public String sayBye();
}

package com.acme;
@Stateless
public class MyEJB
    implements Hello, GoodBye {
    ...
}

package com.acme;
@Singleton(name="HelloSingleton")
public class HelloBean {
    ...
}

package com.acme;
@Stateful
public class ShoppingCart
    ...
}

package com.acme;
public class Util { //Not a EJB or Servlet
    ...
}

The following portable jndi names are then made available by the container to the clients:


java:global/hello/MyEJB!com.acme.Hello
java:global/hello/MyEJB!com.acme.GoodBye

java:global/hello/HelloSingleton
java:global/hello/HelloSingleton!com.acme.HelloBean

java:global/hello/ShoppingCart
java:global/hello/ShoppingCart!com.acme.ShoppingCart


Note:

  1. Since MyEJB implements more than one interface, the global jndi names must include the implemented interface
  2. For HelloBean, the value specified in the name() attribute is used as <bean-name>
  3. Since HelloBean bean exposes a no interface view, the qualified bean class name is used as <fully-qualified-bean-intf-name>
  4. Since ShoppingCart bean exposes a no interface view, the qualified bean class name is used as <fully-qualified-bean-intf-name>
  5. Since, the application is deployed as a standalone module, <app-name> is not used in the global jndi name.

Client code:


InitialContext ic = new InitialContext();
Hello = (Hello) ic.lookup("java:global/hello/MyEJB!com.acme.Hello");
GoodBye = (GoodBye) ic.lookup("java:global/hello/MyEJB!com.acme.GoodBye");

ShoppingCart = (ShoppingCart) ic.lookup("java:global/hello/ShoppingCart");


You can also use the portable jndi names in injection too

@EJB(lookupName="java:global/hello/ShoppingCart")

private ShoppingCart cart;

More name spaces


In addition to the java:global namespace, the container is also required to make the bean(s) available under two other name spaces:
java:app and java:module


Why do we need these two? In the case of java:global, the name contains a hard coded <app-name> and (or) <module-name>. Assuming, that <app-name> and <module-name> are not specified in .xml, re-packaging the bean and client into a different module breaks the client. For example, if FooBean was originally packaged inside foo.jar, the client that looked up using ic.lookup("java:global/foo/FooBean") will break if FooBean is re-packaged inside module2.jar

Since, most of the time the beans and the clients are colocated in the same application or even within the same module, EJB 3.1 allows accessing these colocated beans in a easier way. The spec defines two more name spaces called java:app and java:module.

java:module allows a component executing within a Java EE application to access a namespace
rooted below the <module-name> portion of the namespace corresponding to its module.

You can think of java:module as the jndi sub-context that is rooted under the "current module" in which the client is located. java:module differs from java:global in the sense that the client can access only those beans that are packaged inside the same module as the client. If a component in module1 has to lookup a component in module2, then it has to use java:global (or java:app).

Similarly,
can think of java:app as the jndi sub-context that is rooted under the "current app" in which the client is located.

The java:app and java:module names are of the form:

java:app/<module-name>/<bean-name>!<fully-qualified-intf-name>

and

java:module/<bean-name>!<fully-qualified-intf-name>


In our example, the Util class can access other components as follows:

java:app/hello/MyEJB!com.acme.Hello
java:app/hello/MyEJB!com.acme.GoodBye

java:app/hello/HelloSingleton
java:app/hello/HelloSingleton!com.acme.HelloBean

java:app/hello/ShoppingCart
java:app/hello/ShoppingCart!com.acme.ShoppingCart

java:module/MyEJB!com.acme.Hello
java:module/MyEJB!com.acme.GoodBye

java:module/HelloSingleton
java:module/HelloSingleton!com.acme.HelloBean

java:module/ShoppingCart
java:module/ShoppingCart!com.acme.ShoppingCart



Running the sample application

  1. Save and unzip  portable-jndi-app.zip
  2. cd portable-jndi-name
  3. mvn install will build the application. The .war file will be under target directory
  4. <v3-install-dir>/bin/asadmin deploy --force=true target/portable-jndi-app.war
  5. Open a browser and access localhost:8080/webejb/Example1Servlet
I will be updating this blog with one more sample app where the EJBs and Servlets are packaged inside a .ear file.

Also, I have used mvn as the build / packing tool.

References


[1] EJB 3.1 Specification

[2] Ken Saks' note on portable jndi name

Thursday Nov 06, 2008

Singleton EJB support in GlassFish V3 Prelude

The GlassFish Enterprise Server V3 Prelude has been released. To get a sneak preview of some of the EJB 3.1 features in V3 Prelude, you need to install ejb container by following the instructions from my earlier blog

In this blog, I will describe one of the EJB 3.1 features available in V3 Prelude: Singleton EJBs.

One of the frequent problems that ejb developers face is to figure out how to share data between multiple components of an application. Singleton session beans are meant for this purpose. A Singleton EJB is a session bean component that is instantiated once per application. A Singleton session bean is intended to be shared by concurrent requests. In other words, all requests to the singleton will be routed to the single instance of the Singleton bean instance.

Let me demonstrate this by using a simple application. Lets say that we want to count the number of times a HelloServlet was accessed. Though there are other ways to do this, lets use a Singleton bean to accomplish the task. Note that, we can not maintain a counter inside a Stateless session bean as the container might maintain a pool of these stateless bean instances (and each will have their own counters). The Singleton session bean (called CounterBean) keeps a counter. It will have a incrementAndGetHitCount() method that increments the counter and will be called from the SimpleServletServlet.

Defining a Singleton bean

A singleton bean can be defined by using the @Singleton annotation. Note that Singleton beans can have business interfaces and interceptors just like Stateless and Stateful session beans. Also, remember that EJB 3.1 now allows optional interface view. More can be read about optional interface view in my earlier blog.

package com.sun.ejb31.test;

import javax.ejb.Singleton;
@Singleton
public class CounterBean {
    private int hitCount;

    //Note the use of synchronized keyword
    public synchronized int incrementAndGetHitCount() {
        return hitCount++;
    }

}

Handling concurrency in a Singleton

Since there is only one instance of the Singleton bean, the container routes all the requests (method invocations) to the single instance. This means that concurrent invocations are possible. The EJB 3.1 specification allows two choices to handle concurrency issues:

Container Managed Concurrency (CMC): With Container Managed Concurrency, the container is responsible for controlling concurrent access to the bean instance based on method-level locking metadata. Each business method method can be annotated with either a Read(shared) lock or Write (exclusive) lock Note: GlassFish V3 Prelude supports only BMC.

Bean Managed Concurrency (BMC): With Bean Managed Concurrency demarcation, the container allows full concurrent access to the Singleton bean instance. It is the responsibility of the bean developer to guard its state as necessary against synchronization errors due to concurrent access.

Obtaining a reference to the Singleton bean

Obtaining a reference to a Singleton bean is no different from obtaining a reference to other types of beans. In our example, we will inject a reference to the Singleton bean into our Servlet (though a JNDI lookup would have worked as well too).
package com.sun.ejb31.test;

...
import javax.ejb.EJB;

public class SimpleServlet extends HttpServlet {
   
    @EJB CounterBean counterBean;
    
    protected void processRequest(
        HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet SimpleServlet</title>");  
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Number of times this servlet is accessed: "
                    + counterBean.incrementAndGetHitCount());
            out.println("</body>");
            out.println("</html>");
        } finally { 
            out.close();
        }
    }

    ...
    ... 

}

How to deploy and run

Assuming that you already have installed the ejb container in V3 Prelude, (if not follow these instructions)

To start the server: java -jar <install_dir>/modules/glassfish.jar

To deploy: <install_dir>/bin/asadmin deploy SimpleCounter.war

To redeploy: <install_dir>/bin/asadmin deploy --force=true SimpleCounter.war

URL to access the servlet: http://localhost:8080/SingletonCounter/SimpleServlet

Resources

EJB 3.1 public draft

SimpleCounter.war

Source files: CounterBean.java and SimpleServlet.java

EJB 3.1 Container in GlassFish V3 Prelude

The GlassFish Enterprise Server V3 Prelude has been released. In this blog, I will describe the steps to install the EJB container to have a sneak preview of some of the EJB 3.1 features.
  • First download the V3 prelude bundle
  • Then start the server by doing: java -jar <install_dir>/glassfish/modules/glassfish.jar
  • Open a browser window and access the V3 administration GUI by accessing the url: http://localhost:4848
  • From the left panel, select the uptate tool
  • Select glassfish-ejb component and click install to install the ejb-container module.
  • Restart the server and you are now ready to deploy ejb applications to the V3 prelude application server
  • Note:

    Only Stateless Session beans and Singleton beans with local interfaces, no interface view are supported. Stateful, Message driven and EJB 2.x entity beans are not supported. Remote interfaces and Remote business interfaces for any of the bean type are not supported yet. Timer Service is supported. See Marina's blog about timer service.

    EJB container implementation in V3 Prelude gives you an early look at some of the EJB 3.1 features. It is not a full, feature-complete container implementation and is not suitable for production deployments. It is suitable for experimentation and exploration. Experiment, take a look at the new approach being taken in GlassFish v3, and then let us know what you think

    For a full list of what is planned in EJB3.1 please refer to Ken's blog

    Monday May 05, 2008

    Installing EJB Container in GlassFish V3

    The EJB 3.1 Specification has a load of features that simplifies EJB development even further. A couple of EJB 3.1 features have been implemented in GlassFish V3. In this blog I will describe how EJB container can be installed in GlassFish V3.

    Installing EJB 3.1 Container module in GlassFish V3 TP2

    1. First download and install GlassFish V3 Technology Preview 2
    2. cd to <V3_install_dir>/bin
    3. run update tool (./updatetool). If you are running it for the first time, it will install the update tool. Rerun it again to run the update tool
      1. From the left panel, pick the Available add-ons
      2. Click the glassfishv3-ejb checkbox and click install
      3. Accept the License agreement by pressing Accept. This will install the ejb-container module
    See my other blog for a sneak preview of some of the EJB 3.1 features in GlassFish V3

    EJB 3.1 in GlassFish V3 TP2

    In this blog, I will describe some of the EJB 3.1 features that are available in GlassFish V3.

    For a full list of what is planned in EJB3.1 please refer to Ken's blog

    Note: Before, you run any of the EJB 3.1 applications ensure that you follow the steps outlined in Installing EJB container in GlassFish V3

    What EJB features are available in GlassFish V3 TP2

    Only Stateless Session beans with local interfaces are supported. Stateful, Message driven and EJB 2.x entity beans are not supported. Remote interfaces and Remote business interfaces for any of the bean type are not supported yet. Timer Service is supported, but a little bit of configuration is needed to enable it. We will be blogging about how to enable TimerService in GlassFish V3 shortly.

    Support for other types of beans will be available soon.

    Note: TP2 gives you an early look at GlassFish v3. It is not a full, feature-complete application server and is not suitable for production deployments. It is suitable for experimentation and exploration. Experiment, take a look at the new approach being taken in GlassFish v3, and then let us know what you think

    Using GlassFish V3 server

    To run the sample application provided, follow the steps mentioned in How to run the hello.war

    Quick start guide provides more details on how to use the GlassFish V3 server.

    Optional Local Business Interfaces

    Recall that even though EJB 3.1 simplified the EJB development by introducing the business interfaces, the bean developer must still write at least one interface. For most of the applications this is again an overhead. In EJB 3.1 an EJB need not implement any interface as long as it contains one of the component defining annotations (or the XML equivalent). So a simple EJB 3.1 HelloBean looks like this:

    @Stateless
    public class HelloBean {
    public String sayHello() {
    return "Hello, World!!";
    }
    }

    Note: The client still has to perform a JNDI lookup or inject a reference of the bean. More specifically, it cannot use the new operator to construct the bean.

    So a Servlet that use the HelloBean will be coded like the following: public class HelloServlet {
    @EJB private HelloBean hello;
    ....
    hello.sayHello();
    ....
    }

    Simplified packaging

    JavaEE 5 greatly improved the ease of use by providing a bunch of annotations that that obviated the need for XMLs. However, it still required that Servlets/JSPs be packaged in a .war file and EJBs be packaged (in possibly multiple) .jar files. These files must further be packaged inside a .ear file. For simple web applications that wanted to use EJBs, the above packaging restrictions was a bit of an overkill

    Another cool feature that is introduced in EJB 3.1 is the simplification of packaging requirements of EJBs. Now, EJB classes can be packaged inside the .war file itself!! The classes must reside under WEB-INF/classes.

    Because of the above two features, the structure of our hello.war looks like this.

    META-INF/
    META-INF/MANIFEST.MF
    WEB-INF/
    WEB-INF/classes/
    WEB-INF/classes/com/
    WEB-INF/classes/com/sun/
    WEB-INF/classes/com/sun/v3/
    WEB-INF/classes/com/sun/v3/demo/
    WEB-INF/classes/com/sun/v3/demo/HelloEJB.class
    WEB-INF/classes/com/sun/v3/demo/HelloServlet.class
    WEB-INF/web.xml
    index.jsp

    How to run hello.war

    Download the attachments provided. HelloEJB31.war contains the application that can be deployed. HelloEJB31.zip contains the sources.

    1. Start the server by running: <install_dir>/asadmin start-domain
    2. Deploy the application by running: <install_dir>/asadmin deploy hello.war
    3. Open a browser and go to: http://localhost:8080/HelloEJB31/HelloServlet

    About

    Mahesh Kannan

    Search

    Categories
    Archives
    « April 2014
    SunMonTueWedThuFriSat
      
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
       
           
    Today