/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.graph; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.List; import java.util.Objects; import com.opengamma.sesame.engine.ComponentMap; import com.opengamma.sesame.proxy.InvocationHandlerFactory; import com.opengamma.util.ArgumentChecker; /** * A node in the function model that inserts a dynamic proxy. * <p> * Dynamic proxies are used to add additional behaviour to the node tree. */ public class ProxyNode extends DependentNode { /** * The implementation type. */ private final Class<?> _implementationType; /** * The node that is wrapped by the proxy. */ private final FunctionModelNode _delegateNode; /** * The proxy invocation factory. */ // TODO should this be a Class<?> and the instance can be retrieved from the ComponentMap? that could be serialized private final InvocationHandlerFactory _handlerFactory; /** * Creates an instance. * * @param delegateNode the delegate node, not null * @param interfaceType the expected type of the object created by this node, not null * @param implementationType the implementation type to create, may be null * @param handlerFactory the proxy invocation factory, not null */ ProxyNode(FunctionModelNode delegateNode, Class<?> interfaceType, Class<?> implementationType, InvocationHandlerFactory handlerFactory) { super(interfaceType, delegateNode.getParameter(), delegateNode); _implementationType = ArgumentChecker.notNull(implementationType, "implementationType"); _delegateNode = ArgumentChecker.notNull(delegateNode, "delegate"); _handlerFactory = ArgumentChecker.notNull(handlerFactory, "handlerFactory"); } //------------------------------------------------------------------------- /** * Gets the delegate node. * * @return the delegate node, not null */ public FunctionModelNode getDelegate() { return _delegateNode; } /** * Gets the implementation type. * * @return the implementation type, not null */ public Class<?> getImplementationType() { return _implementationType; } /** * Gets the underlying concrete node. * <p> * This is the node that the proxy decorates. * * @return the delegate node, not null */ @Override public FunctionModelNode getConcreteNode() { return _delegateNode.getConcreteNode(); } //------------------------------------------------------------------------- @Override protected Object doCreate(ComponentMap componentMap, List<Object> dependencies, FunctionIdProvider idProvider) { Object delegate = dependencies.get(0); InvocationHandler invocationHandler = _handlerFactory.create(delegate, this, idProvider); return Proxy.newProxyInstance(getType().getClassLoader(), new Class<?>[]{getType()}, invocationHandler); } @Override protected String prettyPrintLine() { return "proxy " + getType().getSimpleName() + "(" + _handlerFactory.getClass().getSimpleName() + ")"; } //------------------------------------------------------------------------- @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } if (!super.equals(obj)) { return false; } final ProxyNode other = (ProxyNode) obj; return Objects.equals(this._implementationType, other._implementationType) && Objects.equals(this._delegateNode, other._delegateNode) && Objects.equals(this._handlerFactory, other._handlerFactory); } @Override public int hashCode() { return 31 * super.hashCode() + Objects.hash(_implementationType, _delegateNode, _handlerFactory); } }