Saturday, 20 June 2009

Autowiring EJB 3.0 in Tomcat from remote JBoss

To be honest I've never fully understood EJB 2.x or written an application using that specification. Well, I've written some EJBs, but it was just following an example of different EJB in the same project. Even though we used Spring at that time nothing seemed simple and straightforward. Every time I wanted to use an EJB I had to modify several XML files to be able to inject EJB into some bean. Not funny at all.

Now that I know Spring and it's @Autowired annotation everything seems far more usable. Even Java EE 5 has it's own annotations like @EJB.

So, here's my problem. My application is going to be used simultaneously by many users, up to several hundreds at the same time. So I need to have scallable architecture. I chose EJB for logic tier and JSF for web tier. Of course in each of those tiers I can use Spring for dependency injection via @Autowired. But then, what about EJB? Every place I've looked people were either deployed single WAR on JBoss or Glassfish, that contained EJB and all web stuff, or used sophisticated XML configurations that did all the magic with injecting EJBs. I wanted something more. I didn't want any defining EJBs in XML, one entry per one EJB, and then, on web side, one entry per one injection.

Well, Spring comes in handy in such situations. So, in logic tier I have annotated session bean:

@Stateless(mappedName = "sth/SessionService")
public class SessionServiceEJB implements SessionService {

All that it does is saying that this is a stateless session bean (SessionService is it's remote interface) and will be mapped in JNI under the name "sth/SessionService".

Then in web beans I have:

@EJB(mappedName = "sth/SessionService")
private SessionService sessionService;

Which means that sessionService should be injected with EJB mapped under the name "sth/SessionService".

As web tier is put on Tomcat, which doesn't understand @EJB annotation, I used Spring to do the magic, it understands this annotation and injects EJBs properly. But where from get those EJBs? Well, we have some really interesting features in Spring like SimpleJndiBeanFactory. So my application requires applicationContext.xml file with a bean defined something like that:

<bean id="simpleJndiBeanFactory" class="org.springframework.jndi.support.SimpleJndiBeanFactory">
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming.client</prop>
<prop key="java.naming.provider.url">jnp://localhost:1099</prop>
</props>
</property>
</bean>

So what does it do. First of all this creates a new Spring I define bean factory which will be the source of our injected EJBs. Then, in "jndiEnvironment" I define a source where this bean factory should look for EJBs.

Primary objective completed, I can insert via Spring any EJB deployed on application server without defining this EJB anywhere. Unfortunately secondary objectives are not there (yet). First of all, I would like to skip this "mappedName" parameter, at least in web tier. Second, as you can see above configuration requires JBoss, it's not universal. If you want to use Glassfish, Apache Geronimo or some other application server you'll need to configure JNDI source by yourself. Third, there's "localhost" in the address, which would certainly be wrong in production environment. But I believe that host can be configured in a different way, although I didn't look for any. Do you have any solutions to that?

No comments:

Post a Comment