Package com.thoughtworks.proxy.toys.delegate

Source Code of com.thoughtworks.proxy.toys.delegate.DelegatingInvoker

/*
* Created on 24-May-2004
*
* (c) 2003-2005 ThoughtWorks Ltd
*
* See license.txt for license details
*/
package com.thoughtworks.proxy.toys.delegate;

import com.thoughtworks.proxy.Invoker;
import com.thoughtworks.proxy.ProxyFactory;
import com.thoughtworks.proxy.factory.StandardProxyFactory;
import com.thoughtworks.proxy.kit.ObjectReference;
import com.thoughtworks.proxy.kit.ReflectionUtils;
import com.thoughtworks.proxy.kit.SimpleReference;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
* Invoker that delegates method calls to an object.
* <p>
* This forms the basis of many other proxy toys. The delegation behaviour was factored out of
* <tt>HotSwappingInvoker</tt>.
* </p>
*
* @see com.thoughtworks.proxy.toys.hotswap.HotSwappingInvoker
* @author Aslak Helles&oslash;y
* @author Paul Hammant
* @author Dan North
* @author J&ouml;rg Schaible
* @since 0.1
*/
public class DelegatingInvoker implements Invoker {
    private static final long serialVersionUID = 1L;
    private transient Map methodCache;
    private ProxyFactory proxyFactory;
    private ObjectReference delegateReference;
    private int delegationMode;

    /**
     * Construct a DelegatingInvoker.
     *
     * @param proxyFactory the {@link ProxyFactory} to use
     * @param delegateReference the {@link ObjectReference} of the delegate
     * @param delegationMode one of the delegation modes
     * @throws IllegalArgumentException if the <tt>delegationMode</tt> is not one of the predefined constants of
     *             {@link Delegating}
     * @since 0.2
     */
    public DelegatingInvoker(
            final ProxyFactory proxyFactory, final ObjectReference delegateReference, final int delegationMode) {
        this.proxyFactory = proxyFactory;
        this.delegateReference = delegateReference;
        this.delegationMode = delegationMode;
        if (delegationMode > 1) {
            throw new IllegalArgumentException("Invalid delegation mode");
        }
        this.methodCache = new HashMap();
    }

    /**
     * Construct a DelegatingInvoker.
     *
     * @param proxyFactory the {@link ProxyFactory} to use
     * @param delegateReference the {@link ObjectReference} of the delegate
     * @param staticTyping {@link Delegating#STATIC_TYPING} or {@link Delegating#DYNAMIC_TYPING}
     * @since 0.1
     * @deprecated since 0.2, use {@link DelegatingInvoker#DelegatingInvoker(ProxyFactory, ObjectReference, int)}
     */
    public DelegatingInvoker(
            final ProxyFactory proxyFactory, final ObjectReference delegateReference, final boolean staticTyping) {
        this(proxyFactory, delegateReference, staticTyping ? Delegating.MODE_DIRECT : Delegating.MODE_SIGNATURE);
    }

    /**
     * Construct a DelegatingInvoker with a {@link StandardProxyFactory} and {@link Delegating#MODE_SIGNATURE}.
     *
     * @param delegate the delegated object
     * @since 0.1
     */
    public DelegatingInvoker(final Object delegate) {
        this(new StandardProxyFactory(), new SimpleReference(delegate), Delegating.MODE_SIGNATURE);
    }

    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        final Object result;
        Object delegate = delegate();

