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øy
028 * @author Jö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 }