# EJB 3.1 BeanLocator - When Dependency Injection Is Not Enough

Dependency Injection has also some disadvantages:It is static - the dependencies are resolved at start time.The service user has to live with the given contracts or conventions.DI is only available for certain classes which are managed by a container.In rare cases you will have to use the BeanLocator (ServiceLocator 2.0). It encapsulates the JNDI and makes the lookup easier. In EJB 3.1 the JNDI-names were standardized and can be reliably derived from the ear, ejb and EJB-class/interface names. Knowing that, you can go even further and use a builder pattern to construct the names. 

public class BeanLocator {

    public static class GlobalJNDIName {

        private StringBuilder builder;
        private final static String PREFIX = "java:global";
        //some constants omitted...

        public GlobalJNDIName() {
        	//loading the configuration
        }

        public GlobalJNDIName withAppName(String appName) {
            this.appName = appName;
            return this;
        }

        public GlobalJNDIName withModuleName(String moduleName) {
            this.moduleName = moduleName;
            return this;
        }

        public GlobalJNDIName withBeanName(String beanName) {
            this.beanName = beanName;
            return this;
        }
        
       //some builder methods omitted
      

        String computeBeanName(Class beanClass) {
      		//some logic
        }

        private boolean isNotEmpty(String name){
            return (name != null && !name.isEmpty());
        }

        public String asString() {
        	//construction
        }

        public  T locate(Class clazz) {
            return BeanLocator.lookup(clazz, asString());
        }

        public Object locate() {
             return BeanLocator.lookup(asString());
        }
    }

    /**
     * 
     * @param clazz the type (Business Interface or Bean Class)
     * @param jndiName the global JNDI name with the pattern: java:global[/]//#
     * @return The local or remote reference to the bean.
     */
    public static  T lookup(Class clazz, String jndiName) {
            Object bean = lookup(jndiName);
            return clazz.cast(PortableRemoteObject.narrow(bean, clazz));
    }

    public static Object lookup(String jndiName) {
        Context context = null;
        try {
            context = new InitialContext();
            return context.lookup(jndiName);
        } catch (NamingException ex) {
            throw new IllegalStateException("Cannot connect to bean: " + jndiName + " Reason: " + ex, ex.getCause());
        } finally {
            try {
                context.close();
            } catch (NamingException ex) {
                throw new IllegalStateException("Cannot close InitialContext. Reason: " + ex, ex.getCause());
            }
        }
    }
}

The module and ear names are static and stable. You can specify them in a property file (global.jndi):

#Configuration for the application-wide defaults
module.name=BeanLocatorModule
application.name=BeanLocatorApp


 Alternatively, you could specify everything you need with the builder pattern:    @Test
    public void jndiName() {
        String expected = "java:global/appName/moduleName/beanName#java.io.Serializable";
        String actual = new BeanLocator.GlobalJNDIName().
                withAppName("appName").
                withModuleName("moduleName").
                withBeanName("beanName").withBusinessInterface(Serializable.class).asString();
        assertEquals(expected, actual);
    }


The BeanLocator could be used in Servlets as following:

public class TestServlet extends HttpServlet {

    private TestSingleton testSingleton;

    @Override
    public void init() throws ServletException {
        this.testSingleton = (TestSingleton) new BeanLocator.GlobalJNDIName().
                withBeanName(TestSingleton.class).
                locate();
    }


The whole project (BeanLocator) with tests was pushed into: http://kenai.com/projects/javaee-patterns/. It was tested with Glassfish v3 Preview and Netbeans 6.5/6.7.1.Interesting: the parsing of global.jndi is faster than accessing the annotations the first time.[You will find a more detailed explanation of the BeanLocator in the book "Real World Java EE Patterns - Rethinking Best Practices", page: 217, Chapter "Infrastructural Patterns And Utilities"]
