package net.sourceforge.javautil.common.event;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.proxy.CollectionProxyCondition;
import net.sourceforge.javautil.common.proxy.DefaultReturnValue;
import net.sourceforge.javautil.common.proxy.pojo.Pojo;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
/**
* The delegator of events for pojo listeners, thus this supports the {@link Pojo} annotation.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class EventDelegator implements InvocationHandler {
/**
* This assumes the current thread local class loader.
*
* @see #createProxy(ClassLoader, Class, Object)
*/
public static <T extends java.util.EventListener> T createProxy (Class<T> listenerType, Object pojoTarget) {
return createProxy(Thread.currentThread().getContextClassLoader(), listenerType, pojoTarget);
}
/**
* @param <T> The type of event listener
* @param loader The loader to use for creating the proxy
* @param listenerType The class of the listener type
* @param pojoTarget The target for event notifications
* @return The proxy for dealing with the pojo in a typed fashion
*/
public static <T extends java.util.EventListener> T createProxy (ClassLoader loader, Class<T> listenerType, Object pojoTarget) {
return (T) Proxy.newProxyInstance(loader, new Class[] { listenerType }, new EventDelegator(listenerType, pojoTarget));
}
protected final Object target;
protected final ClassDescriptor<?> targetType;
protected final ClassDescriptor<? extends java.util.EventListener> listenerType;
protected final ClassMethod allEventHandler;
protected EventDelegator(Class<? extends java.util.EventListener> listenerType, Object target) {
this.target = target;
this.targetType = ClassCache.getFor( target.getClass() );
this.listenerType = ClassCache.getFor( listenerType );
this.allEventHandler = targetType.getMethod(EventHandler.class);
}
/**
* @return The target this proxy is delegating to.
*/
public Object getTarget() { return target; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) return method.invoke(target, args);
Pojo pojo = method.getAnnotation(Pojo.class);
ClassMethod cm = null;
Object returnValue = null;
if (pojo != null) {
cm = targetType.getMethod(pojo.value());
} else {
cm = targetType.findMethod(method.getName(), args);
}
if (cm != null) returnValue = cm.invoke(target, args);
else if (this.allEventHandler != null && method.getAnnotation(CollectionProxyCondition.class) == null) {
returnValue = this.allEventHandler.invoke(target, args);
}
if (method.getReturnType() == void.class) return null;
if (returnValue != null && method.getReturnType().isInstance(returnValue))
return returnValue;
DefaultReturnValue drv = method.getAnnotation(DefaultReturnValue.class);
if (drv != null) {
return ReflectionUtil.coerceString(method.getReturnType(), drv.value());
} else if (method.getReturnType().isPrimitive()) {
return ReflectionUtil.getPrimitiveDefault(method.getReturnType());
}
return null;
}
}