001    /*
002     * (c) 2003-2005, 2009, 2010 ThoughtWorks Ltd
003     * All rights reserved.
004     *
005     * The software in this package is published under the terms of the BSD
006     * style license a copy of which has been included with this distribution in
007     * the LICENSE.txt file.
008     * 
009     * Created on 04-May-2004
010     */
011    package com.thoughtworks.proxy.toys.decorate;
012    
013    import java.lang.reflect.InvocationTargetException;
014    import java.lang.reflect.Method;
015    
016    import com.thoughtworks.proxy.Invoker;
017    import com.thoughtworks.proxy.kit.PrivateInvoker;
018    
019    
020    /**
021     * Invoker implementation for the decorating proxy. The implementation may decorate an object or another {@link Invoker}.
022     *
023     * @author Dan North
024     * @author Aslak Hellesøy
025     * @author Jörg Schaible
026     * @since 0.1
027     */
028    public class DecoratingInvoker<T> implements Invoker {
029        private static final long serialVersionUID = 8293471912861497447L;
030        private Invoker decorated;
031        private Decorator<T> decorator;
032    
033        /**
034         * Construct a DecoratingInvoker decorating another Invoker.
035         *
036         * @param decorated the decorated {@link Invoker}.
037         * @param decorator the decorating instance.
038         * @since 1.0
039         */
040        public DecoratingInvoker(final Invoker decorated, final Decorator<T> decorator) {
041            this.decorated = decorated;
042            this.decorator = decorator;
043        }
044    
045        /**
046         * Construct a DecoratingInvoker decorating another object.
047         *
048         * @param delegate  the decorated object.
049         * @param decorator the decorating instance.
050         * @since 1.0
051         */
052        public DecoratingInvoker(final Object delegate, final Decorator<T> decorator) {
053            this(new PrivateInvoker(delegate), decorator);
054        }
055    
056        public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
057            @SuppressWarnings("unchecked")
058            final T typedProxy = (T)proxy;
059            final Object[] decoratedArgs = decorator.beforeMethodStarts(typedProxy, method, args);
060            try {
061                final Object result = decorated.invoke(proxy, method, decoratedArgs);
062                return decorator.decorateResult(typedProxy, method, decoratedArgs, result);
063            } catch (InvocationTargetException e) {
064                throw decorator.decorateTargetException(typedProxy, method, decoratedArgs, e.getTargetException());
065            } catch (Exception e) {
066                throw decorator.decorateInvocationException(typedProxy, method, decoratedArgs, e);
067            }
068        }
069    }