Adam Bien's Weblog

Monday Jun 21, 2010

EJB 3.1 + Hessian = (Almost) Perfect Binary Remoting

EJB 3.1 + REST are perfect combo for HTTP and resource style programming. REST is not very well suited for the exposure of already existing interfaces. The RPC-misuse of REST will result in hard to understand and so to maintain code.
With hessian it is very easy to expose existing Java-interfaces with almost no overhead. Hessian is also extremely (better than IIOP and far better than SOAP) fast and scalable. The size of the whole hessian library (hessian-4.0.7.jar) is smaller than 400 kB and so compatible with the "Kilobyte Deployment" style of Java EE 6 programming and deployment.

To expose an existing EJB 3.1 with hessian:


@Stateless
public class CurrentTime {
    public long nanos(){
        return System.nanoTime();
    }
}

You will need an interface:

public interface TimeService {
    public long nanos();
}


...and hessian-specific implementation of the endpoint:


public class HessianTimeEndpoint extends HessianServlet implements TimeService{
	
    @EJB
    CurrentTime currentTime;
	
    @Override
    public long nanos() {
        return currentTime.nanos();
    }
}


The hessian enpoint is an servlet - so the dependency injection works here without any XML configuration. You can just inject your no-interface EJB 3.1 view bean into the servlet.
The client side is also very lean. You only need a two lines of code to get a reference tot he proxy:

public class HessianTimeEndpointTest {
    private TimeService timeService;
	@Before
    public void initProxy() throws MalformedURLException {
        String url = "http://localhost:8080/EJB31AndHessian/TimeService";
        HessianProxyFactory factory = new HessianProxyFactory();
        this.timeService = (TimeService) factory.create(TimeService.class,url);
        assertNotNull(timeService);
    }
    @Test
    public void nanos() {
        long nanos = this.timeService.nanos();
        assertTrue(nanos>0);
        System.out.println("Nanos: " + nanos);
    }
}

HessianServlet inherits from GenericServlet and not from HttpServlet. This is a shame, because you will have to use a web.xml deployment descriptor, instead of a single annotation @WebServlet:

<web-app >
    <servlet>
        <servlet-name>TimeService</servlet-name>
        <servlet-class>com.abien.patterns.business.sf.hessian.HessianTimeEndpoint</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TimeService</servlet-name>
        <url-pattern>/TimeService</url-pattern>
    </servlet-mapping>
</web-app>

You will find the executable project (tested with Netbeans 6.9 and Glassfish v3.0.1) in: http://kenai.com/projects/javaee-patterns/ [project name: EJB3AndHessian].
The whole WAR (EJB 3, Servlet, web.xml and the hessian "framework") is 393 kB. 385 kB hessian, and 7 kB EJB + Servlet :-)


The initial deployment of the WAR with EJBs took:

INFO: Portable JNDI names for EJB CurrentTime : [java:global/EJB31AndHessian/CurrentTime!com.abien.patterns.business.sf.CurrentTime, java:global/EJB31AndHessian/CurrentTime]
INFO: Loading application EJB31AndHessian at /EJB31AndHessian
INFO: EJB31AndHessian was successfully deployed in 807 milliseconds.


Don't worry: the subsequent deployments are substantially faster :-):

INFO: Portable JNDI names for EJB CurrentTime : [java:global/EJB31AndHessian/CurrentTime!com.abien.patterns.business.sf.CurrentTime, java:global/EJB31AndHessian/CurrentTime]
INFO: Loading application EJB31AndHessian at /EJB31AndHessian
INFO: EJB31AndHessian was successfully deployed in 568 milliseconds.

