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 }