1 package org.lsst.ccs.utilities.dispatch;
2
3
4 import java.lang.reflect.InvocationHandler;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Proxy;
7 import java.util.concurrent.CopyOnWriteArrayList;
8 import java.util.logging.Level;
9
10 /**
11 * Instances of this class creates a dynamic proxy that dispatches method call
12 * to registered agents implementing an interface type.
13 * <P>
14 * <B>beware</B> : if the implemented interface is itself a parameterized type
15 * no type control is exercised on these type parameters.
16 *
17 * @author Bernard AMADE
18 */
19 public class SynchronousDispatchProxy <I> {
20 protected CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<Object>() ;
21 class Invoker implements InvocationHandler {
22 @Override
23 public Object invoke(Object o, Method method, Object[] parms){
24 for(Object goal : list) {
25 try {
26 method.invoke(goal, parms);
27 } catch (Exception exc) {
28 PackCst.CURLOG.log(Level.SEVERE, "dispatching to " + goal, exc);
29 }
30 }
31 return null;
32 }
33 }
34
35 protected I proxy ;
36
37 /**
38 * prepares a generator able to deliver a Proxy object able to dispatch method calls to registered agents.
39 * The methods of the interface will necessarily be of procedural nature (the return values will be dumped)
40 * @param interfaceType
41 */
42 public SynchronousDispatchProxy(Class<I> interfaceType) {
43 // not necessarily a good idea ;
44 proxy = (I) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {interfaceType}, new Invoker()) ;
45
46 }
47
48 /**
49 * Same as previous but with a specified ClassLoader
50 * @param interfaceType
51 * @param loader
52 */
53 public SynchronousDispatchProxy(Class<I> interfaceType, ClassLoader loader) {
54 proxy = (I) Proxy.newProxyInstance(loader, new Class[] {interfaceType}, new Invoker()) ;
55 }
56
57 /**
58 * Registers a code ready to receive "synchronous" commands
59 * @param executant (should implement the interface)
60 */
61 public <T extends I> void addExecutant(T executant) {
62 list.add(executant) ;
63 }
64
65 /**
66 * Remove the code from the listeners list
67 *
68 * @param executant
69 */
70 public <T extends I> void removeExecutant(T executant){
71 list.remove(executant) ;
72 }
73
74 /**
75 * to be called once to get a dynamically generated proxy that will forward calls to registered agents.
76 *
77 * @return
78 */
79 public I getProxy() {
80 return proxy ;
81 }
82 }