Package com.thoughtworks.proxy.toys.multicast

A toy to perform a single call on multiple objects and manage the results.

See:
          Description

Interface Summary
Multicast Interface that is implemented by all multicasting proxies.
 

Class Summary
Multicasting<T> Toy factory to create proxies delegating a call to multiple objects and managing the individual results.
Multicasting.MulticastingBuild<T>  
Multicasting.MulticastingWith<T>  
MulticastingInvoker<T> A Invoker implementation that multicasts calls to multiple targets.
 

Package com.thoughtworks.proxy.toys.multicast Description

A toy to perform a single call on multiple objects and manage the results.

The package provides a proxy factory creating proxies, that can delegate a single call to a lot of different instances and manages the individual results. Main component is the Multicasting toy, a utility class creating these proxies. Such a proxy contains an instance of a MulticastingInvoker that delegates the calls.

The multicasting toy will always try to optimize the created proxy taking the types into regard, that is should implement, the types of all delegated objects and all their interfaces:

The multicasting proxy has some surprising features. What will be the result of a call? The problem is, that a method will just return a specific type, but not necessarily an array or collection of them. What to do about primitives? The MulticatingInvoker implements a simple strategy:

  1. if the return value of the called methods is an object, drop all null returned values and create for the remaining objects a new Multicasting proxy (rules above apply) or return null if none is left
  2. if the return value is a primitive (except a Boolean), then sum up the values and return the sum
  3. if the return value is a Boolean, then return true if any method call returned also true otherwise return false

Note that the multicasting invoker does not handle exceptions. If one method call throws, the exception is not catched.

Following example demonstrates a multicast to two different list objects. First of all implements the proxy the type List automatically. The method add returns a boolean, which will be logically and-combined for the overall result of the call. The content of the two lists will be printed only if the element was added to both lists:

ArrayList<String> arrayList = new ArrayList<String>();
LinkedList<String> linkedList = new LinkedList<String>();
@SuppressWarnings("unchecked")
List<String> listCombined = List.class.cast(Multicasting.proxy(arrayList, linkedList).build());
if (listCombined.add("Hello")) {
    System.out.println("List 1: " + arrayList.toString());
    System.out.println("List 2: " + linkedList.toString());
}

Next example demonstrates the multicast of a method on a proxy, that cannot implement the necessary type for the method, because Integer.class is final for which it should create the proxy. Nevertheless the call to intValue succeeds and the resulting values are summed up. And do not get confused by the value, the result is 8:

List<Integer> list1 = new ArrayList<Integer>();
list1.add(5);
list1.add(100);
List<Integer> list2 = new LinkedList<Integer>();
list2.add(3);
@SuppressWarnings("unchecked")
List<Integer> listCombined = List.class.cast(Multicasting.proxy(list1, list2).build());
Multicast values = Multicast.class.cast(listCombined.get(0));
System.out.println("Sum of the first integers: " + values.multicastTargets(Integer.class, "intValue", null).toString());

In this use case we demonstrate, that the proxy can implement different types and a multicast will only be executed on the valid targets:

File workingDir = new File(".");
List<String> files = Arrays.asList(workingDir.list());
File multicast = Multicasting.proxy(File.class, List.class)
    .with(workingDir, files)
    .build(new CglibProxyFactory());
System.out.println("Current working directory: " + multicast.getAbsolutePath());
System.out.println("Files in working directory: " + List.class.cast(multicast).size());

If the result of a method is a final class, there is normally no way to access the resulting elements, since the proxy cannot implement the class type. In this example we access the String targets with the help of the Multicast interface:

Method method = String.class.getMethod("length");
Multicast multicast = Multicasting.proxy("ProxyToys", "is", "great").build();
System.out.println("Total number of characters: " + multicast.multicastTargets(method, null));
String[] strings = multicast.getTargetsInArray(String.class);
for (int i = 0; i < strings.length; i++) {
    System.out.println("String[" + i + "]: " + strings[i]);
}

The last example demonstrates the inheritance of the multicast proxy, the filtering of null values in the result and the abandonment of the proxy if it is no longer necessary. Here we get with the call of the iterator method again a multicasting proxy. The call of the next method will result in a null value from the set and the String from the list. Since the String class is final, the returned value from the call is no longer a proxy, the cast would fail:

List<String> list = new ArrayList<String>();
Set<String> set = new HashSet<String>();
list.add("ProxyToys");
set.add(null);
@SuppressWarnings("unchecked")
Collection<String> collection = Collection.class.cast(Multicasting.proxy(list, set).build());
Iterator<String> iter = collection.iterator();
String value = iter.next();
System.out.println("Element gained from the iterator: " + value);



Copyright © 2005-2010 Codehaus. All Rights Reserved.