001    /*
002     * (c) 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 24-Feb-2005
010     */
011    package com.thoughtworks.proxy.toys.dispatch;
012    
013    import com.thoughtworks.proxy.ProxyFactory;
014    import com.thoughtworks.proxy.factory.StandardProxyFactory;
015    import com.thoughtworks.proxy.kit.ObjectReference;
016    import com.thoughtworks.proxy.kit.ReflectionUtils;
017    import com.thoughtworks.proxy.kit.SimpleReference;
018    
019    /**
020     * Proxy factory for dispatching proxy instances.
021     *
022     * @author Jörg Schaible
023     * @author Juan Li
024     * @author Paul Hammant
025     * @see com.thoughtworks.proxy.toys.dispatch
026     * @since 0.2
027     */
028    public class Dispatching<T> {
029    
030        private Class<?>[] types;
031        private Object[] delegates;
032    
033        private Dispatching(Class<?>[] types) {
034            this.types = types;
035        }
036    
037        /**
038         * Creates a builder for proxy instances that allow delegation.
039         *
040         * @param primaryType the primary type of the proxy that will not have to be cast to
041         * @param types the other types of the proxy
042         * @return a builder that will proxy instances of the supplied type.
043         * @since 1.0
044         */
045        public static <T> DispatchingWith<T> proxy(Class<T> primaryType, Class<?>... types) {
046            return new DispatchingWith<T>(primaryType,  types);
047        }
048    
049        private T build(ProxyFactory factory) {
050            @SuppressWarnings("unchecked")
051            final ObjectReference<Object>[] references = new ObjectReference[delegates.length];
052            for (int i = 0; i < references.length; i++) {
053                references[i] = new SimpleReference<Object>(delegates[i]);
054            }
055            return factory.<T>createProxy(new DispatchingInvoker(factory, types, references), types);
056        }
057    
058        public static class DispatchingWith<T> {
059            private final Dispatching<T> dispatching;
060    
061            private DispatchingWith(Class<T> primaryType, Class<?>[] types) {
062                this.dispatching = new Dispatching<T>(ReflectionUtils.makeTypesArray(primaryType, types));
063            }
064    
065            /**
066             * Defines the object that shall be delegated to. This delegate must implement the types used to create the
067             * dispatching proxy or have signature compatible methods.
068             *
069             * @param delegates the objects that will receive the calls.
070             * @return the factory that will proxy instances of the supplied type.
071             * @since 1.0
072             */
073            public DispatchingBuild<T> with(final Object... delegates) {
074                dispatching.delegates = delegates;
075                return new DispatchingBuild<T>(dispatching);
076            }
077        }
078    
079        public static class DispatchingBuild<T> {
080            private final Dispatching<T> dispatching;
081    
082            private DispatchingBuild(Dispatching<T> dispatching) {
083                this.dispatching = dispatching;
084            }
085    
086            /**
087             * Create a dispatching proxy of given types for the given objects using the {@link StandardProxyFactory}
088             *
089             * @return the created proxy
090             * @since 1.0
091             */
092            public T build() {
093                return build(new StandardProxyFactory());
094            }
095    
096            /**
097             * Create a dispatching proxy of given types for the given objects using a special {@link ProxyFactory}.
098             *
099             * @param factory the {@link ProxyFactory} to use
100             * @return the created proxy
101             * @since 1.0
102             */
103            public T build(ProxyFactory factory) {
104                return dispatching.build(factory);
105            }
106        }
107    }