/* 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);
}
}