Wednesday 17 January 2007

Java Dynamic Proxies: One Step from Aspect-oriented Programming

Dynamic Proxies are a nifty, often overlooked feature of the Java language. Introduced in J2SE 1.3, they allow you to intercept method calls so you can interpose additional behavior between a class caller and its"callee". From the caller's perspective, a proxy is no different from the real class that it encapsulates — it presents the same interfaces and follows all the rules and conventions expected of the real class. For savvy programmers, proxies present a unique time saving opportunity. Why spend effort inserting and maintaining such common code as debugging and logging when you can just centralize it and put in a proxy instead? Logging, retry semantics,performance metrics, performance optimizations, test stubs, and caching are examples of application concerns that cut across class implementations regardless of design and business function. Trends within the Java community are modeling such concerns as aspects—important to the application but orthogonal to the main task at hand. Rather than coding this logic painstakingly throughout your application, wouldn't it be nice if you could just express this behavior in one place and have it apply to every class? With Dynamic proxies, you can easily do so—and once youunderstand proxies, you've made a small conceptual leap towards the bigger picture—aspect-oriented programming (AOP).

Dynamic Proxy Basics
A dynamic proxy is a class that implements a list of interfaces, which you specify at runtime when you create the proxy. To create a proxy, use the static method java.lang.reflect.Proxy.newP
roxyInstance().This method takes three arguments:

  • The class loader to define the proxy class
  • An invocation handler to intercept and handle method calls
  • A list of interfaces that the proxy instance implements
The returned Proxy instance behaves like any other class that implements the supplied interfaces. The statement, proxy instanceof MyInterface, returns true and casts to any of the target interfaces. For example,
MyInterface obj = (MyInterface) proxy
will also succeed.

From the code perspective, the proxy instance is no different from a normal class. Provided the actual creation of the proxy is encapsulated (e.g., inside a factory or ServiceLocator), the proxy is totally transparent. Behavior can be inserted dynamically without changing the way your classes are wired or how your code interacts. This transparency enables you to add common code easily and quickly without affecting class collaborations or having to add (or test) your extra code explicitly for every class.

At the heart of the Proxy mechanism is the InvocationHandler interface. You must supply an InvocationHandler instance when you create a proxy instance. The InvocationHandler is responsible for intercepting and dispatching all method calls made on the proxy. It contains one method: invoke(Object proxy, Method method, Object[] args). The first argument is the proxy instance that has been invoked, the second argument is the target method, and the third argument (args) are the runtime parameters that the caller supplies. You must add any additional behavior inside the invoke() method, as this will get executed whenever a method is executed on the proxy.

Take a common cross cutting concern, logging, as an example. Create a simple InvocationHandler class that logs method entries and exits using System.out.println. Your class must implement the InvocationHandler interface and provide an implementation of the invoke() method. Pass the real class inas a parameter on the constructor, as follows:

public class LoggingHandler implements InvocationHandler {
    protected Object delegate;

    public LoggingHandler(Object delegate) { 
         this.delegate = delegate; 
    }

    public Object invoke(Object proxy,Method method,
                   Object[] args) throws Throwable {
        try {
            System.out.println("Calling method "+ method+ " at "
                + System.currentTimeMillis());
            Object result = method.invoke(delegate, args);
            return result;
         } catch (InvocationTargetException e) {
             throw e.getTargetException();
         } finally {
             System.out.println("Called method("+ method+ " at "
                + System.currentTimeMillis());
         }
      }
}

Monday 15 January 2007

Proxy Pattern & Dynamic Proxies

B) Dynamic Proxies

Using Java Reflection you create dynamic implementations of interfaces at runtime. You do so using the class java.lang.reflect.Proxy.The name of this class is why I refer to these dynamic interface implementations as dynamic proxies. Dynamic proxies can be used for many different purposes, e.g.database connection and transaction management,dynamic mock objects for unit testing, and other AOP-like method intercepting purposes. Here is a list of topics covered in this post on dynamic proxies:

  1. Creating Proxies
  2. InvocationHandler's
  3. Known Use Cases

B.1)Creating Proxies
You create dynamic proxies using the "Proxy.newProxyInstance()" method. The newProxyInstance() methods takes 3 parameters:

  1. The ClassLoader that is to "load" the dynamic proxy class.
  2. An array of interfaces to implement.
  3. An InvocationHandler to forward all methods calls on the proxy to.

