EJBServices class - encapsulating EJBHomes jndi names & classes

Discussions

J2EE patterns: EJBServices class - encapsulating EJBHomes jndi names & classes

  1. the EJBServices class contains static fields holding every EJB's jndi name, home class and an INT "code" to identify the EJB.

    The class itself may require a bit extra coding work
    But in large projects its convenient that:
    All changes to jndi names and classes are done in one place
    Keeping the service Locator's code generic and clean
    And very helpful for the client side developers


    example: (try 2 ignore the syntax)
    the following example shows the EJBservices Implementation class, it encapsulate ejbs home names and classes
    note: the example consist of one ejb - ProcessManager

    public class EJBServices{

     static final int ProcessManager = 1;//the ejb's "service code"

     static final Class ProcessManagerClass = //home's class
               ProcessManagerHome.class;

     static final String ProcessManagerName = //ejb's jndi name
               "ProcessManagerHome";


    //this method takes an int code and return the bean's the Home class


    public static Class getHomeClass(int service){
         switch( service ){
         case EJBServices.ProcessManager :
              return ProcessManagerClass;
          }
        return null;

    }



    //this method again takes the code and return the jndi name

    public static String getJndiName(int service){
         switch( service ){
         case EJBServices.ProcessManager :
              return ProcessManagerName;
          }
        return null;

    }





    business delegate:
    the business delegate simply invoke the serviceLocator's
    getService() method to get the EJBObject

    public class aDelegate{

      ServiceLocator services;
      ProcessManager managerEJB; //ejb remote interface

    public aDelegate(){
      services = new ServiceLocator();

      managerEJB = (ProcessManager)
           services.getService(EJBServices.ProcessManager);

    }



    Service Locator:
    you all know this pattern
    though here i suggest to implement it as a simple pojo
    and not as a singleton , since the EJBHome factory is a singletone that caches the home interfaces.
    and the Service Locator is also used to gain access to dataSources etc, so in my opinion in an enterprise application it should be a simple pojo
    ......

    EJBObject getService(int service){
        
        Class homeClass = EJBServices.getHomeClass(service);
        String jndiName = EJBServices.getJndiName(service);

        EJBHome home = EJBHomeFactory.getInstance()
                       .getHome(homeClass,jndiName);

        return home.create();
    .......


    EJBHomeFactory:
    the home factory is simply a singletone that caches the ejb's home in a map.
    like -

     getHome(Class homeClass,String jndiName){
            EJBHome home =
                (EJBHome)PortableRemoteObject.narrow(
                 ctx.lookup(jndiName),homeClass);





    looking forward to your opinions
    regards
    Alon.
  2. But JNDI Names are also in DD[ Go to top ]

    Good idea!

    You say
    "All changes to jndi names and classes are done in one place Keeping the service Locator's code generic and clean
    And very helpful for the client side developers"

    However, JNDI names primarily come from the Deployment descriptor. That makes it two places. It would be nice if EJBServices.java can be generated from the DD, but then you have another level indirection between the JNDI names and the int constants clients use.

    I strongly believe there is some scope for auto-generation of either the java file it self, or some sort of an external mapping file.

    Cheers,
    -Ajith Kallambella
  3. If an EJB gets un-deployed and then redeployed, caching home interfaces can be problematic. If this is really expected to be an expensive call (which it is not *within* most app servers) then you may want to add some retry logic.


    Also, why define this numeric mapping rather than a flyweight that contains both the JNDI name and the home interface class?

    public static final Foo FOO = new Foo("ProcessManagerHome", ProcessManagerHome.class);
  4. RE: EJBServices class[ Go to top ]

    IMO, we can use ServiceLocator as a lower-level service and encapulate with EJBService, so that we can invoke EJB more simpler:

    For example:


    public class EJBService {

        private ServiceLocator serviceLocator;

        public EJBService (ServiceLocator serviceLocator) {
            this.serviceLocator = serviceLocator;
        }

        public Object getRemoteObject(String jndiName) throws EJBException {
            try {
                EJBHome ejbHome = serviceLocator.getRemoteHome(jndiName, EJBHome.class);
                //get the method of create
                Method method = ejbHome.getClass().getDeclaredMethod("create",
                        new Class[0]);
                Object obj = method.invoke(ejbHome, new Object[0]);
                return obj;
            } catch (ServiceLocatorException e) {
                throw new EJBException(e);
            } catch (SecurityException e) {
                throw new EJBException(e);
            } catch (IllegalArgumentException e) {
                throw new EJBException(e);
            } catch (NoSuchMethodException e) {
                throw new EJBException(e);
            } catch (IllegalAccessException e) {
                throw new EJBException(e);
            } catch (InvocationTargetException e) {
                throw new EJBException(e);
            }
        }
    }


    Use EJBService

    public interface FooEJBExample extends EJBObject
    {
        /**
         *
         * This gets content
         *
         * @param name <code>String</code> name for greeting
         * @return string which makes up "Hello, name"
        */
        public String hello ()
        throws RemoteException;

    }

    FooEjbExample obj =
          (FooEjbExample) myEJBService.getObj ("java:comp/env/FooEjbExample");


    obj.hello
  5. I wrote up an article/blog entry discussing how to implement the pattern.

    http://www.trajano.net/2005/08/ejb-pattern-service-locator-with.html

    It is similar to what you already have except I detailed with test cases and a step by step approach of how to get there. Its a multipart article, the next article will be discussing optimizations to the codebase.
  6. Have you seen how Spring handles this: client-side EJB access with zero coding. You simply specify the business interface and JNDI name in a config file, and Spring automatically calls home.create() and generates a proxy. Calling code is decoupled from the EJB API, depending only on the business methods interface (typically the superinterface of the EJB component interface, and typically not aware that EJB will be used to implement it). No more Service Locator or Business Delegate custom code.

    Rgds
    Rod