package com.rahul.patterns;

import java.util.*;
import javax.naming.*;
import java.rmi.RemoteException;
import javax.ejb.*;
import javax.rmi.PortableRemoteObject;
import java.io.*;
import javax.sql.*;
import javax.jms.*;
import java.sql.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import javax.transaction.*;

public class ServiceLocator{
    
    private static Properties properties=null;
    private static ServiceLocator me;
    private static InitialContext context =null;
    private static Map cache=Collections.synchronizedMap(new HashMap());
    
    private ServiceLocator() throws ServiceLocatorException{
        try{
            if(properties!=null){
                context=new InitialContext(properties);
            }else{
                context=new InitialContext();
            }
        }catch(NamingException ne){
            throw new ServiceLocatorException("Exception in Constructor ", ne);
        }
    }
    
    /** This method is to be used before invoking getInstance() of ServiceLocator for the
     * first time.  The reason for this method is so that certain properties
     * can be passed to the InitialContext object during its creation.   Examples of
     * such properties are
     *
     * "java.naming.factory.initial" key whose value is "weblogic.jndi.WLInitialContextFactory"
     *
     * in case of weblogic.
     *
     * @param pProperties The properties the InitialContext is to be passed while creation
     */
    public void setup(Properties pProperties){
        this.properties=pProperties;
    }
    /** Clears the JNDI cache being maintained by this class.
     */
    public void refresh(){
        cache.clear();
    }
    
    /** The ServiceLocator class is implemented as a Singleton.
     * This method is the standard method as per the Singleton pattern and returns the static
     * reference to the ServiceLocator stored inside the ServiceLocator Class
     * @return The single instance of ServiceLocator stored inside this singleton
     * @throws ServiceLocatorException This exception is thrown when the instance is being created for the first time
     */
    public static ServiceLocator getInstance() throws ServiceLocatorException{
        if (me==null){
            me=new ServiceLocator();
        }
        return me;
    }
    
    /** Returns the cached EJBHome object for the requested service name.
     * @param PJNDIName The name by which the object is bound in the JNDI tree
     * @param clazz The class name of the Object being looked up
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return EJBHome of the object being looked up
     */
    private EJBHome getCachedHome(String pJNDIName, Class pClazz) throws ServiceLocatorException{
        
        EJBHome home=(EJBHome)cache.get(pJNDIName);
        if (home==null){
            home=getHome(pJNDIName,pClazz, false);
            cache.put(pJNDIName,home);
        }
        return home;
    }
    
    /** Returns the EJBHome object for the requested service name.
     * @param pJNDIName The name by which the object is bound in the JNDI tree
     * @param pClazz The class name of the Object being looked up
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return EJBHome of the object being looked up
     */
    public EJBHome getHome(String pJNDIName, Class pClazz , boolean pFromCache) throws ServiceLocatorException{
        if (pFromCache){
            return getCachedHome(pJNDIName,pClazz);
        }else{
            try{
                Object objref=context.lookup(pJNDIName);
                EJBHome home=(EJBHome)PortableRemoteObject.narrow(objref,pClazz);
                return home;
            }catch(NamingException ne){
                throw new ServiceLocatorException("Exception when returning home",ne);
            }
        }
    }
    
    /** Returns the EJBHome object for the requested service name.
     * @param pServiceId The name of the service as defined in the Service class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return EJBHome of the object being looked up
     */
    public EJBHome getHome(int pServiceId, boolean pFromCache) throws ServiceLocatorException{
        return this.getHome(Services.getServiceName(pServiceId),Services.getServiceClass(pServiceId), pFromCache);
    }
    
    /** Returns the DataSource object for the requested service name.
     * @param pServiceId The service id as defined by the services
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return DataSource of the object being looked up
     */
    public DataSource getDBConn(int pServiceId , boolean pFromCache) throws ServiceLocatorException{
        return this.getDBConn(Services.getServiceName(pServiceId), pFromCache);
    }
    
