Service locator pattern


Service Locator Pattern is used when we want to use JNDI query to locate various services. Considering that looking up JNDI for a service is expensive, the service locator pattern takes advantage of caching technology. The first time a service is requested, the service locator looks up the service in JNDI and caches the service object. When the same service is requested again, the service locator looks in its cache, which can improve the performance of the application to a great extent. The following are the entities of this design pattern.

  • Service - The service that actually handles the request. A reference to this service can be found in the JNDI server.

  • Context / Initial Context - JNDI Context with a reference to the service to be found.

  • Service Locator - Service Locator is a single point of contact for obtaining services through JNDI lookup and caching services.

  • Cache - Cache stores references to services so that they can be reused.

  • Client - Client is the object that calls the service through ServiceLocator.

Implementation

We will create ServiceLocator, InitialContext, Cache, Service As various objects representing entities. Service1 and Service2 represent entity services.

ServiceLocatorPatternDemo, our demo class is here as a client and will use ServiceLocator to demonstrate the service locator design pattern.

servicelocator_pattern_uml_diagram.jpg

Step 1

Create service interface Service.

Service.java

public interface Service {
   public String getName();
   public void execute();
}

Step 2

Create the entity service.

Service1.java

public class Service1 implements Service {
   public void execute(){
      System.out.println("Executing Service1");
   }

   @Override
   public String getName() {
      return "Service1";
   }
}

Service2.java

public class Service2 implements Service {
   public void execute(){
      System.out.println("Executing Service2");
   }

   @Override
   public String getName() {
      return "Service2";
   }
}

Step 3

Create for JNDI query InitialContext.

InitialContext.java

public class InitialContext {
   public Object lookup(String jndiName){
      if(jndiName.equalsIgnoreCase("SERVICE1")){
         System.out.println("Looking up and creating a new Service1 object");
         return new Service1();
      }else if (jndiName.equalsIgnoreCase("SERVICE2")){
         System.out.println("Looking up and creating a new Service2 object");
         return new Service2();
      }
      return null;		
   }
}

Step 4

Create cache Cache.

Cache.java

import java.util.ArrayList;
import java.util.List;

public class Cache {

   private List<Service> services;

   public Cache(){
      services = new ArrayList<Service>();
   }

   public Service getService(String serviceName){
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(serviceName)){
            System.out.println("Returning cached  "+serviceName+" object");
            return service;
         }
      }
      return null;
   }

   public void addService(Service newService){
      boolean exists = false;
      for (Service service : services) {
         if(service.getName().equalsIgnoreCase(newService.getName())){
            exists = true;
         }
      }
      if(!exists){
         services.add(newService);
      }
   }
}

Step 5

Create a service locator.

ServiceLocator.java

public class ServiceLocator {
   private static Cache cache;

   static {
      cache = new Cache();		
   }

   public static Service getService(String jndiName){

      Service service = cache.getService(jndiName);

      if(service != null){
         return service;
      }

      InitialContext context = new InitialContext();
      Service service1 = (Service)context.lookup(jndiName);
      cache.addService(service1);
      return service1;
   }
}

Step 6

Use ServiceLocator to demonstrate the service locator design pattern.

ServiceLocatorPatternDemo.java

public class ServiceLocatorPatternDemo {
   public static void main(String[] args) {
      Service service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();
      service = ServiceLocator.getService("Service1");
      service.execute();
      service = ServiceLocator.getService("Service2");
      service.execute();		
   }
}

Step 7

Verify the output.

Looking up and creating a new Service1 object
Executing Service1
Looking up and creating a new Service2 object
Executing Service2
Returning cached  Service1 object
Executing Service1
Returning cached  Service2 object
Executing Service2