EJB 3.1 And REST - The Lightweight Hybrid

The Local / Remote interfaces in EJB 3.1 are optional. You can still, however, expose a Session bean as a RESTFul (JSR-311) service.


package com.abien.patterns.business.rest.boundary;

import com.abien.patterns.business.rest.control.Service;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Stateless
@Path("current")
public class ServiceFacade {

    @EJB
    Service service;

    @GET
    public String getDate(){
        return service.getCurrentDate().toString();
    }

}


The Service is just another, usual, @Local bean:


@Stateless
public class Service {

    public Date getCurrentDate(){
        return new Date();
    }
}


A ServiceFacade becomes available via REST, just denoting it with the JAR-RS annotations. Its both an EJB 3.1 and a REST-resource - it is available under http://localhost:8080/EJBRestHybrid/resources/current (tested with Glassfish v3 preview). It will return the current time as String (Mon Jun 29 08:19:32 CEST 2009). The additional @Stateless has the following advantages:

  • Injection capabilities: you can easily inject other EJBs, EntityManagers, JMS-resources, DataSources or JCA connectors
  • Transactions: all changes made in a REST-call will be automatically and transparently synchronized with the database
  • Single threading programming model -> the old EJB goodness.
  • Monitoring: an EJB is visible in JMX
  • Throttling: its easy to restrict the concurrency of an EJB using ThreadPools or bean pools
  • Vendor-independence: EJB 3 runs on multiple containers, without any modification (and without any XML in particular :-))

Exposing a protocol-neutral ServiceFacade directly via REST can make it REST-dependent. E.g. you may pass JAXB-enabled classes as parameters / return - values. It will be hard then to expose the ServiceFacade through other channels. On the other hand - if REST is all you need, it is the simplest and leanest approach. There are no additional libraries needed - everything is already included in a Java EE 6 container (in Glassfish v3 the whole EJB 3.1 container is < 1 MB...). 

The whole example project (tested with Netbeans 6.7rc3 and Glassfish v3 Preview) with source code was pushed into http://kenai.com/projects/javaee-patterns. In Netbeans 6.7 you will have to enable Glassfish v3 capabilities. If you are using vi or emacs :-), you will have to include the Java EE 6 API to the classpath.

[This sample is based on the ServiceFacade pattern from the "Real World Java EE Patterns" book] 

Comments:

