Sunday, December 20, 2009

Was I defeating bean pooling in OpenEJB?

As I previously reported I had to use JNDI to obtain a reference to my stateless session bean from my Jersey Rest service.

In so doing I created a helper class that would, among other things, cache the JNDI and EJB references I needed.

That got me to wondering - since I was using the same EJB reference over and over was I somehow defeating the stateless session bean pooling that OpenEJB was surely providing me?

The only documentation I could find on this hinted that pooling worked via the bean method invocations and not the bean reference itself. But, I wanted to see it with my own eyes. I did notice that my JNDI lookup was returning a proxy object and not my bean implementaion, so this provided me some hope that I was not defeating pooling.

My first test was to invoke my EJB 10 times via the same reference and, from inside my EJB implementation identify the bean instance that was invoked. Well, the 10 invocations went to the same instance - no pooling so far.

But, my test was not very realistic so I modified it to invoke my EJB 10 times via the same reference but from 10 separate threads. This time the 10 invocations were handled by 10 different instances of my bean implementation. Whew - proof that I had not defeated pooling by caching and reusing the bean reference I was retrieving from JNDI.

Out of curiosity I increased my invocations to 100 and this time only 9 unique instances of my stateless session bean were used to handle these 100 requests.

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.