[See also Service Facade pattern, page 69"Real World Java EE Patterns - Rethinking Best Practices]


NEW: Java EE 7 Testing and Quality Workshop

A book about rethinking Java EE Patterns

Comments:

One disadvantage of that solution:

It's not Java EE standard!

Posted by Simon Martinelli on June 21, 2010 at 05:32 PM CEST #

Yes - but the deviation from the standard is only 400kB and very portable.

It is also tunneled via 8080, so works better, than the standard IIOP way.

Thanks for your comment!,

adam

Posted by adam-bien.com on June 21, 2010 at 05:36 PM CEST #

Another disadvantage:

You have useless code. The delegate:
return currentTime.nanos();

JBoss has another solution for EJBs over HTTP:
http://www.jboss.org/ejb3/docs/tutorial/http_https/http_https.html

It's not standard as well, but no useless code.

Posted by Simon Martinelli on June 21, 2010 at 06:48 PM CEST #

@Simon,

its just a useless delegate, because its a "Hello World" sample. In real world I use the first layer to DTO -> PDO conversion if needed.

Again: hessian is not standard but very portable. I tested it on several servers - it even plays well with Spring.
EJBs over HTTP are just JBoss and so absolutely not portable...

Btw. EJBs over HTTP is a really old
JBoss 3 feature (invoker). I used it in ~2002 it worked perfectly as well!

thanks!,

adam

Posted by adam-bien.com on June 21, 2010 at 07:39 PM CEST #

I made an example project located on gihub which combines Maven, JEE 6, NetBeans RCP, Flex and Hessian. To avoid writing an extra wrapper servlet for every session bean I wrote a servlet that dynamically invokes the required bean/method.

http://github.com/mikael2/Sample-JEE6-Maven-project/blob/master/mjee-web/src/main/java/com/exie/web/DynamicHessianServlet.java

It is rather simple and mostly a cut and paste from the original Hessian servlet. To support stateful session beans on the client you also need a class to track the Hessian cookies.

http://github.com/mikael2/Sample-JEE6-Maven-project/blob/master/NetBeansRCP/RemoteHandler/src/main/java/com/exie/hessian/HessianCookieProxyFactory.java

The client code looks like:
HessianCookieProxyFactory factory = new HessianCookieProxyFactory("http://localhost:8080/mjee-web/services/hessian/");
MyService service = factory.create(MyService.class);

Posted by Mikael Tollefsen on June 22, 2010 at 03:20 PM CEST #

Instead of extending HessianServlet, instantiate the servlet as is and set the delegate with servlet.setObject(currentTime), that's ever simpler.

Posted by ebourg on June 22, 2010 at 07:03 PM CEST #

wow, this is rather cool. It's indeed unfortunate that you can't use the WebServlet annotation, but other than that it looks very neat.

I love java ee and I love ejb, but one small disadvantage with remote ejb is that many application servers have an impossible amount of required client libs.

With JBoss AS I have to copy a dozen different jars files to my Java SE client weighing in at many megabytes. Why can't there be a simple single ejb-remote-jboss-client.jar orso?

Posted by Dexter Hughes on June 22, 2010 at 10:10 PM CEST #

393 kB + the whole boatload of the JEE app server necessary to support those totally unnecessary @EJB/@Stateless. Not my idea of lightweight...

Posted by Dimitris on June 22, 2010 at 11:12 PM CEST #

@Dimitris,

@EJB / @Stateless are probably unnecessary, but something with similar functionality is necessary.

Btw. the EJB container in Glassfish is > 1 MB. What do you mean exactly by boatload? (an OSGi bundle),

thanks for you semi-constructive comment! :-),

adam

Posted by adam-bien.com on June 23, 2010 at 02:41 AM CEST #

@Dexler,

I did some experiments in the past with EJB 3 and IIOP. Actually you can access EJBs straight from JDK - without any client libs.

thanks!

adam

Posted by adam-bien.com on June 23, 2010 at 02:43 AM CEST #

@Ebourg,

"...Instead of extending HessianServlet, instantiate the servlet as is and set the delegate with servlet.setObject(currentTime), that's ever simpler..."

But @WebServlet would be still more elegant.

I already thought about the delegate...

thanks!

adam

Posted by adam-bien.com on June 23, 2010 at 02:44 AM CEST #

@Mikael,

thanks for the pointer! Nice stuff. Will take a look at that!,

adam

Posted by adam-bien.com on June 23, 2010 at 02:45 AM CEST #

And even more fun with Hessian, remote invocation over your favorite AMQP middleware:

http://github.com/ebourg/qpid-hessian

Posted by ebourg on June 23, 2010 at 03:03 AM CEST #

Hessian is not *that* fast. See
http://code.google.com/p/thrift-protobuf-compare/wiki/BenchmarkingV2

Posted by Markus Kohler on June 23, 2010 at 02:05 PM CEST #

Excellent job Mikael Tollefsen!!

Posted by Gardella Juan on May 18, 2011 at 01:05 AM CEST #

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