Here we are at the third post on EJB3 and Guice integration. Let's start to discover how to integrate JNDI with Guice. We'll see how to inject some EJB3 Bean through Dependency-Iniection-Pattern into non-managed components (POJO) using Guice on JBoss AS 5. The aim is to recreate an improved version of the "@EJB3" standard annotation, cause the original version allow only to inject EjbBean into managed component (EJB3-Servlet). ServiceLocator and BusinessDelegator pattern are too MUCH OLD.
We have to follow three steps:
- Create a Stateless Session Bean EJB3 to deploy on a JBoss Application Server
- Develop a simple java application that will remotely invoke the EjbBean
- Use Guice to inject (through DI) the EjbBean into the application
Let's start to create the Stateless Session Bean. We'll use Eclipse to develop it: Select from menu: File -> New -> EJB Project and let's create a new project in that way:

Insert in this project a stateless session bean with a remote interface plus implementation. This is the remote interface:
package org.bizlogic;
import javax.ejb.Remote;
@Remote
public interface EJB3TestRemote {
public String statelessMethod(String s);
}
and this is an implementation:
package org.bizlogic;
import javax.annotation.PostConstruct;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import org.apache.log4j.Logger;
/**
* Session Bean implementation class EJB3Test
*/
@Stateless
@Remote(EJB3TestRemote.class)
public class EJB3Test implements EJB3TestRemote {
private static Logger log = Logger.getLogger(EJB3Test.class.getName());
/**
* Default constructor.
*/
public EJB3Test() {}
@PostConstruct
public void useless() {
log.info(String.format("postconstuct"));
}
public String statelessMethod(String s) {
log.info(String.format("Received: " + s));
return String.format("What a nice String! - %s", new StringBuilder(s).reverse().reverse());
}
}
Done! It was very simple. Now we can deploy that project into JBoss using twiddle utility (is a utility into jboss distribution) or we can export it with Eclipse: let's click on the project, select "Export" from pop-up menu and select "EJB JAR file" to export it correctly. Give to the module a name and select the deploy folder of our app server located in $JBOSS_HOME/server/default/deploy (if we are using the default configuration). At the end of the operation JBoss will say to us:
16:11:35,118 INFO [SessionSpecContainer] Starting jboss.j2ee:jar=Test-EJB3-Guice.jar,name=EJB3Test,service=EJB3 16:11:35,118 INFO [EJBContainer] STARTED EJB: org.bizlogic.EJB3Test ejbName: EJB3Test 16:11:35,126 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI: EJB3Test/remote - EJB3.x Default Remote Business Interface EJB3Test/remote-org.bizlogic.EJB3TestRemote - EJB3.x Remote Business Interface
We have an active instance of jboss with our EJB3Test bean and remote interface deployed.
We have arrived at the second step and we can start to play with Guice. Let's create a simple java project that will use the natural remote side of this EJB3 Bean and let's start to inject the Jndi Context (java.naming.InitialContext). We have to select on Eclipse "New" -> "Java Project", go to the project properties "Build Path" and let's add the libraries founded in Guice2 distribution package downloaded by googlecode (here: http://google-guice.googlecode.com/files/guice-2.0.zip). The libraries are: aopalliance.jar, guice-2.0.jar, guice-jndi.jar (and if we want log4j-1.2.15.jar too).
We have not inserted any kind of code yet but let's configure the jndi context: at src level we have to insert a properties file called jndi.properties with that content:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=localhost
The default way to call that Bean is to initialize a new instance of the java.naming.InitialContext and invoke a lookup on the object like the following code:
public class NiceClass {
public void tryJndi() throws NamingException {
InitialContext cxt = new InitialContext();
EJB3TestRemote test = (EJB3TestRemote) cxt.lookup("EJB3Test/remote");
System.out.println(test.statelessMethod(" JBOSS Hello "));
}
}
We can start to configure Guice and inject the JNDI context. Write a class called "GuiceModule" that extends the AbstractModule class and in that class we have to specify that every time Guice meet an @Inject annotation with @Named("JNDI") selector on a type java.naming.Context reference, it have to inject a new InitialContext type instance, like we have just seen in the previous post.
public class GuiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Context.class).annotatedWith(Names.named("JNDI")).to(InitialContext.class);
}
}
Well, now we are able to refactor the NiceClass class in that way:
public class NiceClass {
@Inject @Named("JNDI")
private Context cxt;
public void tryJndi() throws NamingException {
EJB3TestRemote test = (EJB3TestRemote) cxt.lookup("EJB3Test/remote");
System.out.println(test.statelessMethod("JBOSS HELLO"));
}
}
In that way it works great. There's a little problem. We have just said to Guice to inject a new instance of InitialContext, but it isn't very useful. The real advantage comes when we let Guice to deal internally with jndi context and injects the EJB3 Bean instead! Guice can do the dirty work through a particular object called JndiIntegration.
If we go to read the code of this open source class, we'll find that it joins Jndi with Guice using a reference @Inject Context context;. The problem is that when the class is instantiated, it request a binding to java.naming.Context. So we have to configure it. We have to say to Guice HOW to inject the Jndi context using the jndi properties. We have to remove from GuiceModule configuration the method "annotatedWith(Names.named("JNDI"))" and refactor in that way:
bind(Context.class).to(InitialContext.class).in(Singleton.class);
and from the source code we discover how the static function "fromJndi" works: it creates a Provider
bind(DataSource.class).toProvider(fromJndi(DataSource.class, "java:..."));
Perfect! Now we are able to bind the remote interface of our Ejb3 in the GuiceModule class, specifing the object name to invoke. Let's add
import static com.google.inject.jndi.JndiIntegration.fromJndi;
and finally we can configure our EJB3 Bean:
bind(EJB3TestRemote.class) .annotatedWith(Names.named("EJB3TestRemote")) .toProvider(fromJndi(EJB3TestRemote.class,"EJB3Test/remote"));
Note: The "/remote" suffix is a JBoss way to invoke the EJB3 under JBoss. On OpenEJB or WebSphere there are some differences.
We are able to do a DI of the bean:
public class NiceClass {
@Inject @Named("EJB3TestRemote")
private EJB3TestRemote test;
public void tryJndi() throws NamingException {
System.out.println( test.statelessMethod("JBOSS HELLO") );
}
}
IHMO the @Named selector annotation is not very useful. We dont need it, we have only a remote interface. It will be more useful if we had a local interface too, cause in that way whe can choose wich kind of interface to use. Let's running all ... et voilĂ ! how wonderful!
Let's Try [com.google.inject.Guice] please --- What a nice String! - JBOSS HELLO
Now the things are more interesting. Now we are able to inject EJB3 into POJO, in that way we can use EJb Bean into object non managed and we can extends our RPC ajax call using different patter from GWT standards (like command pattern, a very nice implementation is Gwt-Dispatcher). I have a doubt in the case we need to use more than a jndi java.naming.Context in the same application (a context for local object and a context for remote ojbject).
The only solution to that is to extend the JndiIntegration class and add 2 static methods fromJndiLocal and fromJndiRemote that works on 2 different instance of InitialContext (in that case is useful to use @Named annotation). This is a very particular case.
For any comments please contact me to davassi [at] yahoo [dot] it . To the next Post on JMX :-)