Here is an example:

InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface)
Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[]{ MyInterface.class },
handler);

After running this code the proxy variable contains a dynamic implementation of the MyInterface interface.All calls to the proxy will be forwarded to the handler implementation of the general InvocationHandler interface.InvocationHandler's are covered in the next section.

B.2)InvocationHandler's 

As mentioned earlier you must pass an InvocationHandler implementation to the Proxy.newProxyIn stance() method. All method calls to the dynamic proxy are forwarded to this InvocationHandler implementation.Here is how the InvocationHandler interface looks:


public interface InvocationHandler{
Object invoke(Object proxy,
Method method, Object[] args) throws Throwable;
}

Example implementation

public class MyInvocationHandler
implements InvocationHandler{
public Object invoke(Object proxy,
Method method, Object[] args) throws Throwable {
//do something "dynamic"
}
}

The proxy parameter passed to the invoke() method is the dynamic proxy object implementing the interface.Most often you don't need this object.The Method object passed into the invoke() method represents the method called on the interface the dynamic proxy implements.From the Method object you can obtain the method name, parameter types, return type, etc.See the text on 'Methods' for more information.The Object[] args array contains the parameter values passed to the proxy when the method in the interface implemented was called.

Note:
Primitives (int, long etc) in the implemented interface arewrapped in their object counterpars (Integer, Long etc.).

B.3)Known Use Cases
Dynamic proxies are known to be used for at least the following purposes:

  1. Database Connection and Transaction Management
  2. Dynamic Mock Objects for Unit Testing
  3. Adaptation of DI Container to Custom Factory Interfaces
  4. AOP-like Method Interception

B.3.1)Database Connection and Transaction Management
The Spring framework has a transaction proxy that can start and commit / rollback a transaction for you.This use case will be explained in more detail in the next text in this Java Reflection series, so I'll only describe it briefly. The call sequence becomes something along this:
web controller --> proxy.execute(...);
proxy --> connection.setAutoCommit(false);
proxy --> realAction.execute();
real Action does database work
proxy --> connection.commit();

B.3.2)Dynamic Mock Objects for Unit Testing
The Butterfly Testing Tools makes use of dynamic proxies to implement dynamic stubs,mocks and proxies for unit testing. When testing a class A that uses another class B (interface really), you can pass a mock implementation of B into A instead of a real B. All method calls on B are now recorded, and you can set what return values the mock B is to return. Furthermore Butterfly Testing Tools allow you to wrap a real B in a mock B,so that all method calls on the mock are recorded, and then forwarded to the real B. This makes it possible to check what methods were called on a real functioning B. For instance,if testing a DAO you can wrap the database connection in a mock. The DAO will not see the difference,and the DAO can read/write data to the database as usual since the mock forwards all calls to the database. But now you can check via the mock if the DAO uses theconnection properly, for instance if the connection.close() is called (or NOT called), if you expected that.This is normally not possible to determine from the return value of a DAO.

B.3.3)Adaptation of DI Container to Custom Factory Interfaces
The dependency injection container Butterfly Container has a powerful feature that allows you to inject thewhole container into beans produced by it. But, since you don't want a dependency on the container interface, the container is capable of adapting itself to a custom factory interface of your design. You onlyneed the interface. No implementation. Thus the factory interface and your class could look something like this:

public interface IMyFactory {
Bean bean1();
Person person();
...
}

public class MyAction{
protected IMyFactory myFactory= null;
public MyAction(IMyFactory factory){
this.myFactory = factory;
}
public void execute(){
Bean bean = this.myFactory.bean();
Person person = this.myFactory.person();
}
}

When the MyAction class calls methods on the IMyFactory instance injected into its constructor by the container, the method calls are translated into calls to the IContainer.instance() method, which is the method you use to obtain instances from the container. That way an object can use Butterfly Container asa factory at runtime, rather than only to have dependencies injected into itself at creation time. And this without having any dependencies on any Butterfly Container specific interfaces.

B.3.4)AOP-like Method Interception
The Spring framework makes it possible to intercept method calls to a given bean, provided that beanimplements some interface. The Spring framework wraps the bean in a dynamic proxy. All calls to thebean are then intercepted by the proxy. The proxy can decide to call other methods on other objects eitherbefore, instead of, or after delegating the method call to the beean wrapped.

Friday 12 January 2007

