martedì 18 giugno 2013

EJB smart lookup

I want to post a nice solution i found for looking up the EJB, easy and simple.
It follows the KISS idea, Keep It Simple and Strong.
Part of this solution is a contribution of Massimiliano.
Let's start from this idea:
I want to provide to the user a library that is capable to lookup enterprise beans, without telling him anything about the class that implements the exposed interfaces.

I have many enterprise beans in my application, one of the is for example the account manager:


import javax.ejb.Remote;
import javax.ejb.Stateless;
...
...
@Stateless(name = "Account")
@Remote(IAccount.class)

public class AccountManager implements IAccount {
...
}

This class implements the interface IAccount.  It is and EJB stateless bean, and the name used to look up this stateless bean is Account. Telling the name of the bean is the first step. Doing so we know the name we have to use for the lookup.
Once deployed the EJB projects an output like this:

java:global/MyBankLogicEAR/MyBankLogic/Account!main.IAccount
java:app/MyBankLogic/Account!main.IAccount
java:module/Account!main.IAccount
java:jboss/exported/MyBankLogicEAR/MyBankLogic/Account!main.IAccount
java:global/MyBankLogicEAR/MyBankLogic/Account
java:app/MyBankLogic/Account
java:module/Account


We need to consider the red part, to look up the EJB. Removing the name of the bean the red part would look like /MyBankLogicEAR/MyBankLogic/NameOfThePackage.AccountManager!main.IAccount

As already said, I want the user NOT to be aware of the path, the name and just avoid him all the problems of looking up the beans.

This said let's take a look at the code produced by Massimiliano:
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
try {
            final Context context = new InitialContext(jndiProperties);
            String appName = "";
            String moduleName = "jboss-firstbean";
            String distinctName = "";
            String beanName = "FirstBean";
            String interfaceFullName = "ejb.RemoteFirstBean";
            final String jndi = "ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName;
            RemoteFirstBean statelessRemote = (RemoteFirstBean)context.lookup(jndi);

        } catch (NamingException ex) {
            System.out.println("problems");
        }
this is part of the post access EJB on jboss as 7. You may refer to it for more detailed explanations.
Thus this said, i want to avoid the user to use this snipped of code, but instead just tell which interface implementation he wants to lookup.
Interfaces are common among the client and the server, and shares the accessible remote methods. A part these methods, user must NOT be aware of everything else.

This is the solution i propose:
package utility;


import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;


public class Lookup<tipo>{

 private static final Hashtable jndiProperties = new Hashtable();
 private static final String appname = "MyBankLogicEAR";
 private static final String modulename = "MyBankLogic";
 private static final String distname = "";
 private static Context context;
 private Boolean isStateless = true;
 private String interfaceName = "";

 public Lookup(Boolean isStateLess, Class <Tipo> classe) {
  this.isStateless = isStateLess;
  this.interfaceName = classe.getName();
 }
 public <Tipo> Tipo lookup() throws Exception{
  Tipo res = null;
  String beanName = "";
  switch (interfaceName) {
  case "main.IAccount":
   beanName = "Account";
   break;
  case "main.ICliente":
   beanName = "Cliente";
   break;
  case "main.ICommonOperation":
   beanName = "Common";
   break;
  case "main.IDipendente":
   beanName = "Dipendente";
   break;
  case "main.IServizi":
   beanName = "Servizi";
   break;
  case "main.IUser":
   beanName = "Login";
   break;
  case "main.IReportGeneration":
   beanName = "Report";
   break;
  default:
   beanName = "";
   break;

  }
  if(beanName.compareTo("")==0){
   return null;
  }
  res = lookup(beanName, interfaceName, isStateless);
  return res;

 }

 private <Tipo> Tipo lookup(String beanName, String interfaceName,
   boolean stateless) throws Exception{
  jndiProperties.put(Context.URL_PKG_PREFIXES,
    "org.jboss.ejb.client.naming");
  Object bean;
  try {

   context = new InitialContext(jndiProperties);
   String jndi = "ejb:" + appname + "/" + modulename + "/" + distname
     + "/" + beanName + "!" + interfaceName;
   if (!stateless) {
    jndi = jndi + "?stateful";
   }
   //System.out.println("jndi: " + jndi);
   bean = context.lookup(jndi);
   return (Tipo) bean;
  } catch (NamingException ex) {
   throw new Exception("Non posso fare il lookup all'EJB");
  }
 }

}
In this way the user with a simple code like:
            
IUser  u = new Lookup<IUser>(Boolean.FALSE, IUser.class).lookup();
Can lookup the EJB which is responsible to provide the methods exposed in the interface IUser.


This is very simple because programmers on server side are aware of the names of the beans, and they may also write an even complex code for look up, like a factory does. Hence they can provide a simple library with this class to lookup the beans.
It is strong because user just knows whether or not an EJB is stateless or not, thus thanks to the interface and using the library it can lookup beans on the Jboss as 7 without having any problem with the name of the application, the EAR,  or the module name.