Hessian is an old but very interesting binary protocol known for a very good compromise between compression time and size. That’s probably one of the faster usable for remote webservices.
The question in a JavaEE server is how to use it as transparently as possible? Here is the answer for OpenEJB/TomEE.
Boring stuff: maven dependency
Here is the maven dependency to get openejb hessian features.
<dependency> <groupId>org.apache.openejb</groupId> <artifactId>openejb-hessian</artifactId> <version>4.6.0-SNAPSHOT</version> <scope>provided</scope> </dependency>
Don’t forget to add hessian dependency:
<dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.7</version> <scope>provided</scope> <!-- can be compile depending the way you deploy it --> </dependency>
Note: hessian is known to have some limitations (enum handling for instance). To avoid it you can use the fork used in resthub: org.resthub:hessian:4.0.8
If you use TomEE you have to add openejb-hessian jar to TomEE libs but hessian implementation can be either in the container (surely better) or in the webapp.
What do i get with it?
Remote EJBs
The more trivial case will be the ability to deploy remote EJBs as Hessian services. Basically if you have an EJB implementing:
@Remote public interface Calculator { int sum(int a, int b); }
You can use a hessian client to invoke this EJB. The hessian service will be deployed under /hessian subcontext of the webapp and the service name will the implementation class simple name. Here is a client sample:
final HessianProxyFactory clientFactory = new HessianProxyFactory(); final Calculator client = Calculator.class.cast(clientFactory.create(Calculator.class, "http://localhost:8080/hessian/CalculatorBean")); int total = client.sum(1, 2);
CDI beans as hessian services
openejb-hessian module contains the annotation org.apache.openejb.cdi.api.Hessian. It allows you to define a CDI bean as an hessian service when added on an interface of a CDI bean.
@Hessian(path = "service") // will be deployed on /hessian/service public interface CdiService { Out call(In in); } @ApplicationScoped public class MyCdiHessianService implements CdiService { @Inject private CdiBean bean; @Override public Out call(final In in) { assertNotNull(bean); return new Out(in.value); } }
If you don’t want to use @Hessian you can set as a system property:
openejb.hessian.<qualified name of MyCdiHessianService>_<hessian interface>.path = <path>
More portable client?
If using hessian API for the client is an issue (probably because you are using the EJB Remote feature and you expect an EJB client API with configurable properties) there is a simple solution: use hessian initial context. Just use the following code:
final Properties p = new Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, HessianInitialContextFactory.class.getName()) p.put(Context.PROVIDER_URL, "http://127.0.0.1:4204/HessianInitialContextTest/hessian/") final Context context = new InitialContext(p); final String ejbSimpleName = "CalculatorBean"; final Calculator client = Calculator.class.cast(context.lookup(ejbSimpleName));
There are a bunch of config for this client:
-
openejb.hessian.client.api: interface class of the client
-
openejb.hessian.client.force-serializable: should hessian handle serialization of input/output even when not implementing java.io.Serializable
-
openejb.hessian.client.chunked: does hessian client use chunking
-
openejb.hessian.client.debug: debug hessian client
-
openejb.hessian.client.read-timeout and openejb.hessian.client.connect-timeout: timeout for remote communications
Note: user/password are supported through Context.SECURITY_PRINCIPAL and Context.SECURITY_CREDENTIALS properties
Last note
Hessian supports BASIC authentication so you can use it with TomEE. It works very well with JAAS authentication.
And the best thing is hessian deployment works with the flag i spoke about in my last post (EJBD/JAXWS): if you have @WebService EJBs you can deploy them as hessian webservices forcing OpenEJB/TomEE to consider them as @Remote EJBs.