Dimitri Missoh
enthusiastic technologist and problem solver

July 19th, 2009

Behind the scenes - Using dynamic proxies

Most of the time, a developer has to integrate a new functionality into an existing system. The challenge is not only to develop the piece of code that solves the problem but also to integrate the result of your implementation without breaking the running system and reuse most of the modules that already exist. In this article I would like to give you an example of how dynamic proxies can be used to achieve an integrating task on the low level (i.e. on the code level). First let’s have a look on some theoretical aspects.

Dynamic Proxy is a well known design pattern often used to protect or control the access to an object instance. A proxy object implements the same interface (or set of interfaces) of the object you want to control the access of. Instead of using the object itself, the proxy is passed to the client code.

All method call invocations are delegated to the proxy instance. The proxy instance makes most of the time either a pre-processing, a post-processing, handle the method invocation itself or just delegate the execution to the real object. Attentive readers will notice that this sounds like the decorator pattern. But there is a slightly difference between the decorator and the proxy pattern. The proxy pattern do not encapsulates the target object, it only acts as a delegate. For more details please have a look at the excellent article on JavaWorld.

Since Java 1.3, implementing dynamic proxies has been largely simplified by the introduction of the Dynamic Proxy API. See the following API description for more details. As mentioned above, to use dynamic proxies, you have to implement the same interface as your target object. But what if the target object do not implement any interface? That is exactly where the cglib library comes to the rescue. It is a code generation library used to extend Java class and implements interfaces at runtime. A prominent framework that makes an extensive use of it is Spring.

I would like to illustrate the use of dynamic proxies and especially the use of the cglib library through a very basic example. Suppose your company spent a lot of money to acquire a printing framework you now want to embed in your brand new product. Your product has a client-server based architecture where data are stored on a database accessible through the server.

With the client, you can browse the content of the repository. Your customers now want to be able to print out the content of a container. The printing frameworks can only handle some kind of files types. Furthermore let say that this framework is continually being enhanced. Every new release support more files types. The only fact we know about the framework is that it uses file extensions to determine which file types can be proceeded. The code the printing frameworks uses (which in fact is not modifiable) look like in the snippet below:

package com.dmissoh.proxies;
 
import java.io.File;
import java.util.Collection;
import java.util.Iterator;
 
/**
 * This is the class responsible for printing in a third party library.
 * In the real world, this class cannot be edited.
 
 *
 * The logic use in this class is simple. The file name is used to decide if it should be printed or not.
 
 *
 * Only files having the extension <strong>pdf</strong> will be proceeded. If this condition is fulfilled,
 * the <code>File.getAbsolutePath()</code> method is called to retrieve the full path, and print the file out.
 
 *
 * P.S.: A file that is going to be printed should also be accessible on the disc.
 *
 * @author Dimitri Missoh
 */
public class ThirdPartyPrinter {
 
	public void printOutFiles(Collection files) {
		if (files != null) {
			for (Iterator iterator = files.iterator(); iterator.hasNext();) {
				File file = iterator.next();
				String fileName = file.getName();
				if (fileName.indexOf(".pdf") &gt; -1) {
					String path = file.getAbsolutePath();
					System.err.println("Print the file: " + path);
				}
			}
		}
	}
}

Since files are physically located on the back-end we don’t want to download them all before sending them to the printing framework. This do not make sense because we know that the printing framework can handle only a predefined set of file types. In addition we want to be careful with the available bandwidth.

In the current version we know that the printing framework can only handle PDF files.

The quick and dirty approach will be:

  • first retrieve the list of files name available in the container
  • filter out only those having the extension PDF
  • send another server request to download only the PDF files
  • finally send the downloaded files for printing.

Well, this may be an acceptable solution until we get the next release of the printing framework which now handles more file types. We will than have to change the client code again to filter out not the new set of files the printing framework can now handle.
The printing framework calls two methods:

  • File.getName() to check if the file can be printed and,
  • File.getAbsolutePath() just before it prints the file.

Since the printing framework uses the java.io.File, the idea is to use cglib to create a proxy for the File object. The job of this proxy will be to download the file every time the File.getAbsolutePath() is called (since this method is called only for those files).

P.S.: Why can’t we just use the Dynamic Proxy API Java provides out of the box? The response is trivial, the File object do not implements any interfaces.

So let see how the new implementation could look like:

The PrintClient simulates the client code that calls the printing framework. It instantiates the file proxies (LazyFileDownloaderProxy) and request the printing job.

