/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.opengamma.sesame.graph.FunctionIdProvider;
import com.opengamma.sesame.graph.FunctionModelNode;
import com.opengamma.sesame.graph.InterfaceNode;
import com.opengamma.sesame.graph.NodeDecorator;
import com.opengamma.sesame.graph.ProxyNode;
/**
* Decorates node in the graph with a proxy.
* <p>
* Subclasses should be stateless and thread safe as there is only one instance shared between all proxied objects.
*/
public abstract class ProxyNodeDecorator extends NodeDecorator implements InvocationHandlerFactory {
@Override
public FunctionModelNode decorateNode(FunctionModelNode node) {
if (!(node instanceof ProxyNode) && !(node instanceof InterfaceNode)) {
return node;
}
Class<?> interfaceType;
Class<?> implementationType;
if (node instanceof InterfaceNode) {
implementationType = ((InterfaceNode) node).getImplementationType();
interfaceType = ((InterfaceNode) node).getType();
} else {
implementationType = ((ProxyNode) node).getImplementationType();
interfaceType = ((ProxyNode) node).getType();
}
if (decorate(interfaceType, implementationType)) {
return createProxyNode(node, interfaceType, implementationType, this);
} else {
return node;
}
}
@Override
public ProxyInvocationHandler create(final Object delegate, ProxyNode node, FunctionIdProvider functionIdProvider) {
return new AbstractProxyInvocationHandler(delegate) {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return ProxyNodeDecorator.this.invoke(proxy, delegate, method, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
};
}
//-------------------------------------------------------------------------
/**
* Indicates whether a node should be wrapped in a proxy.
* <p>
* Note that the implementation type is not necessarily the type of the delegate
* as the delegate could be another proxy, ie. it is the type of the real object.
*
* @param interfaceType the type of the interface being decorated, not null
* @param implementationType the implementation type being decorated, not null
* @return true if decoration should occur
*/
protected abstract boolean decorate(Class<?> interfaceType, Class<?> implementationType);
/**
* Called when a method on the proxy is invoked.
*
* @param proxy the proxy whose method was invoked, not null
* @param delegate the object being proxied, not null
* @param method the method that was invoked, not null
* @param args the method arguments, null if the method takes
* no arguments
* @return the return value of the call
* @throws Throwable if something goes wrong with the underlying call
* TODO param for the concrete type? or the proxy node itself?
*/
protected abstract Object invoke(Object proxy, Object delegate, Method method, Object[] args) throws Throwable;
}