This is the second, and last part of the Using Dependency Injection in Struts2 for stateless EJBs series of posts. In this post I will present a utility class that can be used to make the creation of Guice bindings for EJB3s easier.
Introducing EjbBinder
Our goal is to make an easier API, specifically for creating bindings of EJB3s, and make the specification of the JNDI name optional, when possible. The below code is a new version of the EjbModule
class that uses a new class, called EjbBinder
, that we are going to present in this post.
public class EjbModule implements Module { public void configure(Binder binder) { // Bind Context to the default InitialContext. binder.bind(Context.class).to(InitialContext.class); EjbBinder ejbs = new EjbBinder(binder, new GlassfishEjbJndiNameStrategy()); ejbs.bindRemote(CurrencyManagerRemote.class); ejbs.bind(DatesManagerRemote.class, "com.tzavellas.dates.ejb.DatesManagerBean"); } }
EjbBinder
contains two methods named bind
and bindRemote
. The bind
method receives as arguments the expected class and JNDI name and simply uses Binder
and JndiItegration
to create a binding. The bindRemote
method takes as an argument the remote interface of a sesion EJB3 and creates a binding using a JNDI name retrieved from the EjbJndiNameStrategy
, that is specified in the EjbBinder
constructor (BTW the CurrencyManagerRemote
EJB interface in the above code does not relate with the application that we developed in the previous post and it is here to illustrate the bindRemote
method).
The definition of the EjbJndiNameStrategy
interface:
public interface EjbJndiNameStrategy { String interfaceToJndiName(Class<?> beanInterface); }
The implementation of EjbBinder
:
import com.google.inject.Binder; import com.google.inject.binder.ScopedBindingBuilder; import static com.google.inject.jndi.JndiIntegration.fromJndi; public class EjbBinder { private Binder binder; private EjbJndiNameStrategy jndiNameStrategy; public EjbBinder(Binder binder, EjbJndiNameStrategy nameStrategy) { this.binder = binder; this.jndiNameStrategy = nameStrategy; } public <T> ScopedBindingBuilder bindRemote(Class<T> beanInterface) { return bind(beanInterface, jndiNameStrategy.interfaceToJndiName(beanInterface)); } public <T> ScopedBindingBuilder bind(Class<T> beanInterface, String jndiName) { return binder.bind(beanInterface) .toProvider(fromJndi(beanInterface, jndiName)); } }
Application Server Specific Naming Strategies
When you create a new EJB and you do not specify a JNDI name, the application server assigns a default name for you. So, if you have an implementation of EjbJndiNameStrategy
that uses the naming rules of your application server you could avoid the need to specify a JNDI name when creating the EJB and when creating the binding of the EJB to Guice.
Below we have two implementations of the EjbJndiNameStrategy
that can infer the JNDI name of an EJB’s remote client interface using the remote interface’s class for the Glassfish and JBoss application servers.
For the Glassfish application server the default global JNDI name of an EJB with a remote interface is the fully qualified name of the remote interface.
public class GlassfishEjbJndiNameStrategy implements EjbJndiNameStrategy { public String interfaceToJndiName(Class> beanInterface) { return beanInterface.getName(); } }
For the JBoss application server the default JNDI name for the remote interface of an EJB is earName/beanName/remote.
//WARNING: Not tested! public class JbossEjbJndiNameStrategy implements EjbJndiNameStrategy { private String earName = ""; public JbossEjbJndiNameStrategy() { } public JbossEjbJndiNameStrategy(String earName) { if (earName != null && "".equals(earName.trim())) this.earName = earName + "/"; } public String interfaceToJndiName(Class<?> beanInterface) { return earName + interfaceToBeanName(beanInterface) + "/remote"; } protected String interfaceToBeanName(Class<?> beanInterface) { String name = beanInterface.getSimpleName(); if (name.endsWith("Remote")) name = name.replace("Remote", ""); return name + "Bean"; } }
nice articles about using ejb3 in struts2. i did something very similar but without a dependency injection framework.
my solution does use a custom annotation and a struts2 interceptor.
you can find it here (its written in german, but the code is commented in english):
http://blog.pierosartini.de/archives/3-In-Struts2-auf-EJB3-Session-Bean-zugreifen.html