package net.sourceforge.javautil.poly;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.javautil.common.CollectionUtil;
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;
import net.sourceforge.javautil.common.reflection.cache.ClassMethodAbstract.ArgumentMatch;
import net.sourceforge.javautil.interceptor.IInterceptorManager;
import net.sourceforge.javautil.interceptor.type.InterceptorInvocationHandler;
/**
* This will handle invocations for dynamic pojo abilities.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class PojoViewInvocationHandler implements InvocationHandler {
protected final Object target;
protected final IInterceptorManager interceptor;
protected final ClassDescriptor targetDesc;
protected final Map<Method, ClassMethod> cache = new HashMap<Method, ClassMethod>();
protected final Object defaultTarget;
public PojoViewInvocationHandler(IInterceptorManager interceptor, Object target, Object defaultTarget) {
if (Proxy.isProxyClass(target.getClass())) {
InvocationHandler handler = Proxy.getInvocationHandler(target);
if (handler instanceof InterceptorInvocationHandler) {
this.target = InterceptorInvocationHandler.getTarget((InterceptorInvocationHandler)handler);
} else {
this.target = target;
}
} else {
this.target = target;
}
this.interceptor = interceptor;
this.targetDesc = ClassCache.getFor(this.target.getClass().getSuperclass());
this.defaultTarget = defaultTarget;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!cache.containsKey(method)) {
Pojo pojo = method.getAnnotation(Pojo.class);
cache.put(method, pojo == null ? null : targetDesc.getMethod(pojo.value()));
}
ClassMethod cm = cache.get(method);
if (cm != null) {
Object[] modifiedArguments = null;
if (cm.getParameterTypes().length == 0) {
modifiedArguments = CollectionUtil.EMPTY_OBJECT_ARRAY;
} else if (cm.getParameterTypes().length == 1 && cm.getParameterTypes()[0] == method.getDeclaringClass()) {
modifiedArguments = new Object[] { defaultTarget };
} else if (cm.compareArguments(args) == ArgumentMatch.FUNCTIONAL) {
modifiedArguments = args;
} else {
throw new IllegalArgumentException("Cannot call method appropriately");
}
return interceptor.invoke(target, cm.getJavaMember(), modifiedArguments);
} else {
return interceptor.invoke(defaultTarget, method, args);
}
}
}