/**
*
*/
package poxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import callback.PrimitiveUtil;
/**
* More industrial-level dynamic proxy , which main detach the Invocation handler and the real instance of a proxy class,
* which can store many proxy handler with them listener, this is very useful.
* Mean while, it also can work in multi thread env, so you can use it with Thread pool and Scheduler!
*
* @author daniel
*
*/
public class IndustrialDynamicProxy {
/*
* container of iface & his InvocationHandler
* Note: work in multithread env
*/
private Map _iface2Handler = new HashMap();
/*
* Generates the 'caller' side of the caller/listener relationship.
*/
public Object generateCaller(Class iFace, CallBackType type) {
CallBackHanlder newHandler;
Object proxy=null;
//check iface
if(!iFace.isInterface()){
throw new IllegalArgumentException("Class [" + iFace.getName() + "] is not an interface");
}
//generate a new handler
newHandler = new CallBackHanlder(type);
//generate the face's proxy
proxy = Proxy.newProxyInstance(iFace.getClassLoader(),
new Class[] { iFace },
newHandler);
//register iface & proxy
synchronized(_iface2Handler){
if(_iface2Handler.containsKey(iFace)){
throw new IllegalArgumentException("Caller already generated " + " for interface [" +
iFace.getName() + "]");
}
_iface2Handler.put(iFace, newHandler);
}
return proxy;
}
/*
* Register a listener for a given interface. If the caller has not
* been registered, then an error will be thrown.
*/
public void registerListener(Class iFace, Object o) {
CallBackHanlder handler;
if(!iFace.isAssignableFrom(o.getClass())){
throw new IllegalArgumentException("Object [" + o + "] does not " +
"implement [" + iFace.getName() +
"]");
}
synchronized (_iface2Handler) {
handler = (CallBackHanlder) _iface2Handler.get(iFace);
}
if(handler == null){
throw new IllegalArgumentException("No callback for interface [" +
iFace.getName() + "] exists");
}
handler.addListener(o);
}
/**
* @param args
*/
public static void main(String[] args) {
//Base testhandler
IndustrialDynamicProxy x=new IndustrialDynamicProxy();
//register iface, get the proxy
MyInterface caller = (MyInterface)x.generateCaller(MyInterface.class, CallBackType.RETURN_LAST);
//register the listener(real instance)
x.registerListener(MyInterface.class, new MyInterface(){
@Override
public int addTwo(int a, int b) {
System.out.println("Target method called");
return a + b;
}
});
//call the listener
int result=caller.addTwo(2, 4);
//take a look
System.out.println("addTwo(2,4):"+result);
}
/**
* An inner class to operate listeners in private
*/
static class CallBackHanlder implements InvocationHandler{
/*
* container of listeners (real instance)
* Note: work in multithread env
*/
private Set _listeners = new HashSet();
//tool of get right Type
private CallBackType _type = null;
CallBackHanlder(CallBackType type){
this._type=type;
}
private void addListener(Object o){
synchronized(_listeners){
_listeners.add(o);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Set listeners;
synchronized (_listeners) {
listeners = new HashSet(_listeners);
}
return _type.callListeners(method, args, listeners);
}
}
}
//Interface
interface MyInterface {
int addTwo(int a, int b);
}
/*
* CallBackType,
*/
abstract class CallBackType {
public static final CallBackType RETURN_LAST = new CallBackType() {
public Object callListeners(Method meth, Object[] methArgs,Set listeners)throws Throwable
{
Object last = null;
for (Iterator i=listeners.iterator(); i.hasNext(); ) {
Object listener = (Object)i.next();
try {
last = meth.invoke(listener, methArgs);
} catch(InvocationTargetException e) {
throw e.getTargetException();
}
}
if (last == null) {
// Nobody listening ...
return PrimitiveUtil.getBasicValue(meth.getReturnType());
}
return last;
}
};
public abstract Object callListeners(Method meth, Object[] methArgs,
Set listeners)
throws Throwable;
}