adam bien's blog

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]