        // equals(...) and hashCode()
        if (method.equals(ReflectionUtils.equals)) {
            // Note: equals will normally compare the classes directly, so we have to dereference
            // all delegates and then swap the call (in case of our argument is also a delegation proxy).
            final Object arg = args[0];
            while (delegate != null && proxyFactory.isProxyClass(delegate.getClass())) {
                Invoker invoker = proxyFactory.getInvoker(delegate);
                if (invoker instanceof DelegatingInvoker) {
                    delegate = ((DelegatingInvoker)invoker).delegate();
                }
            }
            if (arg == null) {
                result = delegate == null ? Boolean.TRUE : Boolean.FALSE;
            } else {
                result = arg.equals(delegate) ? Boolean.TRUE : Boolean.FALSE;
            }
        } else if (method.equals(ReflectionUtils.hashCode)) {
            // equals and hashCode must be consistent
            result = new Integer(delegate == null ? hashCode() : delegate.hashCode());

            // null delegate
        } else if (delegate == null) {
            result = null;

            // regular method call
        } else {
            Method methodToCall = (Method)methodCache.get(method);
            if (methodToCall == null) {
                methodToCall = getMethodToInvoke(method, args);
                methodCache.put(method, methodToCall);
            }
            result = invokeOnDelegate(methodToCall, args);
        }
        return result;
    }

    /**
     * Retrieve the delegated object in derived classes.
     *
     * @return the delegated object
     * @since 0.1
     */
    protected Object delegate() {
        return delegateReference.get();
    }

    /**
     * Lookup a matching method. The lookup will only be done once for every method called on the proxy.
     *
     * @param method the invoked method on the proxy
     * @param args the arguments for the invocation
     * @return the matching method
     * @throws DelegationException if no matching method can be found
     * @since 0.2
     */
    protected Method getMethodToInvoke(final Method method, final Object[] args) {
        if (delegationMode == Delegating.MODE_DIRECT) {
            return method;
        } else {
            final String methodName = method.getName();
            try {
                return delegate().getClass().getMethod(methodName, method.getParameterTypes());
            } catch (Exception e) {
                throw new DelegationException("Unable to find method " + methodName, e, delegate());
            }
        }
    }

    /**
     * Invoke the given method on the delegate.
     *
     * @param method the method to invoke
     * @param args the arguments for the invocation
     * @return the method's result
     * @throws InvocationTargetException if the invoked method throws any exception
     * @since 0.1
     */
    protected Object invokeOnDelegate(final Method method, final Object[] args) throws InvocationTargetException {
        final Object delegate = delegate();
        try {
            return method.invoke(delegate, args);
        } catch (InvocationTargetException e) {
            throw e;
        } catch (Exception e) {
            throw new DelegationException("Problem invoking " + method, e, delegate);
        }
    }

    /**
     * Retrieve the {@link ObjectReference} of the delegate.
     *
     * @return the reference of hte delegate
     * @since 0.2
     */
    protected ObjectReference getDelegateReference() {
        return this.delegateReference;
    }

    /**
     * Retrieve the {@link ProxyFactory} to use.
     *
     * @return the ProxyFactory
     * @since 0.2
     */
    protected ProxyFactory getProxyFactory() {
        return this.proxyFactory;
    }

    /**
     * Compares a DelegatingInvoker with another one for equality. Two DelegatingInvoker are equal, if they have both
     * the same <tt>delegation mode</tt> and their delegees are equal.
     *
     * @see java.lang.Object#equals(java.lang.Object)
     * @since 0.2
     */
    public boolean equals(final Object obj) {
        if (obj instanceof DelegatingInvoker) {
            final DelegatingInvoker invoker = (DelegatingInvoker)obj;
            return invoker.delegationMode == delegationMode && delegate().equals(invoker.delegate());
        }
        return false;
    }

    public int hashCode() {
        final Object delegate = delegate();
        int hashCode = delegate == null ? System.identityHashCode(this) : delegate.hashCode();
        switch (delegationMode) {
        case Delegating.MODE_DIRECT:
            hashCode = ~hashCode;
            break;
        case Delegating.MODE_SIGNATURE:
            hashCode = -hashCode;
            break;
        // case Delegating.MODE_MATCHING:
        // hashCode = -(~hashCode);
        // break;
        }
        return hashCode;
    }

    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        methodCache = new HashMap();
    }
}
TOP

Related Classes of com.thoughtworks.proxy.toys.delegate.DelegatingInvoker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.