Execution Trace using Dynamic Proxy

  1. Client invokes Method A, which is part of an interface.
  2. The Dynamic Proxy intercepts the call, receives a call to a generic invoke method. This isthe magic sauce.
  3. The dynamic proxy invokes the original method using reflection, along with more logic, e.g.logging the call.
There are two supernatural phenomena here:
  • You have a class which can take any shape - each instance of the class can decide, at runtime, which interfaces it will implement.
  • When the instance receives a call through any of these interfaces, it will actually receive a call to one invoke method with all the relevant details: the method which was invoked and the arguments.
Other than the above, it's all plain Java code which you control.
There are some limitations to dynamic proxies, derived directly from the way they work:
  • The invocations you're tracing must be part of an interface. If not, you'll need to extract the interface. Still, even if you do, it will only work for public methods invoked by outside callers.
  • You should control the instantiation of the target class' instances. It should be intercepted and replaced with your own instances.

The Debug Proxy
Sun provides an example (http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html#examples) of tracing using dynamic proxy. I made some modifications to the code and I'm attaching my own version of a "DebugProxy". The main limitation in the original code is that it proxies only the immediate interfaces implemented by the original class. If the class extends a super-class which implements an interface, this interface will not be "proxied" (is that a word?). I also made some more modifications:

  • Used Apache commons logging to do the actual logging. The logging is done "on behalf" of the original class in trace level only.
  • Logging all the method arguments using toString.
  • Correctly throwing exceptions: will throw the original exception that occurred.
  • Using Java 5 features (Generics, for each loops, etc.).

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DebugProxy implements java.lang.reflect.InvocationHandler {
  private final Loglogger;
  private final Object obj;

  @SuppressWarnings("unchecked")
  public static Object newInstance(final Object obj) {
     final List<Class<?>> interfaces = new ArrayList<Class<?>>();
     Class currentClass = obj.getClass();
     while (currentClass != null) {
       if (currentClass.equals(Object.class)) {
         currentClass = null;
       } else {
         for (final Class currInterface : currentClass.getInterfaces()) {
           interfaces.add(currInterface);
         }
         currentClass = currentClass.getSuperclass();
       }
     }
     final Class<?>[] interfaceArray = new Class<?>[interfaces.size()];
     return Proxy.newProxyInstance(obj.getClass().getClassLoader(), 
               interfaces.toArray(interfaceArray), new DebugProxy(obj));
  }

  private DebugProxy(final Object obj) {
     this.obj = obj; 
     this.logger = LogFactory.getLog(obj.getClass());
  }

  public Object invoke(final Object proxy, final Method m, 
              final Object[] args) throws Throwable {
    Object result;
    try {
      if (logger.isTraceEnabled()) {
         logger.trace("Invoking "+ m.getDeclaringClass().getSimpleName() + "."
            + m.getName() + "(), args: " + argsToString(args));
      }
      result = m.invoke(obj, args);
    } catch (final InvocationTargetException e) {
      e.getCause().printStackTrace();
      throw e.getTargetException();
    } catch (final Exception e) {
      throw new RuntimeException("unexpected invocation exception: "
             + e.getMessage(), e);
    } finally { }
    return result;
  }

  private String argsToString(final Object[] args) {
    if (args == null) { return "none"; } 
    else {
      final StringBuffer sb = new StringBuffer();
      for (int i = 0; i < args.length; i++) {
         sb.append(args[i]);
         if (i < (args.length - 1)) { sb.append(", "); }
      }
      return sb.toString();
    }
  }
}

If you're not using Commons Logging, you may want to change that as well.
Next, change the instantiation on your class. Here's the example:

  • Original code: MyInterface obj = new MyClass(...)
  • New code: MyInterface obj = (MyInterface)DebugProxy.newInstance(new MyClass(...))
That's it. You're all set. Just execute the program and check the results in the log. After the first time, youwill have your proxy in place and the whole process becomes even simpler.

Conclusion
Using a DynamicProxy to trace runtime execution has several advantages:

  • It's very simple to set up. It's laser-targeted at the class which is interesting at the moment,ignoring the rest of the system.
  • You control the code, hence, you have the ultimate control on the way the events are logged. You have all the information and you can log it in any way you see fit. You can even set up a break point inside your debug proxy and intercept all the calls.
  • Not much overhead on the system at runtime.
Of course, there are the limitations:
  • The intercepted calls must be made through an interface.
  • You need to control the instantiation of the original class.