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 */
011package com.thoughtworks.proxy.toys.decorate;
012
013import java.lang.reflect.InvocationTargetException;
014import java.lang.reflect.Method;
015
016import com.thoughtworks.proxy.Invoker;
017import 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 */
028public 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}