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 03-May-2004
010 */
011package com.thoughtworks.proxy.toys.decorate;
012
013import com.thoughtworks.proxy.ProxyFactory;
014import com.thoughtworks.proxy.factory.StandardProxyFactory;
015import com.thoughtworks.proxy.kit.ReflectionUtils;
016
017
018/**
019 * Toy factory to create proxies decorating an object in an AOP style.
020 * <p>
021 * An InvocationDecorator is used for the additional functionality. It is called before the original method is called,
022 * after the original method was called, after the original method has thrown an exception or when an exception occurs,
023 * calling the method of the decorated object.
024 * </p>
025 *
026 * @author Dan North
027 * @author Aslak Helles&oslash;y
028 * @author J&ouml;rg Schaible
029 * @author Jian Li
030 * @author Paul Hammant
031 * @see com.thoughtworks.proxy.toys.decorate
032 * @since 0.1
033 */
034public class Decorating<U, T> {
035
036    private U delegate;
037    private Class<?>[] types;
038    private Decorator<T> decorator;
039    
040    private Decorating(final U delegate, final Class<T>primaryType, final Class<?>... types) {
041        this.delegate = delegate;
042        this.types = ReflectionUtils.makeTypesArray(primaryType, types);
043    }
044
045    /**
046     * Creates a factory for proxy instances that allow decoration.
047     *
048     * @return a factory that will proxy instances of the supplied type.
049     * @since 1.0
050     */
051    public static <T> DecoratingWith<T> proxy(final Class<T> type) {
052        return new DecoratingWith<T>(new Decorating<T, T>((T)null, type));
053    }
054
055    /**
056     * Creates a factory for proxy instances that allow decoration.
057     *
058     * @param primaryType the primary type implemented by the proxy
059     * @param types other types that are implemented by the proxy
060     * @return a factory that will proxy instances of the supplied type.
061     * @since 1.0
062     */
063    public static <T> DecoratingWith<T> proxy(final Class<T> primaryType, final Class<?> ... types) {
064        return new DecoratingWith<T>(new Decorating<T, T>((T)null, primaryType, types));
065    }
066
067    /**
068     * Creates a factory for proxy instances that allow decoration.
069     * 
070     * @param delegate  the delegate
071     * @return a factory that will proxy instances of the supplied type.
072     * @since 1.0
073     */
074        public static <U> DecoratingVisitor<U, U> proxy(final U delegate) {
075            @SuppressWarnings("unchecked")
076        final Class<U> type = (Class<U>)delegate.getClass();
077                return new DecoratingVisitor<U, U>(new Decorating<U, U>(delegate, type));
078    }
079
080    /**
081     * Creates a factory for proxy instances that allow decoration.
082     * 
083     * @param delegate  the delegate
084     * @param type the type of the proxy when it is finally created.
085     * @return a factory that will proxy instances of the supplied type.
086     * @since 1.0
087     */
088    public static <U, T> DecoratingVisitor<U, T> proxy(final U delegate, final Class<T> type) {
089        return new DecoratingVisitor<U, T>(new Decorating<U, T>(delegate, type));
090    }
091
092    /**
093     * Creates a factory for proxy instances that allow decoration.
094     *
095     * @param delegate  the delegate
096     * @param primaryType the primary type implemented by the proxy
097     * @param types other types that are implemented by the proxy
098     * @return a factory that will proxy instances of the supplied type.
099     * @since 1.0
100     */
101    public static <U, T> DecoratingVisitor<U, T> proxy(final U delegate, final Class<T> primaryType, final Class<?> ... types) {
102        return new DecoratingVisitor<U, T>(new Decorating<U, T>(delegate, primaryType, types));
103    }
104    
105    public static class DecoratingWith<T> {
106        private Decorating<T, T> decorating;
107
108        private DecoratingWith(Decorating<T, T> decorating) {
109            this.decorating = decorating;
110        }
111
112        /**
113         * specify the delegate
114         *
115         * @param delegate  the delegate
116         * @return the factory that will proxy instances of the supplied type.
117         * @since 1.0
118         */
119        public DecoratingVisitor<T, T> with(T delegate) {
120            decorating.delegate = delegate;
121            return new DecoratingVisitor<T, T>(decorating);
122        }
123    }
124
125    public static class DecoratingVisitor<U, T> {
126        private Decorating<U, T> decorating;
127
128        private DecoratingVisitor(Decorating<U, T> decorating) {
129            this.decorating = decorating;
130        }
131
132        /**
133         * specify the visited decorator
134         *
135         * @param decorator the decorator
136         * @return the factory that will proxy instances of the supplied type.
137         * @since 1.0
138         */
139        public DecoratingBuild<U, T> visiting(Decorator<T> decorator) {
140            decorating.decorator = decorator;
141            return new DecoratingBuild<U, T>(decorating);
142        }
143    }
144
145    public static class DecoratingBuild<U, T> {
146        private Decorating<U, T> decorating;
147
148        private DecoratingBuild(Decorating<U, T> decorating) {
149            this.decorating = decorating;
150        }
151
152        /**
153         * Creating a decorating proxy for an object using the {@link StandardProxyFactory}.
154         *
155         * @return the created proxy implementing the <tt>type</tt>
156         * @since 1.0
157         */
158        public T build() {
159            return build(new StandardProxyFactory());
160        }
161
162        /**
163         * Creating a decorating proxy for an object using a special {@link ProxyFactory}.
164         *
165         * @param proxyFactory the {@link ProxyFactory} to use.
166         * @return the created proxy implementing the <tt>type</tt>
167         * @since 1.0
168         */
169        public T build(final ProxyFactory proxyFactory) {
170            DecoratingInvoker<T> invoker = new DecoratingInvoker<T>(decorating.delegate, decorating.decorator);
171            return proxyFactory.<T>createProxy(invoker, decorating.types);
172        }
173    }
174}