Hessian and TomEE/OpenEJB: make remote services insanely fast!


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.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s