/* FusionInvoker.java Purpose: Description: History: Tue Nov 4 14:45:31 2008, Created by Flyworld Copyright (C) 2008 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.InvocationHandler; import java.lang.reflect.Proxy; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; import org.zkoss.lang.Classes; /** * The fusion invocation handler. It is used to <i>fuse</i> * two or more instance into one object. * It is usefully if you want to have a single object to represent two more * other instances. * * <p>Example: * * <pre><code> * public interface IA { * public void f(); * } * public interface IB { * public void g(); * } * public class A implements IA { * public void f() {...} * } * public class B implements IB { * public void g() {...} * } * </code></pre> * Then, you could fuse them together as follows: * <pre><code> * Object obj = FusionInvoker.newInstance(new Object[] {new A(), new B()}); * </code></pre> * * Thus, the fused proxy object, <code>obj</code>, could be used as if * it implements <code>IA</code> and <code>IB</code>: * * <pre><code> * IA ia = (IA) obj; * ia.f(); * IB ib = (IB) obj; * ib.g(); * </code></pre> * * @author RyanWu * @since 3.5.2 * */ public class FusionInvoker implements InvocationHandler, java.io.Serializable { private Object[] _targets; /** Use {@link #newInstance(Object[])} instead. */ protected FusionInvoker(Object[] targets) { _targets = targets; } /** Use for only two object, see {@link #newInstance(Object[])}. */ public static Object newInstance(Object target1, Object target2) { return newInstance(new Object[] { target1, target2 }); } /** * Creates an object that contains the all interfaces by wrapping giving * object, targets. * <p> * Usage shortcut: FusionInvoker.newInstance(new Object[] { Object a, Object * b }); * * @param targets * the objects need to wrapped */ public static Object newInstance(Object[] targets) { Set<Class> targetClasses = new HashSet<Class>(); for (int i = 0; i < targets.length; i++) { Class[] allClass = targets[i].getClass().getInterfaces(); for (int j = 0; j < allClass.length; j++) { targetClasses.add(allClass[j]); } } ClassLoader cl = Classes.getContextClassLoader(FusionInvoker.class); return Proxy.newProxyInstance( cl != null ? cl: FusionInvoker.class.getClassLoader(), targetClasses .toArray(new Class[targetClasses.size()]), new FusionInvoker( targets)); } // -- InvocationHandler --// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class cls = method.getDeclaringClass(); for (int i = 0; i < _targets.length; ++i) if (cls.isInstance(_targets[i])) return method.invoke(_targets[i], args); throw new InternalError("Unknown method " + method); } }