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