Wednesday, November 10, 2010

Service Locator

Configurable Service Locator: Service locator is used to hide the complexity of look up an object from centralized location.

Below is a configurable Service Locator implementation which can be used to locate EJB(3.0), JMS, DATATSOURCE. This Service locator totally depends on a properties file which will have all information about environment and jndi names. If you want to integrate a new jndi name to this locator you will have to just add a key value name pair to properties file and no changes in java code.

If you have created a JDBC JNDI name jdbc/JdbcOraclePool then you have to put it as JDBC_JNDI_ORACLE=jdbc/JdbcOraclePool in properties file. 

There are two KEY which can be changed for different application server vendor and should be defined in properties file and they are CONTEXT_PROVIDER_URL and CONTEXT_INITIAL_CONTEXT_FACTORY.

Below an example for Glassfish server

CONTEXT_PROVIDER_URL=iiop://127.0.0.1:3700
CONTEXT_INITIAL_CONTEXT_FACTORY =com.sun.appserv.naming.S1ASCtxFactory
JDBC_JNDI_NAME=jdbc/__CallFlowPool

Jav Code for PropertyReader can be found at
http://tiwarijavaj2eeblog.blogspot.com/2010/11/property-file-reader.html

This locator does not cast object after lookup so client should cast to appropriate type after getting JNDI object from Service Locator.


package org.paandav.servicelocator;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.paandav.propreader.PropertyReader;
public class ServiceLocator
{
 private static final Lock     lock        = new ReentrantLock();
 private static ServiceLocator sloc        = null;
 private Map<String, String>   propertyMap = null;
 private Context               ctx         = null;
 private Map<String, Object>   cache       = null;
 private ServiceLocator()throws ServiceLocatorException
 {
  try
  {
   propertyMap = PropertyReader.getMapForPropertiesFileKey(ServiceLocatorKeys.SERVICE_LOCATOR_FILE_KEY);
   Hashtable<String, String> ctxProp = new Hashtable<String, String>(2);
   ctxProp.put(Context.PROVIDER_URL,
               propertyMap.get(ServiceLocatorKeys.CONTEXT_PROVIDER_URL).trim());
   ctxProp.put(Context.INITIAL_CONTEXT_FACTORY,
               propertyMap.get(ServiceLocatorKeys.CONTEXT_INITIAL_CONTEXT_FACTORY).trim());
   ctx   = new InitialContext(ctxProp);
   cache = new ConcurrentHashMap<String, Object>();
  }
  catch (Exception ex)
  {
   ex.printStackTrace();
   throw new ServiceLocatorException(ex.getMessage());
  }
 }
 public static ServiceLocator getInstance()
   throws ServiceLocatorException
 {
  if (sloc == null)
  {
   try
   {
    lock.lock();
    if (sloc == null)
    {
     sloc = new ServiceLocator();
    }
   }
   finally
   {
    lock.unlock();
   }
  }
  return sloc;
 }
 public Object getObject(String jndiKeyName)
   throws ServiceLocatorException
 {
  if ((jndiKeyName == null) || "".equals(jndiKeyName))
  {
   throw new IllegalArgumentException("Invalid key name");
  }
  Object ds                 = null;
  String dataSourceJNDIName = propertyMap.get(jndiKeyName);
  if ((dataSourceJNDIName == null) || "".equals(dataSourceJNDIName))
  {
   throw new IllegalArgumentException("JNDI name not found in properties file");
  }
  if (!cache.containsKey(dataSourceJNDIName))
  {
   try
   {
    lock.lock();
    if (!cache.containsKey(dataSourceJNDIName))
    {
     ds = ctx.lookup(dataSourceJNDIName);
     if (ds != null)
     {
      cache.put(dataSourceJNDIName, ds);
     }
    }
   }
   catch (Exception ex)
   {
    throw new ServiceLocatorException(ex.getMessage());
   }
   finally
   {
    lock.unlock();
   }
  }
  else
  {
   ds = cache.get(dataSourceJNDIName);
  }
  return ds;
 }
}

No comments:

Post a Comment