ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Dynamic Delegation and Its Applications Dynamic Delegation and Its Applications

by Lu Jian
11/17/2004

The Proxy pattern is an important and widely used design pattern in object-oriented programming. Do you ever use Proxy in Java since its introduction in JDK 1.3? A dynamic proxy class is a class that implements a list of interfaces specified at runtime. An implementation for the proxy's behavior can be provided at runtime through an InvocationHandler. So Proxy is an important class in Java's reflection package, and is widely used in many Java applications.

One limitation of Proxy is that it can only accept interfaces. In some circumstances, you need to apply the Proxy pattern not only to interfaces, but also to abstract classes, and even concrete classes.

This article introduces Dynamic Delegation, which can create delegation for both interfaces and classes at runtime.

Proxy Overview

In JDK 1.3, the Proxy class was added to java.lang.reflect. It can create a concrete class that implements all of the specified interfaces at runtime. The dynamically generated class redirects all of the method calls defined in the interfaces to an InvocationHandler.

Given two interfaces, Idel1 and Idel2, Proxy will create a IdelProxy class as the proxy of these two interfaces (I use IdelProxy as the generated proxy class name for convenience). Figure 1 shows this arrangement.

Class Diagram of IdelProxy
Figure 1. Class diagram of IdelProxy

Below is the related code snippet.


    Class clazz = Proxy.getProxyClass(
         Idel1.class.getClassLoader(), 
         new Class[] { Idel1.class, Idel2.class });

Delegation Versus Proxy

Proxy only works for interfaces. What if we need it to work for both classes and interfaces? The Dunamis project on java.net introduces Delegation as an alternative to Proxy. Delegation uses a different approach than Proxy.

Given a class named TestBean, the delegation class TestBeanDelegation's class diagram is shown in Figure 2.

Class Diagram of TestBeanDelegation
Figure 2. Class diagram of TestBeanDelegation (click for full-size image)

TestBeanDelegation implements the Delegation interface and extends the TestBean class. It also contains references to TestBean and DelegationInvocationHandler. All of the method calls on TestBeanDelegation will be delegated to them.

Take getName() as an example. The chart in Figure 3 illustrates the sequence of the method call.

Sequence Chart of TestBeanDelegation.getName()
Figure 3. Sequence chart of TestBeanDelegation.getName() (click for full-size image)

The related pseudocode is:


//The delegation class is a sub-class of the class to be delegated
public class TestBeanDelegation extends TestBean
        implements Delegation {
    //The object to be delegated
    TestBean bean;
    //The invocation handler
    DelegationInvocationHandler handler;
    ...
    static Method m0 = null;
    ...

    static {
        ...
        try {
            m0 = TestBean.class.getMethod("getName",
                                 new Class[] {});
        } catch (Exception exception) {
        }
        ...
    }

    public TestBeanDelegation(Object bean) {
        this.bean = (TestBean)bean;
    }

    public String getName() {
        boolean goon = true;
        String ret = null;
        Throwable t = null;
        try {
            goon = handler.invokeBefore(bean,
                        m0, new Object[] {});
            if (goon)
                try {
                    ret = bean.getName();
                } catch (Throwable throwable) {
                    t = throwable;
                }
            if (t != null)
                ret = handler.invokeAfterException(bean,
                            m0, new Object[] {}, t);
            else
                ret = handler.invokeAfter(bean,
                            m0, new Object[] { name }, null);
            return ret;
        } catch (RuntimeException e) {
            throw e;
        } catch (Error e) {
            throw e;
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

An Introduction to Dynamic Delegation

Dynamic Delegation is based on the Jakarta Byte-Code Engineering Library (BCEL). It can analyze the existing class and generate a delegation class in byte code for an interface, abstract class, or even a concrete class at runtime.

Related Reading

Java In a Nutshell
By David Flanagan

The interface/class to be delegated should meet the following conditions:

  • Dynamic Delegation can accept one class at most, but can accept multiple interfaces.

    This limitation is based on Java's single inheritance model. One Java class can have at most one superclass. Since the generated delegation class takes the given class as its superclass, it is illegal to specify more than one class. If no class specified, the default superclass is Object.

  • The input class should have a default constructor with a public or protected modifier.

    The delegation class will call the superclass' default constructor in its own constructor.

  • The input class cannot be final, and should be visible to the caller.

    The proxy class generated by Proxy is final. It will not be accepted by Dynamic Delegation.

  • Dynamic Delegation cannot accept any class that implements the Delegation interface.

    Since it is already a delegation class, why would you need to delegate it again?

The generated delegation class has the following characteristics:

  • It is generated on the fly and has no class file.
  • It implements all of the given interfaces and extends the given class.
  • It also implements the Delegation interface.
  • It has a constructor that accepts an Object instance as a parameter.

DelegationGenerator is the main class of Dynamic Delegation. A client can use it to generate a delegation class/object for a specific class/interface/object. DelegationInvocationHandler is an interface defining all of the delegation behaviors and is expected to be implemented by the client's developer. The delegation object can use the _getInvocationHandler() and _setInvocationHandler() methods defined in Delegation to access the DelegationInvocationHandler instance in the delegation object.

Pages: 1, 2, 3

Next Pagearrow