Writing a dynamic proxy class

The following example uses a dynamic proxy class to keep track of how much time it takes to execute a method.

Two classes are implemented: JMSTransporter and TibcoTransporter, both implementing the interface Transporter.

interface Transporter {  
   public void sendMessage(String message);
}
 
class TibcoTransporter implements Transporter {
   public void sendMessage(String message) {
      ...
   }
}
 
class JMSTransporter implements Transporter {
   public void sendMessage(String message) {
      ...
   }
}

Suppose we need to do some performance tests to see how long each transporter takes to perform its task. The typical way of doing this is to record a timestamp in the beginning of the method and at the end and printing out the difference:

   long start = System.currentTimeMillis();
 
   .. perform job
 
   long stop = System.currentTimeMillis();
   System.out.println("Total time it took: " + (stop - start));

We would have to do that for the TibcoTransporter as well as the JMSTransporter. It also uglifies the code, makes it harder to maintain (remove when it goes in production) and may introduce bugs. You could also write a wrapper around it, but this is a tedious task and would require you to do this for every interface.

Since JDK1.3, you can simplify this task using a dynamic proxy class. A dynamic proxy class is a class that implements a list of interfaces at runtime. An instance of this class can handle method invocations of the interface(s) and dispatches them to the object that implements the interface.

Writing a proxy class is simple: implement the InvocationHandler interface and its method

   public Object invoke(Object proxy, Method method, Object[] args)            
                     throws Throwable; 

To instantiate a proxy object:

   Proxy.newProxyInstance(ClassLoader loader,
                          Class[] interfaces,
                          InvocationHandler h) 

In our example, the proxy class TimerProxy is created. All method invocations to the interfaces that were specified when instantiating the proxy object with newProxyInstance are dispatched to the TimerProxy.

Main.java:

import java.lang.reflect.*;
 
interface Transporter
{
   public void sendMessage(String message);
}
 
class TibcoTransporter implements Transporter
{
   public void sendMessage(String message) {
      // let's assume the message takes 1 second to send 
      // using Tiboc RendezVous
      try {
         Thread.sleep(1000);
      }
      catch(InterruptedException e) {
      }
      System.out.println("Message '" + message + "' sent with the TibcoTransporter");
   }
}
 
class JMSTransporter implements Transporter
{
   public void sendMessage(String message) {
      // let's assume the message takes 2 seconds to send 
      // using a JMS implementation
      try {
         Thread.sleep(2000);
      }
      catch(InterruptedException e) {
      }
      System.out.println("Message '" + message + "' sent with the JMSTransporter");
   }
}
   
public class Main
{
   public static void main(String []args) {
      TibcoTransporter tibcoTransporter = new TibcoTransporter();

      Transporter transporter1 = (Transporter) TimerProxy.newInstance(new TibcoTransporter());
      transporter1.sendMessage("Hi");

      Transporter transporter2 = (Transporter) TimerProxy.newInstance(new JMSTransporter());
      transporter2.sendMessage("Hi");
   }
}

class TimerProxy implements InvocationHandler
{
   private Object obj;
 
   public TimerProxy(Object obj) {
      this.obj = obj;
   }
  
   public static Object newInstance(Object obj) {
      return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                                    obj.getClass().getInterfaces(),
                                    new TimerProxy(obj));
   }
 
   public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
   {
      Object result = null;
      long start, stop;
      System.out.println("- Entering " + m.getName() + " in class " + obj.getClass());
      start = System.currentTimeMillis();
      try {
         result = m.invoke(obj, args);
      }
      catch(InvocationTargetException e) {
         throw e.getTargetException();
      }
      catch(Exception e) {
         throw new RuntimeException(e.getMessage());
      }
      finally {
         stop = System.currentTimeMillis();
         System.out.println("- Total time it took: " + (stop - start));
      }
      System.out.println("- Exiting " + m.getName() + " in class " + obj.getClass());
 
      return result;
   }
}

outputs:

- Entering sendMessage in class class TibcoTransporter
Message 'Hi' sent with the TibcoTransporter
- Total time it took: 1002
- Exiting sendMessage in class class TibcoTransporter
- Entering sendMessage in class class JMSTransporter
Message 'Hi' sent with the JMSTransporter
- Total time it took: 2003
- Exiting sendMessage in class class JMSTransporter

Other uses for a dynamic proxy are logging, parameter validation, access control, error handling, …

For more information on Dynamic Proxy Classes, check here