    private DataSource getCachedDBConn(String pServiceName) throws ServiceLocatorException{
        DataSource ds= (DataSource) cache.get(pServiceName);
        if(ds==null){
            ds=getDBConn(pServiceName, false);
            cache.put(pServiceName,ds);
        }
        return ds;
    }
    
    /** Returns the DataSource object for the requested service name.
     * @param pJNDIName The name by which the object is bound in the JNDI tree
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return DataSource of the object being looked up
     */
    public DataSource getDBConn(String pJNDIName , boolean pFromCache) throws ServiceLocatorException{
        if(pFromCache){
            return getCachedDBConn( pJNDIName );
        }else{
            try{
                DataSource  ds=(DataSource)this.context.lookup(pJNDIName);
                return ds;
            }catch(NamingException ne){
                throw new ServiceLocatorException("NamingException in getDBConn",ne);
            }
        }
    }
    /** Returns the EJBObject object for the requested pEJBHomeJndiName name.
     *  The EJBObject is not cached since the Home object is a factory
     * @param pEJBHomeJndiName The name by which the EJBHome object is bound in the JNDI tree
     * @param pEJBHomeClass The EJBHome class name
     * @param pEJBRemoteClass The EJBRemote class name
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return EJBObject
     */
    //  CustomerTerminal customerTerminal = 
   //(CustomerTerminal)ServiceLocator.getStatelessEJB(pHomeJndiName, pHomeClass, pEJBRemoteClass);
    public EJBObject getStatelessEJB(String pEJBHomeJndiName , Class pEJBHomeClass, 
                                                            Class pEJBRemoteClass) throws ServiceLocatorException{
        EJBObject ejbobject;
        EJBHome ejbhome = this.getCachedHome(pEJBHomeJndiName, pEJBHomeClass);
        try {
            Class aclass[] = new Class[0];
            Object aobj[] = new Object[0];
            Method method = ejbhome.getClass().getMethod("create", aclass);
            ejbobject = (EJBObject)method.invoke(ejbhome, aobj);
        }
        catch(NoSuchMethodException nosuchmethodexception) {
            throw new ServiceLocatorException("Creation method doesn't exist" , nosuchmethodexception);
        }
        catch(IllegalAccessException illegalaccessexception) {
            throw new ServiceLocatorException("Error accessing the create method" , illegalaccessexception);
        }
        catch(InvocationTargetException invocationtargetexception) {
            throw new ServiceLocatorException("Error invoking the create method", invocationtargetexception);
        }
        catch(ClassCastException classcastexception) {
            throw new ServiceLocatorException(" is not an EJBObject", classcastexception);
        }
        catch(RuntimeException runtimeexception) {
            throw new ServiceLocatorException("Couldn't get remote interface " , runtimeexception );
        }
        if(ejbobject != null)
            try {
                Class class1 = ejbobject.getClass();
                // narrows the stub examples.ejb20.basic.statelessSession.TraderBean_3p5ifg_EOImpl_WLStub
                ejbobject = (EJBObject)PortableRemoteObject.narrow(ejbobject, class1);
                // narrows to the remote examples.ejb20.basic.statelessSession.Trader
                ejbobject = (EJBObject)PortableRemoteObject.narrow(ejbobject, pEJBRemoteClass);
            }
            catch(ClassCastException classcastexception) {
                throw new ServiceLocatorException("Remote interface is not of type javax.ejb.EJBObject" , 
                                                                            classcastexception );
            }
        catch(RuntimeException runtimeexception) {
            throw new ServiceLocatorException("Couldn't get remote interface for ", runtimeexception);
        }
        return ejbobject;
    }
    
    /** Returns the EJBObject object for the requested Service name.
     *  The EJBObject is not cached since the Home object is a factory
     * @param pServiceId The ServiceId as defined in Services class
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return EJBObject
     */
    public EJBObject getStatelessEJB(int pServiceId) throws ServiceLocatorException{
        return this.getStatelessEJB(Services.getServiceName(pServiceId),
                                                      Services.getServiceClass(pServiceId),
                                                       Services.getServiceRemoteClass(pServiceId));
    }
    
    // TopicConnection and QueueConnection ,  Topic and Queue
    /** Returns the TopicConnectionFactory object bound to the pJNDIName
     * @param pJNDIName The name by which the object is bound in the JNDI tree
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return EJBHome of the object being looked up
     */
    
    public TopicConnectionFactory getTopicConnectionFactory(String pJNDIName, boolean pFromCache) 
                throws ServiceLocatorException{
        if(pFromCache){
            return getCachedTopicConnectionFactory(pJNDIName);
        }else{
            try{
                TopicConnectionFactory topicConnectionFactory=(TopicConnectionFactory)context.lookup(pJNDIName);
                return topicConnectionFactory;
            }catch(NamingException ne){
                throw new ServiceLocatorException("unable to getTopicConnection " ,ne);
            }
        }
    }
    
    private TopicConnectionFactory getCachedTopicConnectionFactory(String pJndiName) 
                throws ServiceLocatorException{
        TopicConnectionFactory topicConnectionFactory=(TopicConnectionFactory)cache.get(pJndiName);
        if (topicConnectionFactory==null){
            topicConnectionFactory=getTopicConnectionFactory(pJndiName, false);
            cache.put(pJndiName,topicConnectionFactory);
        }
        return topicConnectionFactory;
    }
    
    /** Returns the TopicConnectionFactory object bound to the pJNDIName from the Service
     * @param pServiceId The Service Name as defined in the Services class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return TopicConnectionFactory of the object being looked up
     */
    
    public TopicConnectionFactory getTopicConnectionFactory(int pServiceId , boolean pFromCache) 
               throws ServiceLocatorException{
        return getTopicConnectionFactory(Services.getServiceName(pServiceId), pFromCache);
    }
    
    /** Returns the QueueConnectionFactory object bound to the pJNDIName
     * @param pJNDIName The name by which the object is bound in the JNDI tree
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return QueueConnectionFactory of the object being looked up
     */
    public QueueConnectionFactory getQueueConnectionFactory(String pJNDIName , boolean pFromCache) 
              throws ServiceLocatorException{
        if(pFromCache){
            return getCachedQueueConnectionFactory(pJNDIName);
        }else{
            try{
                QueueConnectionFactory queueConnectionFactory=(QueueConnectionFactory)context.lookup(pJNDIName);
                return queueConnectionFactory;
            }catch(NamingException ne){
                throw new ServiceLocatorException("unable to getQueueConnectionFactory " ,ne);
            }
        }
    }
    
    private QueueConnectionFactory getCachedQueueConnectionFactory(String pJndiName) 
                throws ServiceLocatorException{
        QueueConnectionFactory queueConnectionFactory=(QueueConnectionFactory)cache.get(pJndiName);
        if (queueConnectionFactory==null){
            queueConnectionFactory=getQueueConnectionFactory(pJndiName , false);
            cache.put(pJndiName,queueConnectionFactory);
        }
        return queueConnectionFactory;
    }
    
    /** Returns the QueueConnectionFactory object bound to the pJNDIName from the Service
     * @param pServiceId The Service Name as defined in the Services class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return QueueConnectionFactory of the object being looked up
     */
    public QueueConnectionFactory getQueueConnectionFactory(int pServiceId, boolean pFromCache) 
              throws ServiceLocatorException{
        return getQueueConnectionFactory(Services.getServiceName(pServiceId), pFromCache);
    }
    
    /** Returns the Topic object bound to the pJNDIName
     * @param pJNDIName The JNDIName of the Object being looked up
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return Topic of the object being looked up
     */
    public Topic getTopic(String pJNDIName , boolean pFromCache) throws ServiceLocatorException{
        if(pFromCache){
            return getCachedTopic(pJNDIName);
        }else{
            try{
                Topic topic=(Topic)context.lookup(pJNDIName);
                return topic;
            }catch(NamingException ne){
                throw new ServiceLocatorException("unable to getTopic " ,ne);
            }
        }
    }
    
