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 14-May-2004 010 */ 011 package com.thoughtworks.proxy.toys.multicast; 012 013 import java.util.Set; 014 015 import com.thoughtworks.proxy.ProxyFactory; 016 import com.thoughtworks.proxy.factory.StandardProxyFactory; 017 import com.thoughtworks.proxy.kit.ReflectionUtils; 018 019 /** 020 * Toy factory to create proxies delegating a call to multiple objects and managing the individual results. 021 * 022 * @author Dan North 023 * @author Aslak Hellesøy 024 * @author Jörg Schaible 025 * @author Juan Li 026 * @author Paul Hammant 027 * @see com.thoughtworks.proxy.toys.multicast 028 * @since 0.1 029 */ 030 public class Multicasting<T> { 031 private Class<?>[] types; 032 private Object[] delegates; 033 034 private Multicasting(Object... delegates) { 035 this.delegates = delegates; 036 } 037 038 private Multicasting(Class<?> primaryType, Class<?>... types) { 039 this.types = ReflectionUtils.makeTypesArray(primaryType, types); 040 } 041 042 /** 043 * Creates a factory for proxy instances delegating a call to multiple objects and managing the individual results. 044 * 045 * @param primaryType the primary type implemented by the proxy 046 * @param types other types that are implemented by the proxy 047 * @return a factory that will proxy instances of the supplied type. 048 * @since 1.0 049 */ 050 public static <T> MulticastingWith<T> proxy(Class<T> primaryType, Class<?>... types) { 051 return new MulticastingWith<T>(primaryType, types); 052 } 053 054 /** 055 * Creates a factory for proxy instances delegating a call to multiple objects and managing the individual results. 056 * 057 * @param targets targets the target objects 058 * @return a factory that will proxy instances of the supplied type. 059 * @since 1.0 060 */ 061 public static MulticastingBuild<Multicast> proxy(Object... targets) { 062 return new MulticastingBuild<Multicast>(targets); 063 } 064 065 public static class MulticastingWith<T> { 066 Multicasting<T> multicasting; 067 068 private MulticastingWith(Class<T> primaryType, Class<?>[] types) { 069 multicasting = new Multicasting<T>(primaryType, types); 070 } 071 072 /** 073 * With these target Objects 074 * @param targets targets the target objects 075 * @return the factory 076 * @since 1.0 077 */ 078 public MulticastingBuild<T> with(Object... targets) { 079 multicasting.delegates = targets; 080 return new MulticastingBuild<T>(multicasting); 081 } 082 } 083 084 public static class MulticastingBuild<T> { 085 private final Multicasting<T> multicasting; 086 087 private MulticastingBuild(Object[] targets) { 088 multicasting = new Multicasting<T>(targets); 089 } 090 091 private MulticastingBuild(Multicasting<T> multicasting) { 092 this.multicasting = multicasting; 093 } 094 095 /** 096 * @return the proxy using StandardProxyFactory 097 * @since 1.0 098 */ 099 public T build() { 100 return multicasting.build(); 101 } 102 103 /** 104 * Generate a proxy for the specified types calling the methods on the given targets using the {@link StandardProxyFactory}. 105 * <p> 106 * Note, that the method will only return a proxy if necessary. If there is only one target instance and this 107 * instance implements all of the specified types, then there is no point in creating a proxy. 108 * </p> 109 * 110 * @param factory the factory used to generate the proxy 111 * @return the new proxy implementing {@link Multicast} or the only target 112 * @since 1.0 113 */ 114 public T build(ProxyFactory factory) { 115 return multicasting.build(factory); 116 } 117 } 118 119 private T build() { 120 return build(new StandardProxyFactory()); 121 } 122 123 private T build(ProxyFactory factory) { 124 if (types == null) { 125 return buildWithNoTypesInput(factory); 126 } 127 128 if (delegates.length == 1) { 129 int i; 130 for (i = 0; i < types.length; i++) { 131 if (types[i] == Multicast.class) { 132 continue; 133 } 134 if (!types[i].isAssignableFrom(delegates[0].getClass())) { 135 break; 136 } 137 } 138 if (i == types.length) { 139 @SuppressWarnings("unchecked") 140 final T instance = (T) delegates[0]; 141 return instance; 142 } 143 } 144 return new MulticastingInvoker<T>(types, factory, delegates).proxy(); 145 } 146 147 private T buildWithNoTypesInput(ProxyFactory factory) { 148 if (delegates.length > 1) { 149 final Class<?> superclass = ReflectionUtils.getMostCommonSuperclass(delegates); 150 final Set<Class<?>> interfaces = ReflectionUtils.getAllInterfaces(delegates); 151 ReflectionUtils.addIfClassProxyingSupportedAndNotObject(superclass, interfaces, factory); 152 this.types = interfaces.toArray(new Class<?>[interfaces.size()]); 153 return new MulticastingInvoker<T>(types, factory, delegates).proxy(); 154 } 155 @SuppressWarnings("unchecked") 156 final T instance = (T) delegates[0]; 157 return instance; 158 } 159 }