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 */
011package com.thoughtworks.proxy.toys.dispatch;
012
013import com.thoughtworks.proxy.ProxyFactory;
014import com.thoughtworks.proxy.factory.StandardProxyFactory;
015import com.thoughtworks.proxy.kit.ObjectReference;
016import com.thoughtworks.proxy.kit.ReflectionUtils;
017import 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 */
028public 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}