    private Topic getCachedTopic(String pJndiName) throws ServiceLocatorException{
        Topic topic=(Topic)cache.get(pJndiName);
        if (topic==null){
            topic=getTopic(pJndiName , false);
            cache.put(pJndiName,topic);
        }
        return topic;
    }
    /** Returns the Topic object bound to the pJNDIName from the Service
     * @param pServiceId The Service Name as defined in the Services class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return Topic of the object being looked up
     */
    
    public Topic getTopic(int pServiceId , boolean pFromCache) throws ServiceLocatorException{
        return getTopic(Services.getServiceName(pServiceId), pFromCache);
    }
    
    /** Returns the Queue object bound to the pJNDIName
     * @param pJNDIName The JNDIName of the Object being looked up
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return Queue of the object being looked up
     */
    
    public Queue getQueue(String pJNDIName, boolean pFromCache) throws ServiceLocatorException{
        if(pFromCache){
            return getCachedQueue(pJNDIName);
        }else{
            try{
                Queue queue=(Queue)context.lookup(pJNDIName);
                return queue;
            }catch(NamingException ne){
                throw new ServiceLocatorException("unable to getQueue " , ne);
            }
        }
    }
    
    private Queue getCachedQueue(String pJndiName) throws ServiceLocatorException{
        Queue queue=(Queue)cache.get(pJndiName);
        if (queue==null){
            queue=getQueue(pJndiName , false);
            cache.put(pJndiName,queue);
        }
        return queue;
    }
    /** Returns the Queue object bound to the pJNDIName from the Service
     * @param pServiceId The Service Name as defined in the Services class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exceps thrown
     * @return Queue of the object being looked up
     */
    public Queue getQueue(int pServiceId , boolean pFromCache) throws ServiceLocatorException{
        return getQueue(Services.getServiceName(pServiceId), pFromCache);
    }
    
    /** Returns the cached EJBLocalHome object for the requested service name.
     * @param name The name by which the object is bound in the JNDI tree
     * @param clazz The class name of the Home Object being looked up
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return EJBLocalHome of the object being looked up
     *
     */
    private EJBLocalHome getCachedLocalHome(String name, Class clazz) throws ServiceLocatorException{
        EJBLocalHome home=(EJBLocalHome)cache.get(name);
        if (home==null){
            home=(EJBLocalHome)getLocalHome(name,clazz,false);
            cache.put(name,home);
        }
        return home;
    }
    
    /** Returns the EJBLocalHome object for the requested service name.
     * @param name The name by which the object is bound in the JNDI tree
     * @param clazz The class name of the Home Object being looked up
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return EJBLocalHome of the object being looked up
     */
    public EJBLocalHome getLocalHome(String name, Class clazz , boolean pFromCache) throws ServiceLocatorException{
        if(pFromCache){
            return getCachedLocalHome(name,clazz);
        }else{
            try{
                Object objref=context.lookup(name);
                EJBLocalHome localHome=(EJBLocalHome)PortableRemoteObject.narrow(objref,clazz);
                return localHome;
            }catch(NamingException ne){
                throw new ServiceLocatorException("Exception when returning localhome", ne);
            }
        }
    }
    
    /** Returns the EJBLocalHome object for the requested service name.
     * @param pServiceId The Service Name as defined in this class
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI to retrieve the object
     * @throws ServiceLocatorException If any errors occur on Lookup then this exception is thrown
     * @return EJBLocalHome of the object being looked up
     */
    public EJBLocalHome getLocalHome(int pServiceId, boolean pFromCache) 
              throws ServiceLocatorException{
        return this.getLocalHome(Services.getServiceName(pServiceId),
                                                 Services.getServiceClass(pServiceId), pFromCache);
    }
    
