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]