View Javadoc

1   package org.lsst.ccs.utilities.dispatch;
2   
3   import java.lang.reflect.InvocationHandler;
4   import java.lang.reflect.Method;
5   import java.lang.reflect.Proxy;
6   import java.util.concurrent.CopyOnWriteArrayList;
7   import java.util.concurrent.ExecutorService;
8   import java.util.logging.Level;
9   
10  /**
11   *  Instances of this class creates a dynamic proxy that parallely 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   */
18  public class ParallelDispatchProxy<I> {
19  
20      protected CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<Object>();
21      protected I proxy;
22      protected ExecutorService loop;
23  
24      class Invoker implements InvocationHandler {
25          @Override
26          public Object invoke(Object o, final Method method, final Object[] parms) {
27              for (final Object goal : list) {
28                  loop.submit(new Runnable() {
29                      @Override
30                      public void run() {
31                          try {
32                             method.invoke(goal, parms);
33                          }catch(Exception exc) {
34                              PackCst.CURLOG.log(Level.SEVERE, "dispatching to " + goal, exc);
35                          }
36                      }
37                  });
38              }
39              return null;
40          }
41      }
42  
43      /**
44       * prepares a generator able to deliver a Proxy object able to dispatch method calls to registered agents.
45       * The methods of the interface will necessarily be of procedural nature (the return values will be dumped)
46       *
47       * @param interfaceType
48       */
49      public ParallelDispatchProxy(Class<I> interfaceType) {
50          this(interfaceType, false) ;
51      }
52  
53      /**
54       * Same as <TT>ParallelDispatchProxy</TT> but specification of a single Thread dispatch can be added.
55       * @param interfaceType
56       * @param singleThread
57       */
58      public ParallelDispatchProxy(Class<I> interfaceType, boolean singleThread) {
59          // not necessarily a good idea ;
60          proxy = (I) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{interfaceType}, new Invoker());
61          if(singleThread) {
62              this.loop = PackCst.SINGLE_THREAD ;
63          } else {
64              this.loop = PackCst.EXECUTOR_SERVICE;
65          }
66      }
67  
68      /**
69       * Same as previous but with a specified ClassLoader
70       *
71       * @param interfaceType
72       * @param loader
73       */
74      public ParallelDispatchProxy(Class<I> interfaceType, ClassLoader loader) {
75          this(interfaceType, loader, false) ;
76      }
77      public ParallelDispatchProxy(Class<I> interfaceType, ClassLoader loader, boolean singleThread) {
78          proxy = (I) Proxy.newProxyInstance(loader, new Class[]{interfaceType}, new Invoker());
79          if(singleThread) {
80              this.loop = PackCst.SINGLE_THREAD ;
81          } else {
82              this.loop = PackCst.EXECUTOR_SERVICE;
83          }
84      }
85  
86      /**
87       * Registers a code ready to receive "synchronous" commands
88       *
89       * @param executant (should implement the interface)
90       */
91      public <T extends I> void addExecutant(T executant) {
92          list.add(executant);
93      }
94  
95      /**
96       * Remove the code from the listeners list
97       *
98       * @param executant
99       */
100     public <T extends I> void removeExecutant(T executant) {
101         list.remove(executant);
102     }
103 
104     /**
105      * to be called once to get a dynamically generated proxy that will forward calls to registered agents.
106      *
107      * @return
108      */
109     public I getProxy() {
110         return proxy;
111     }
112 }