    /** Returns the mail Session object for the requested service name.
     * @param pJNDIName The JNDI name by which this parameter is to be looked up
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @return an instance of javax.mail.Session that is bound in the JNDI tree
     */
    public javax.mail.Session getMailSession(String pJNDIName, boolean pFromCache) 
             throws ServiceLocatorException {
        if(pFromCache){
            return getCachedMailSession(pJNDIName);
        }else {
            javax.mail.Session session=null;
            try{
                session = (javax.mail.Session)context.lookup(pJNDIName);
            }catch(NamingException ne){
                throw new ServiceLocatorException("Naming Exception thrown in getMailSession()", ne);
            }
            Properties props = new Properties();
            props.put("mail.smtp.host", Services.HOST_NAME);
            return session.getInstance( props,null);
        }
    }
    
    /** Returns the cached mail Session object for the requested service name.
     * @param pJNDIName The JNDI name by which this parameter is to be looked up
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return javax.mail.Session
     */
    private javax.mail.Session getCachedMailSession(String pJNDIName) throws ServiceLocatorException {
        javax.mail.Session  session=(javax.mail.Session )cache.get(pJNDIName);
        if (session==null){
            session=getMailSession(pJNDIName, false);
            cache.put(pJNDIName,session);
        }
        return session;
    }
    
