Sunday, December 20, 2009

Tomcat, OpenEJB and Jersey, oh my

I was recently investigating putting EJBs behind Restful web services.

I did get it working without too much trouble using Jersey and JBoss AS 5.1, but I had to deploy my web app in exploded directory form and not as a war. No matter what I tried I could not get Jersey to find the rest service classes when I deployed my app as a war. This was contrary to my experiences with JBoss 4 and is probably due to the new virtual file system architecture in JBoss 5.

This prompted me to take a look around and see what else is out there. I stumbled upon OpenEJB and thought I would give that a shot inside Tomcat 6.

It was pretty simple getting Tomcat going with Jersey and within a few minutes I had my web service running inside standalone tomcat (without the EJB usage, of course).

However, when I dropped the OpenEJB war file into Tomcat things fell apart and my app would no longer deploy due to an apparent class loader issue which seemed to be introduced by OpenEJB. I tried a lot of different things but couldn't get past the class loader problem. I even went as far as to download and debug into the OpenEJB source code but I quickly found myself in compiled 3rd party code.

Here is the error I kept getting: Could not fully load class: com.sun.jersey.spi.container.servlet.ServletContainer due to: javax/ws/rs/core/Application in classLoader: org.apache.openejb.core.TempClassLoader

I finally decided to simply place the Jersey jars (asm.jar, jersey-core.jar, jersey-server.jar, and jsr311-api.jar) into the Tomcat lib folder and that did the trick. I also set the Jersey dependency to 'provided' in the maven pom for my webapp.
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.1.4.1</version>
        <scope>provided</scope>
    </dependency>
Also, I was hoping the @EJB annotation in my rest service class would inject my stateless bean reference, but it did not - I had to use JNDI. By default, OpenEJB uses the following scheme (you can configure) for naming your beans in JNDI: implementation class name + either 'Local' or 'Remote'.

For example, say you have an EJB class named AccountBeanImpl and it implements interfaces AccountBeanLocal and AccountBeanRemote. The corresponding JNDI names for the account bean would be AccountBeanImplLocal and AccountBeanImplRemote.

No comments: