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 14-May-2004
010 */
011 package com.thoughtworks.proxy.toys.hotswap;
012
013 import static com.thoughtworks.proxy.toys.delegate.DelegationMode.DIRECT;
014 import static com.thoughtworks.proxy.toys.delegate.DelegationMode.SIGNATURE;
015
016 import com.thoughtworks.proxy.ProxyFactory;
017 import com.thoughtworks.proxy.factory.StandardProxyFactory;
018 import com.thoughtworks.proxy.kit.ObjectReference;
019 import com.thoughtworks.proxy.kit.ReflectionUtils;
020 import com.thoughtworks.proxy.kit.SimpleReference;
021 import com.thoughtworks.proxy.toys.delegate.DelegationMode;
022
023
024 /**
025 * Factory for proxy instances that allow to exchange the delegated instance. Every created proxy will implement
026 * {@link Swappable}, that is used for the hot swap operation.
027 *
028 * @author Dan North
029 * @author Aslak Hellesøy
030 * @author Jörg Schaible
031 * @author Conrad Benham
032 * @author Paul Hammant
033 * @see com.thoughtworks.proxy.toys.hotswap
034 * @since 0.1
035 */
036 public class HotSwapping<T> {
037
038 private Object instance;
039 private Class<?>[] types;
040 private DelegationMode delegationMode;
041
042 private HotSwapping(final Class<T> primaryType, Class<?>... types) {
043 this.types = ReflectionUtils.makeTypesArray(primaryType, types);
044 }
045
046 /**
047 * Creates a factory for proxy instances that allow the exchange of delegated instances.
048 *
049 * @param type the type of the proxy when it is finally created.
050 * @return a factory that will proxy instances of the supplied type.
051 * @since 1.0
052 */
053 public static <T> HotSwappingWith<T> proxy(final Class<T> type) {
054 return new HotSwappingWith<T>(new HotSwapping<T>(type));
055 }
056
057 /**
058 * Creates a factory for proxy instances that allow the exchange of delegated instances.
059 *
060 * @param primaryType the primary type implemented by the proxy
061 * @param types other types that are implemented by the proxy
062 * @return a factory that will proxy instances of the supplied type.
063 * @since 1.0
064 */
065 public static <T> HotSwappingWith<T> proxy(final Class<T> primaryType, final Class<?> ... types) {
066 return new HotSwappingWith<T>(new HotSwapping<T>(primaryType, types));
067 }
068
069 /**
070 * Create a proxy with hot swapping capabilities for specific types of the delegate given with an
071 * {@link ObjectReference}. The delegate must implement the given types, if the invoker is in static typing mode,
072 * otherwise it must only have signature compatible methods. Proxies created by this method will implement
073 * {@link Swappable}
074 *
075 * @param factory the {@link ProxyFactory} to use.
076 * @return the created proxy implementing the <tt>types</tt> and {@link Swappable}
077 * @since 1.0
078 */
079 private T build(final ProxyFactory factory) {
080 final ObjectReference<Object> delegateReference = new SimpleReference<Object>(instance);
081 return new HotSwappingInvoker<T>(types, factory, delegateReference, delegationMode).proxy();
082 }
083
084 public static class HotSwappingWith<T> {
085 private final HotSwapping<T> hotswapping;
086
087 public HotSwappingWith(HotSwapping<T> hotswapping) {
088 this.hotswapping = hotswapping;
089 }
090
091 /**
092 * Defines the object that shall be proxied. This delegate must implement the types used to create the hot swap or
093 * have signature compatible methods.
094 *
095 * @param instance the object that shall be proxied.
096 * @return the factory that will proxy instances of the supplied type.
097 * @since 1.0
098 */
099 public HotSwappingBuildOrMode<T> with(final Object instance) {
100 hotswapping.instance = instance;
101 hotswapping.delegationMode = DIRECT;
102 for (Class<?> type : hotswapping.types) {
103 if (!type.isInstance(instance)) {
104 hotswapping.delegationMode = SIGNATURE;
105 break;
106 }
107 }
108 return new HotSwappingBuildOrMode<T>(hotswapping);
109 }
110 }
111
112 public static class HotSwappingBuildOrMode<T> extends HotSwappingBuild<T>{
113 public HotSwappingBuildOrMode(HotSwapping<T> hotswapping) {
114 super(hotswapping);
115 }
116
117 /**
118 * Forces a particular delegation mode to be used.
119 *
120 * @param delegationMode refer to {@link DelegationMode#DIRECT} or
121 * {@link DelegationMode#SIGNATURE} for allowed
122 * values.
123 * @return the factory that will proxy instances of the supplied type.
124 * @since 1.0
125 */
126 public HotSwappingBuild<T> mode(DelegationMode delegationMode) {
127 hotswapping.delegationMode = delegationMode;
128 return new HotSwappingBuild<T>(hotswapping);
129 }
130 }
131
132 public static class HotSwappingBuild<T> {
133 protected final HotSwapping<T> hotswapping;
134
135 public HotSwappingBuild(HotSwapping<T> hotswapping) {
136 this.hotswapping = hotswapping;
137 }
138
139 /**
140 * Create a proxy with hot swapping capabilities for specific types of the delegate given with an
141 * {@link ObjectReference}. The delegate must implement the given types, if the invoker is in static typing mode,
142 * otherwise it must only have signature compatible methods. Proxies created by this method will implement
143 * {@link Swappable}
144 *
145 * @return the created proxy implementing the <tt>types</tt> and {@link Swappable}
146 * @see com.thoughtworks.proxy.toys.hotswap
147 * @since 1.0
148 */
149 public T build() {
150 return build(new StandardProxyFactory());
151 }
152
153 /**
154 * Create a proxy with hot swapping capabilities for specific types of the delegate given with an
155 * {@link ObjectReference}. The delegate must implement the given types, if the invoker is in static typing mode,
156 * otherwise it must only have signature compatible methods. Proxies created by this method will implement
157 * {@link Swappable}
158 *
159 * @param factory the {@link ProxyFactory} to use.
160 * @return the created proxy implementing the <tt>types</tt> and {@link Swappable}
161 * @see com.thoughtworks.proxy.toys.hotswap
162 * @since 1.0
163 */
164 public T build(final ProxyFactory factory) {
165 return hotswapping.build(factory);
166 }
167 }
168 }