    private URL getCachedURL(String pJNDIName) throws ServiceLocatorException{
        URL url=(URL)cache.get(pJNDIName);
        if (url==null){
            url=getURL(pJNDIName, false);
            cache.put(pJNDIName,url);
        }
        return url;
    }
    /**returns the URL object bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the boolean value corresponding to the env pJNDIName name.
     */
    public URL getURL(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedURL(pJNDIName);
        }else {
            try{
                URL url = (URL)context.lookup(pJNDIName);
                return url;
            }catch(NamingException ne){
                throw new ServiceLocatorException("Naming Exception thrown in getURL()", ne);
            }
        }
    }
    
    /**returns the boolean bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the boolean value corresponding to the env pJNDIName name.
     */
    public boolean getBoolean(String pJNDIName, boolean pFromCache) throws ServiceLocatorException {
        
        if(pFromCache){
            return getCachedBoolean(pJNDIName);
        }else {
            try {
                Boolean bool = (Boolean)context.lookup(pJNDIName);
                return bool.booleanValue();
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getBoolean failed with NamingException",ne);
            }
        }
    }
    
    private boolean getCachedBoolean(String pJNDIName) throws ServiceLocatorException {
        
        Boolean bool=(Boolean)cache.get(pJNDIName);
        if (bool==null){
            bool=new Boolean(getBoolean(pJNDIName ,false));
            cache.put(pJNDIName,bool);
        }
        return bool.booleanValue();
    }
    
    
    /**returns the String bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the String value corresponding to the env pJNDIName name.
     */
    public String getString(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedString(pJNDIName);
        }else {
            try {
                return (String)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getString failed",ne);
            }
        }
    }
    
    private String getCachedString(String pJNDIName) throws ServiceLocatorException {
        String envEntry =(String)cache.get(pJNDIName);
        if (envEntry==null){
            envEntry=getString(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    /**returns the String bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the String value corresponding to the env pJNDIName name.
     */
    public Character getCharacter(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedCharacter(pJNDIName);
        }else {
            try {
                return (Character)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getCharacter failed",ne);
            }
        }
    }
    
    private Character getCachedCharacter(String pJNDIName) throws ServiceLocatorException {
        Character envEntry =(Character)cache.get(pJNDIName);
        if (envEntry==null){
            envEntry=getCharacter(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
            this.log("putting in cache and setting it as "+envEntry);        
        }
        return envEntry;
    }
    /**returns the Byte bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Byte value corresponding to the env pJNDIName name.
     */
    public Byte getByte(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedByte(pJNDIName);
        }else {
            try {
                return (Byte)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getByte failed",ne);
            }
        }
    }
    
    private Byte getCachedByte(String pJNDIName) throws ServiceLocatorException {
        Byte envEntry =(Byte)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getByte(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    
    
    /**returns the Short bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Short value corresponding to the env pJNDIName name.
     */
    public Short getShort(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedShort(pJNDIName);
        }else {
            try {
                return (Short)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getShort failed",ne);
            }
        }
    }
    
    private Short getCachedShort(String pJNDIName) throws ServiceLocatorException {
        Short envEntry =(Short)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getShort(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    
    /**returns the Integer bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Integer value corresponding to the env pJNDIName name.
     */
    public Integer getInteger(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedInteger(pJNDIName);
        }else {
            try {
                return (Integer)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getInteger failed",ne);
            }
        }
    }
    
    private Integer getCachedInteger(String pJNDIName) throws ServiceLocatorException {
        Integer envEntry =(Integer)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getInteger(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    
    /**returns the Long bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Long value corresponding to the env pJNDIName name.
     */
    public Long getLong(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedLong(pJNDIName);
        }else {
            try {
                return (Long)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getLong failed",ne);
            }
        }
    }
    
    private Long getCachedLong(String pJNDIName) throws ServiceLocatorException {
        Long envEntry =(Long)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getLong(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    
    /**returns the Double bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Double value corresponding to the env pJNDIName name.
     */
    public Double getDouble(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedDouble(pJNDIName);
        }else {
            try {
                return (Double)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getDouble failed",ne);
            }
        }
    }
    
    private Double getCachedDouble(String pJNDIName) throws ServiceLocatorException {
        Double envEntry =(Double)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getDouble(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    /**returns the Float bound by the pJNDIName in the JNDI tree
     * @param pJNDIName The name by which the String is bound in JNDI
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the Float value corresponding to the env pJNDIName name.
     */
    public Float getFloat(String pJNDIName , boolean pFromCache) throws ServiceLocatorException {
        if(pFromCache){
            return getCachedFloat(pJNDIName);
        }else {
            try {
                return (Float)context.lookup(pJNDIName);
            } catch (NamingException ne) {
                throw new ServiceLocatorException("getFloat failed",ne);
            }
        }
    }
    
    private Float getCachedFloat(String pJNDIName) throws ServiceLocatorException {
        Float envEntry =(Float)cache.get(pJNDIName);
        if (pJNDIName==null){
            envEntry=getFloat(pJNDIName, false);
            cache.put(pJNDIName,envEntry);
        }
        return envEntry;
    }
    
    /**
     * This method obtains the UserTransaction itself for a caller
     * The JNDI Name being looked up being "java:comp/UserTransaction"
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the UserTransaction corresponding to the name parameter
     */
    public UserTransaction getUserTransaction(boolean pFromCache) throws ServiceLocatorException {
        String uTName=Services.USER_TRANSACTION_JNDI_NAME;
        UserTransaction userTransaction = null;
        if(pFromCache){
            return getCachedUserTransaction();
        }else{
            try {
                if (cache.containsKey(uTName)) {
                    userTransaction = (UserTransaction) cache.get(uTName);
                } else {
                    userTransaction = (UserTransaction)context.lookup(uTName);
                }
            }catch (NamingException ne) {
                throw new ServiceLocatorException("Naming exception thrown",ne);
            }
        }
        return userTransaction;
    }
    
    /**
     * This method obtains the Cached UserTransaction itself for a caller
     * @param pFromCache if you want the result from cache the value is true else false
     * a parameter of false will invoke JNDI
     * @throws ServiceLocatorException This exception is thrown when a JNDI NamingException is thrown
     * @return the UserTransaction
     */
    private UserTransaction getCachedUserTransaction() throws ServiceLocatorException {
        String uTName=Services.USER_TRANSACTION_JNDI_NAME;
        UserTransaction userTransaction = (UserTransaction)cache.get(uTName);
        if (userTransaction==null){
            userTransaction=getUserTransaction(false);
            cache.put(uTName, userTransaction);
        }
        return userTransaction ;
    }
    
    private void log(String s) {
        if(VERBOSE) {
            System.out.println(s);
        }
  }
    boolean VERBOSE=true;
}