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    }