Yes, I think the EJB31/JAX-RS combination has a bright future (partly why I used this to illustrate the GlassFish v3 distro/packaging feature in http://blogs.sun.com/alexismp/entry/glassfish_v3_custom_distributions_with)

Posted by Alexis MP on June 29, 2009 at 05:42 PM CEST #

@Alexis,

I use this combination in some projects. It was, however, two-layer architecture with GF 2.1. With GF v3 and EJB 3.1 we will be able to eliminate one layer -> always good stuff!,

thanks & regards,

adam

Posted by Adam Bien on June 29, 2009 at 07:13 PM CEST #

How about call performance:
Traditional RMI-IIOP versus http/RestFull ?

Posted by Sakari on May 27, 2010 at 11:21 AM CEST #

Hi, I tried your example with 2 modifications:

1.
@Stateless
@Path("current")
public class ServiceFacade implements TestInterface {
...
}

With TestInterface GF3 wasn't able to deploy service.

2.I tried to package given example into ejb-jar module (instead of war module).
Again packaged as ejb-jar server didn't deploy such package.

Have you any ideas why?
Thank you, nice articles ....

Posted by Felix on October 27, 2010 at 04:56 PM CEST #

Hi ,

Thanks for the article !!

I have few queries regarding EJb to ResT.

I have created an EJB 3.0 application and converted it to ReST service. I'm able to invoke methods on this ReST service using the url some thing like this: http://localhost:9080/EJB2TOReSTWeb/rest/customers

Now I'm trying to invoke the methods on my EJB by getting the EJB object through JNDI lookup.

but when I do initialConetext.lookup("jndiName");

I'm getting NameNotFoundException on client side. I have checked for this jndi name on my server, but i dont see any ejb registered with that name.

My Question here is : If we convert an EJB (either 2.1 or 3.0) into ReST service, can we still do the lookup of that EJB the way we do it in normal way using initialContext.lookUp();

I'm using JBoss 4.2.3 server, i tried on WAS6.1 also.

Any help would be really appreciated.

Thanks,

Rajesh V

Posted by Rajesh V on March 07, 2012 at 10:30 AM CET #

Felix, its been a couple years since your post but I wound up needing to access an EJB that was deployed in an EAR file via my REST servlet and did it using JNDI... use the JBOSS jmx-console to find the exact JNDI name for my EJB and then use something like:

try {
Context initialContext = new InitialContext();
if (initialContext == null) {
log.error("JNDI problem. Cannot get InitialContext.");
}
personsManagerJndi = (PersonsManagerInterface) initialContext.lookup("CDB080409/PersonsManager/local");
if (personsManagerJndi != null) {
log.info("RestBean.initializeLists: personsManagerJNDI not null");
} else {
log.error("Failed to lookup personsManagerJNDI");
}
} catch (NamingException ex) {
log.error("Cannot get connection: " + ex);
}

from withen the pojo bean that the REST servlet finds via the @Path annotation.

Posted by Jim on September 21, 2012 at 02:53 AM CEST #

This doesnt work in jboss 6.x, EJB injection returns null in every call. After looking for a solution for @EJB injection with rest (resteasy or jersey) for two days, i'm starting to give up on finding a solution.

Posted by Joe on March 13, 2013 at 01:04 PM CET #

Hi,

Thanks

Is the @EJB annotation inside the facade class correct?

There is an @Inject annotation in the repository source example.

Regards,
Ehsun

Posted by Ehsun on April 16, 2013 at 01:10 PM CEST #

Hello Adam,

A question on JAX-RS and how to return an aggregated object ( an object with a list ) .

I am followed this example , a very good example:
http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/RESTfulWebServices/RESTfulWebservices.htm#s6

The Example has one Player and one Team, I added a third table :
CREATE TABLE PHONE(
ID INTEGER NOT NULL,
TEAMNAME VARCHAR(15),
PLAYER_ID INTEGER,
FOREIGN KEY (PLAYER_ID) REFERENCES PLAYER,
PRIMARY KEY (ID)
);

So now , one player has one or many Phones.
But when calling the restful services, I get everything from all the getters except the list !?

I get the following :
<player>
<firstname>Jordan</firstname>
<id>1</id>
<jerseynumber>30</jerseynumber>
<lastname>Michael</lastname>
<lastspokenwords>I will be back</lastspokenwords>
</player>

But where are my phonenumbers ?

regards, Ingo

Posted by inki on November 25, 2013 at 02:21 PM CET #

Hello Adam,

what is the difference between a rest interface with only @path annotation and the other one with @stateless ejb annotation besides the services offered by ejb container ?

Posted by Sam on July 11, 2014 at 08:47 PM CEST #

I have put up an example for this at https://github.com/alexcpn/rest_in_sessionbean
Tested with JBOSS AS 7.1.1. Note that a war file is needed in the ear, with a web.xml . This is using JBOSS inbuilt RESTEasy.

Posted by Alex Punnen on August 08, 2014 at 06:48 AM CEST #

Can you please provide me the full project?

Posted by naren on September 23, 2014 at 01:02 PM CEST #

What you describe in this article works with TomEE?

Posted by Leonardo on January 26, 2015 at 01:10 PM CET #

What you describe here works with TomEE?

Thanks

Posted by Leonardo on January 26, 2015 at 01:11 PM CET #

I realize this post is pretty old by now, but any idea why I can't get this simple example to work with a fresh install of WebLogic 12.1.3? I get a NullPointerException on this line:

return service.getCurrentDate().toString();

and upon inspection it turns out that the service-EJB is indeed NULL.
It works fine in Glassfish 3.1 (as expected).

Posted by ldwl on June 01, 2015 at 01:41 PM CEST #

Hi Adam,
JAX-RS resources (class annotated with @Path) have a per-request default lifecycle.

Now EJBs have their own lifecycle too,I mean when have a reference to an EJB, this reference actually is the reference of a proxy object that manages a pool of EJBs.

When we use EJBs to implement JAX-rs resources how do these lifecycle models coexist ?

Posted by Ralf on November 10, 2016 at 03:51 PM CET #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License