package com.dmissoh.proxies;
 
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
 
import net.sf.cglib.proxy.Enhancer;
 
/**
 * This class represents the client code, the one that calls
 * the third party library's API to print a given collection of files.
 *
 * Instead of calling the third party's APi with a list of <code>File</code>,
 * a collection of <code>LazyFileDownloaderProxy</code> are passed as arguments.
 * This proxies intercept method calls and allow us to make some preprocessing.
 *
 * @author Dimitri Missoh
 *
 */
public class PrintClient {
 
	/**
	 * The main method that calls methods in the third party library.
	 * @param args
	 */
	public static void main(String[] args) {
		Collection files = new ArrayList();
 
		File fileOne 	= (File) newInstance(File.class, "/home/docs/paper.txt");
		File fileTwo 	= (File) newInstance(File.class, "/home/docs/publication.pdf");
		File fileThree 	= (File) newInstance(File.class, "/home/docs/logo.gif");
		File fileFour 	= (File) newInstance(File.class, "/home/docs/book.pdf");
 
		files.add(fileOne);
		files.add(fileTwo);
		files.add(fileThree);
		files.add(fileFour);
 
		// Print all pdf-Files by calling the API in the third party library
		ThirdPartyPrinter fileChecker = new ThirdPartyPrinter();
		fileChecker.printOutFiles(files);
	}
 
	/**
	 * Returns an proxy instance that encapsulate a <code>File</code> object.
	 * @param clazz the <code>Class</code> to create the proxy instance for.
	 * @param argument the arguments to passed to the constructor.
	 * @return a proxy instance of the class passed as argument.
	 */
	@SuppressWarnings("unchecked")
	public static Object newInstance(Class clazz, Object argument) {
		try {
			Enhancer e = new Enhancer();
			e.setSuperclass(clazz);
			e.setCallback(new LazyFileDownloaderProxy());
			Class[] argumentTypes = new Class[]{String.class};
			Object[] arguments = new Object[]{argument};
			return e.create(argumentTypes, arguments);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new Error(e.getMessage());
		}
	}
}

The LazyFileDownloaderProxy is the heart of our example. Method invocations done on the File object (through it proxy) are intercepted. If the called method is getAbsolutePath, the file will be first downloaded and the invocation is than delegated to the File object itself.

package com.dmissoh.proxies;
 
import java.io.File;
import java.lang.reflect.Method;
 
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
/**
 * This class is used as proxy for a <code>File</code> object.
 * The aim of this class is to intercept method calls done on the File object
 * through this proxy.
 *
 * This proxy class dowload the file just before the File.getAbsolutePath() is called,
 * and than delegate the processing to the corresponding method of the <code>File</code> object.
 *
 *
 * @author Dimitri Missoh
 *
 */
public class LazyFileDownloaderProxy implements MethodInterceptor {
 
	/*
	 * (non-Javadoc)
	 *
	 * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,
	 * java.lang.reflect.Method, java.lang.Object[],
	 * net.sf.cglib.proxy.MethodProxy)
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		Object returnValueFromSuper = null;
 
		String methodName = method.getName();
 
		File file = null;
 
		if ((obj instanceof File)) {
			file = (File) obj;
		}
 
		// If the getAbsolutePath() method is called, download the file.
		if ("getAbsolutePath".equals(methodName)) {
			if (file != null) {
				downloadFile(file);
			}
		}
 
		// Than return the value as if it has been called on the corresponding method of the File class.
		try {
			returnValueFromSuper = proxy.invokeSuper(obj, args);
		} catch (Throwable t) {
			System.out.println("throw " + t);
			System.out.println();
			throw t.fillInStackTrace();
		}
		return returnValueFromSuper;
	}
 
	/**
	 * The dummy method called to download the file. This represent the time or resource
	 * consuming operation.
	 *
	 * @param file the file to download.
	 */
	private void downloadFile(File file) {
		for (int i = 0; i &lt; 3; i++) {
			try {
				Thread.sleep(1000);
				System.out.println("Downloading file '" + file.getName()
						+ "' ..." + (i + 1) + " second(s)");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

P.S.: From the cglib website, I download the library file that contains all dependencies (cglib-nodep-2.2.jar).

The screenshot below shows the project structure:

The project structure

The project structure

The project structure

Source files to this article can be either downloaded from this Blog or are available through the SVN repository https://homeworks.googlecode.com/svn/trunk/.

Download Projects Files.

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word