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 04-Feb-2004
010     */
011    package com.thoughtworks.proxy.toys.delegate;
012    
013    import com.thoughtworks.proxy.ProxyFactory;
014    import com.thoughtworks.proxy.factory.StandardProxyFactory;
015    import com.thoughtworks.proxy.kit.SimpleReference;
016    
017    /**
018     * Toy factory to create proxies delegating to another object.
019     * <p>
020     * Such a proxy is used to mask the methods of an object, that are not part of a public interface. Or it is used to make
021     * an object compatible, e.g. when an object implements the methods of an interface, but does not implement the
022     * interface itself.
023     * </p>
024     *
025     * @author Dan North
026     * @author Jian Li
027     * @author Paul Hammant
028     * @see com.thoughtworks.proxy.toys.delegate
029     * @since 0.1
030     */
031    public class Delegating<T> {
032    
033        private Class<T> type;
034        private Object delegate;
035        private DelegationMode delegationMode = DelegationMode.SIGNATURE;
036    
037        private Delegating(Class<T> type) {
038            this.type = type;
039        }
040    
041        /**
042         * Creates a factory for proxy instances that allow delegation.
043         *
044         * @param type     the type of the proxy when it is finally created.
045         * @return a factory that will proxy instances of the supplied type.
046         * @since 1.0
047         */
048        public static <T> DelegatingWith<T> proxy(Class<T> type) {
049            return new DelegatingWith<T>(new Delegating<T>(type));
050        }
051    
052        public static class DelegatingWith<T> {
053            private Delegating<T> delegating;
054    
055            private DelegatingWith(Delegating<T> delegating) {
056                this.delegating = delegating;
057            }
058    
059            /**
060             * With this delegate
061             *
062             * @param delegate the object the proxy delegates to.
063             * @return the factory that will route calls to the supplied delegate.
064             * @since 1.0
065             */
066            public DelegatingModeOrBuild<T> with(Object delegate) {
067                delegating.delegate = delegate;
068                return new DelegatingModeOrBuild<T>(delegating);
069            }
070    
071        }
072    
073        public static class DelegatingModeOrBuild<T> extends DelegatingBuild<T>{
074    
075            private DelegatingModeOrBuild(Delegating<T> delegating) {
076                super(delegating);
077            }
078    
079            /**
080             * Forces a particular delegation mode to be used.
081             *
082             * @param mode refer to {@link DelegationMode#DIRECT} or
083             *             {@link DelegationMode#SIGNATURE} for allowed values.
084             * @return the factory that will proxy instances of the supplied type.
085             */
086            public DelegatingBuild<T> mode(DelegationMode mode) {
087                delegating.delegationMode = mode;
088                return new DelegatingBuild<T>(delegating);
089            }
090    
091        }
092    
093        public static class DelegatingBuild<T> {
094            protected Delegating<T> delegating;
095    
096            private DelegatingBuild(Delegating<T> delegating) {
097                this.delegating = delegating;
098            }
099    
100            /**
101             * Creating a delegating proxy for an object using the {@link StandardProxyFactory}.
102             *
103             * @return the created proxy implementing the <tt>type</tt>
104             * @since 1.0
105             */
106            public T build() {
107                return build(new StandardProxyFactory());
108            }
109    
110            /**
111             * Creating a delegating proxy for an object using a special {@link ProxyFactory}.
112             *
113             * @param factory the {@link ProxyFactory} to use.
114             * @return the created proxy implementing the <tt>type</tt>
115             * @since 1.0
116             */
117            public T build(ProxyFactory factory) {
118                return factory.<T>createProxy(new DelegatingInvoker<Object>(factory,
119                        new SimpleReference<Object>(delegating.delegate), delegating.delegationMode), delegating.type);
120            }
121        }
122    }