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     */
011    package com.thoughtworks.proxy.toys.decorate;
012    
013    import com.thoughtworks.proxy.ProxyFactory;
014    import com.thoughtworks.proxy.factory.StandardProxyFactory;
015    import 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     */
034    public 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    }