Friday

Functional Junit Test - Part 3 - Hot Swapping Using JDK Proxy

Have you ever wished that you could replace an instance with another stub during runtime? Spring framework provides an TargetSource implementation - HotSwappableTargetSource that facilitates such hot swapping at runtime. If for whatever reason, you are not using Spring framework, here is an alternative - JDK Proxy.

The following example shows how to implement JDK Proxy to swap the DAO implementation at runtime. The idea applies to any implementation as long as there is an interface backing it up (as you are aware that JDK proxy only works for interfaces).

Please note the code below only demonstrates the concept and is not working code.

Create an InvocationHandler:

public class Swapper implements java.lang.reflect.InvocationHandler {
        private Object impl;
        private Object realDAO;
        private Object stubDAO;
        boolean useRealDAO;
       
...

       public Object invoke(Object proxy, Method method, Object[] args) {
                  //the logic to choose real or stub depends on your own system. e.g. you may use a flag
                  //to determine which object to return.
                  if (useRealDAO) impl = realDAO;
                  else impl=stubDAO;
                  return method.invoke(impl, args);
       }
}

When the DAO is created, it has to use proxy:

            Swapper swapper= new Swapper(readDAO, stubDAO);
            Object proxy = Proxy.newProxyInstance(stubDAO.getClass().getClassLoader(),
                    new Class[] { theInterface }, swapper);

where "theInterface" is the interface name for real and stub DAO.

In your business service class:

SomeServiceClass
{
    EmployeeDAO employeeDAO= (use the above created proxy)
    void loadEmployeeDetails(Employee employee)
   {
      dao.loadDetails();   
    }
}


To swap at runtime:

((Swapper)employeeDAO).setUseRealDAO(true);

service.loadEmployeeDetails(employee); //loads detail through the real DAO

((Swapper)employeeDAO).setUseRealDAO(false);

service.loadEmployeeDetails(employee); //loads detail through the stub DAO


Please note that, in real world, the DAO will most like be created by a factory class or a container so that the code creating the proxy doesn't need to duplicate.



This shows the simple idea:

 Service
    |

 Proxy

  /    \
real  stub

This technique will also support dynamic reconfiguration of any Java application.

No comments: