Thursday Apr 02, 2009

Glassfish v3, EJB 3.1 and Jersey

With Glassfish V3 promoted build 43 (or greater) and the latest Jersey 1.0.3-SNAPSHOT it is now possible to create no-interface-view session beans (or POJO session beans) deployed in the war and those beans may be either (root) resource or provider classes.

A big thanks to Ken Saks who provided the hooks in the Glassfish EJB module so Jersey can dynamically plug-in if Glassfish EJB support is available.

For example one could develop the following root resource class:

@Stateless
@Path("ssb")
public class StatelessSessionRootResource {

    @Context private UriInfo ui; 
    @GET
    public String get() {
        return "GET: " + ui.getRequestUri().toASCIIString();
    }
}

Notice the annotated field, ui,  to obtain an instance of UriInfo. Jersey will defer to JNDI to obtain an instance of the session bean (using the EJB 3.1 portable naming mechanism) and the EJB module will inform Jersey when an instance of the session bean is constructed so that Jersey gets a chance to inject Jersey/JAX-RS artifacts.

Session beans can also be used for sub-resources. For example one can add another resource class:

@Stateless
public class StatelessSessionResource {

    @Context private UriInfo ui;

    @GET
    public String get() {
        return "GET: " + ui.getRequestUri().toASCIIString();
    }
}

and then modify the StatelessSessionRootResource class to be as follows:

@Stateless
@Path("ssb")
public class StatelessSessionRootResource {

    @Context private UriInfo ui;

    @GET
    public String get() {
        return "GET: " + ui.getRequestUri().toASCIIString();
    }

    @EJB StatelessSessionResource r; 
    @Path("sub")
    public StatelessSessionResource getSub() {
        return r;
    }
}

A reference to StatelessSessionResource is injected onto the root resource class and then the sub-resource locator method, getSub, returns that reference.

Alternatively the same functionality can be achieved using the Jersey specific feature of returning the class:

@Path("sub/class")
public Class<StatelessSessionResource> getSubClass() {
    return StatelessSessionResource.class;
}

See here for a simple maven project, which contains the resource classes presented above, and can be built to create a war file to deploy to Glassfish V3. The following URIs will exercise the application:

http://localhost:8080/ejb-1.0/rs/ssb

http://localhost:8080/ejb-1.0/rs/ssb/sub

http://localhost:8080/ejb-1.0/rs/ssb/sub/class

Tuesday Dec 02, 2008

Jersey, Glassfish, and EJBs as root resources

Jersey supports EJB 3.0 beans as root resources as follows:

  1. Annotate a local or remote interface with @Path and annotate methods as appropriate; and
  2. Ensure that the local or remote interface in 1) is registered by file/directory or package scanning.

The registration mechanism in 2) is no different for registering non-EJBs. The caveat: it currently only works with Glassfish, which supports JNDI lookup of an EJB reference using the fulling qualified class name of the local or remote interface.

The JSR 311 expert group is currently considering approaches to integrate JAX-RS with EJB 3.1, which should present some nice improvements, namely EJBs bundled in the war and EJBs with no interfaces. I have high hopes we can retain the current ease of use registration aspects with JAX-RS as presented here and then it should be really simple to use EJBs as POJOs in the web tier directly serving HTTP requests.

There are already some EJB 3.1 features ready in Glassfish Prelude, as highlighted by Ken, with update centre instructions from Mahesh. Now i need to find the time to experiment...

Thursday Jun 26, 2008

@EJB injection

Jersey has a simple injection provider SPI for injecting instances for annotated fields, method/constructor parameters or setter methods. So it is possible to plug-in your own injection functionality.

Out of the box there is currently no EE-based functionality supported in Jersey but using the injection provider SPI it is very easy to have basic support for @EJB in one small class.

If you have the following resource:

@Path("foo")
public class FooResource {
    @EJB private FooSessionRemote fooSessionRemoteBean;
    
    @GET
    @ProduceMime("text/plain")
    public String get() throws Exception {
        return fooSessionRemoteBean.fooMethod();
    }
}

then the field fooSessionRemoteBean should get injected with an instance of the remote EJB interface.

The following provider class supports this behaviour:

@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {

    public Scope getScope() {
        return Scope.Singleton;
    }

    public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
        if (!(t instanceof Class)) return null;
        
        try {
            Class c = (Class)t;        
            Context ic = new InitialContext();

            final Object o = ic.lookup(c.getName());
            
            return new Injectable<Object>() {
                public Object getValue(HttpContext c) {
                    return o;
                }                    
            };            
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

The EJB reference is looked up using JNDI then an Injectable instance is returned with that reference. This is efficient for per-request resources as the JNDI look up is only performed once. Since the above class is annotated with @Provider it will get picked up and treated like any other provider.

Obviously this could do with some polish to fully implement @EJB injection functionality but i think this example is instructive how one could support other annotations.

About

sandoz

Search

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