zcommon/src/main/java/org/zkoss/lang/reflect/FacadeInvoker.java

Summary

Maintainability
A
0 mins
Test Coverage
/* FacadeInvoker.java


    Purpose: 
    Description: 
    History:
    2001/11/27 20:06:18, Create, Tom M. Yeh.

Copyright (C) 2001 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.1 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.lang.reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;

import org.zkoss.lang.Classes;

/**
 * The facade invocation handler. Like the facade pattern, this invocation
 * handler is used to facade an object with a set of interfaces.
 *
 * <p>This Invocation handler assumes the object being facaded
 * (a.k.a, the target) has all methods of these interfaces, but it might not
 * implement all of these interfaces directly.
 *
 * <p>It happens when you need to provide interfaces to classes that
 * come from third parties.
 *
 * <p>Example:<br>
 *<pre><code>class A {
 *  public void f() {...}
 *}
 *interface I {
 *  public void f();
 *}</code>
 *Then, you could do:
 *<code>I i = (I)FacadeInvoker.newInstance(new A(), new Class[] {I});</code></pre>
 *
 * @author tomyeh
 */
public class FacadeInvoker implements InvocationHandler {
    /** The target that really implements the interfaces. */
    private Object _target;

    /**
     * Creates an object that implements the giving interfaces by
     * wrapping a giving object, target.
     *
     * <p>The target must have all methods in all given interfaces,
     * but might not implement all these interfaces.
     */
    public static final Object newInstance
    (Object target, Class[] interfaces, ClassLoader clsLoader) {
        return Proxy.newProxyInstance(
            clsLoader, interfaces, new FacadeInvoker(target));
    }
    /**
     * Creates an object that implements the giving interfaces by
     * wrapping a giving object, target.
     * <p>A shortcut: newInstance(
     * target, interfaces, Thread.currentThread().getContextClassLoader()).
     */
    public static final Object newInstance(Object target, Class[] interfaces) {
        ClassLoader cl = Classes.getContextClassLoader(FacadeInvoker.class);
        return newInstance(target, interfaces,
            cl != null ? cl: FacadeInvoker.class.getClassLoader());
    }

    protected FacadeInvoker(Object target) {
        _target = target;
    }

    //-- InvocationInvoker --//
    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
        Class cls = _target.getClass();
        if (!method.getDeclaringClass().isAssignableFrom(cls))
            method = Classes.getMethodInPublic(
                    cls, method.getName(), method.getParameterTypes());

        try {
            return method.invoke(_target, args);
        }catch(InvocationTargetException ex) {
            throw ex.getCause();
        }
    }
}