Gianluigi Davassi 's Blog UK

Some J2EE Experiments… Software Development and Web Solution

Friday, 13 November 2009

EJB3 plus Guice... how Exotic! Part 3


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:

module

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 type object that take from the jndi context a specified object that we can bind to a class interface in that way:

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 :-)


Wednesday, 11 November 2009

EJB3 plus Guice... how Exotic! Part 2



Here we are to try Guice's features. My aim is to be able to inject EJB3 Session Bean into not-managed component like POJO. The "@EJB3" j2ee standard annotation for dependency iniection don't allow this behaviour: you are able only to iniect Ebj3Bean into managed component, like EJB3 or Servlet. So we have to work around this limitation. Let's begin.

What's Guice? Guice is a framework that allow us to configure, instantiate and inject GRAPH of object, in a similar way of Spring, but with important differences. One of these differences is that Guice is code-configured, uses a English-like syntax and it doesn't depend by xml configuration file. Let's begin with an example.

I start to create an abstract MyClassA and a MyClassB that extends MyClassA in that way:

package org.exquisitus;

public abstract class MyClassA {

 abstract void yellPlease(String str);
}

package org.exquisitus;

public class MyClassB extends MyClassA {

 @Override
 void yellPlease(String str) {
  System.out.format("You yell: - %s -\n",str);  
 }
}

Now let's write a NiceClass that uses an object instance of MyClassB from a MyClassA type reference:

package org.exquisitus;

import com.google.inject.Inject;

public class NiceClass {

 @Inject private MyClassA a;
 
 public void callMethod() {
  a.yellPlease("OMG!");
 }
}

That code is very simple. The method "callMethod()" will invoke "yellPlease()" method of the unknow-runtime-object referred by 'a'.
No one defined the 'a' reference, there aren't setters, there isn't a class costructor as well. There's a interesting annotation called "@Iniect". This is a Guice Annotation.

package org.exquisitus;

import com.google.inject.AbstractModule;

public class GuiceModule extends AbstractModule {

 @Override
 protected void configure() {
  
  bind(MyClassA.class).to(MyClassB.class); 
 }

}

GuiceModule is a class that extends AbstractModule, and override the the configure() method. This class is the Guice-way to configure the dependency of our objects graph.
Through the bind(classname.class).to(classname.class) expression, i tell to Guice that every time it meet the @Inject annotation on a MyClass reference, it has to popolate with a new instance of MyClassB.
There's a way to specify the object scope of the object to instance, e.g. there's the way to instance a Singleton object.
We have only to try the code. Let's create a Main:

package org.exquisitus;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class TryGuicePlease {

 public static void main(String[] args) {
  
  System.out.format("Let's Try [%s] please ---\n\n",Guice.class.getName());
  
  Injector injector = Guice.createInjector(new GuiceModule());

  NiceClass nice = injector.getInstance(NiceClass.class);
  
  nice.callMethod();
 }

}

Et voila'! We have met the injector. There's a way to inject the injector, but it's very exotic :-). What matter is that when we request a NiceClass instance, Guice will create it with dependency configured yet. So the private field will not have the default value but a new instance of MyClassB, as requested. This is the result:

Let's Try [com.google.inject.Guice] please ---

You yell: - OMG! -

Fantastic, now the things are really interesting. Let's assume that we have the need to instantiate different object for the same type of reference. Thus, let's add a MyClassC that extends and implement the abstract MyClassA.

package org.exquisitus;

public class MyClassC extends MyClassA{

 @Override
 void yellPlease(String str) {
  System.out.format("You reverse yell: - %s -\n",new StringBuilder(str).reverse());
 }

}

that shout a reverse yell :-) How i specify to Guice that when the framework meet a MyClass reference i want to inject a MyClassC object instead of a MyClassB object? I have to use a selector. There are different way to create a selector, and a nice way is to use an annotation!. Let's write 2 annotations for the our classes: @Yell e @ReverseYell

package org.exquisitus;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;

import com.google.inject.BindingAnnotation;

@BindingAnnotation @Target(FIELD) @Retention(RetentionPolicy.RUNTIME)

public @interface Yell {

}

let's write an annotation like @Yell but called @ReversedYell (note the @Target(FIELD) i dont annote methods but fields).

and reconfigure the code using the annotatedWith() method to map the just created annotation like selectors for MyClassB and MyClassC:

package org.exquisitus;

import com.google.inject.AbstractModule;

public class GuiceModule extends AbstractModule {

 @Override
 protected void configure() {
  
  bind(MyClassA.class).annotatedWith(Yell.class).to(MyClassB.class);
  
  bind(MyClassA.class).annotatedWith(ReverseYell.class).to(MyClassC.class);  
 }

}

Let's instance the 2 objects in the same class NiceClass pointed by 2 reference of the same type MyClassA and invoke the 2 methods in callMethod().

package org.exquisitus;

import com.google.inject.Inject;

public class NiceClass {

 @Inject @Yell private MyClassA a;
 
 @Inject @ReverseYell private MyClassA a2;
 
 public void callMethod() {
  a.yellPlease("OMG!");
  a2.yellPlease("OMG!");
 }
}

this is the result!

Let's Try [com.google.inject.Guice] please ---

You yell: - OMG! -
You reverse yell: - !GMO -

This is very interesting but not very useful. Why? We have to inject EJB3 that uses 2 different type of interfaces (Local and Remote) and usually a common interface and the implementation. Add an annotation for every EJB3 increase code size! Theres' the possibility to use a bundled Guice annotation called @Named, in that way:

bind(MyClassA.class).annotatedWith(Names.named("Reverse")).to(MyClassC.class);

and to use the annotation with @Inject we have to write:

@Inject @Named("Reverse") private MyClassA a2;

here we are. We are ready to go deeper in Guice and use it with JBoss AS and let's discover how to use Guice with JNDI :-) To the next Post 3.