Tuesday, July 15, 2008

Grails and EJB 3 Session Beans

A while back I was working on a Grails project that needed to integrate with an EJB2 application via session beans. So, when my current project had a similar need I thought 'piece of cake!'. As it happens it was a piece of cake that wasn't that easy to get at.

The problem came about because we were working with EJB3 this time. I had heard that it should work the same but it doesn't. I eventually found that it is still extremely easy to do (this is Grails we're talking about after all) it's just different.

For starters the Spring class that we used to connect to an EJB2 session bean, SimpleRemoteStatelessSessionProxyFactoryBean (I wonder if there is a TinyURL! for class names) was not working with EJB3. Several people on the forums said that it should, but our application did not believe them. It turns out that there is a Spring class that does work with EJB3 and it even has a shorter name! The JndiObjectFactoryBean is a general purpose Factory for looking up JNDI objects and making them available to other beans. The JndiObjectFactoryBean will even use the JndiTemplate that I had setup before, though I'll show it again so you don't have to hunt it down.

So now we should be in business. Except that it didn't work. When using the SimpleRemoteStatelessSessionProxyFactoryBean we could just use the Session Bean's simple interface name, which was also its JNDI name. That was not working with the JndiObjectFactoryBean. This critter wanted a fully qualified, certified and USDA approved JNDI name. The bummer here is that this is vendor specific. So the rest of this will work for BEAORACLE WebLogic but it might be completely different for your app server.

First we have to make sure that the EJB3 session bean has the mappedName attribute in the @Stateless annotation. (In our case ...mappedName="CoverageSession") That makes up the first part of the JNDI name. Then we add a # symbol and top it off with the fully qualified name of the Remote Interface. So we ended up with something like this for our JNDI name: CoverageSession#org.blah.app.ejb.session.ICoverageSessionRemote Once we gave it that mouthful it was happy.

Here I'll show a slightly modified version of our resources.groovy file:


beans = {
ejbJndi(org.springframework.jndi.JndiTemplate){
environment = [
"java.naming.factory.initial" : "weblogic.jndi.WLInitialContextFactory",
"java.naming.provider.url" : "t3://some.enterprise.server:7001"
"java.naming.security.principal" : "dave",
"java.naming.security.credentials" : "1234" ]}

coverageSession(org.springframework.jndi.JndiObjectFactoryBean){
jndiName = "CoverageSession#org.blah.app.ejb.session.ICoverageSessionRemote"
jndiTemplate = ref("ejbJndi")
}
}


Now we can inject the session bean into a Grails Service and we can call its methods to retrieve and save EJB3 entities from that portion of the application that was written before we began using Grails and it all just works and I'm happy!

I'm still hoping to be able to convert the entire application to Grails before we go production but in case we can't the ability to integrate Grails with all of our existing Java technologies is a big help.

3 comments:

Andres Almiray said...

Dave, I guess by now you know "the cake is a lie", see -> http://is.gd/V4G ;-)

Jack said...

Hi Dave,

nice tip, but getting the following exception while deploying my application on jetty

Error executing script RunApp: weblogic/xml/registry/XMLRegistryException
java.lang.NoClassDefFoundError: weblogic/xml/registry/XMLRegistryException


The weblogic.jar is in the grails-app/lib directory..

Any suggestion?

Thanks,
Jack

Ted said...

Question, and possibly a stupid one, but forgive me. Let's say you had a local EJB3 Session Bean, and you wanted to develop with grails. How would you go about configuring the system to use those local EJBs?