View Javadoc

1   package org.lsst.ccs.utilities.dispatch;
2   
3   
4   import java.util.concurrent.CopyOnWriteArrayList;
5   import java.util.concurrent.ExecutorService;
6   import java.util.logging.Level;
7   
8   /**
9    * Dispatches a Command object to registered "<I>executants</I>" able to handle the command;
10   * each command execution may be handled by a different Thread so every registered agent does not have to wait
11   * for termination of code from the previous  call.
12   * <P>
13   * <B>BEWARE</B> :
14   * <UL>
15   * <LI>
16   *     The default constructor implementation uses a "cached" Thread Pool :
17   *     <UL>
18   *         <LI>
19   *             It is not guaranteed that events will be really executed in parallel.
20   *             A fixed Thread pool knowing about the number of processors  or a pure sequential code may be
21   *             more efficient: test! (and ask for changes!)
22   *             <BR>
23   *             Better use this class if the Command's code takes quite a lot of time to execute.
24   *         <LI>
25   *             The Thread pool may "choke"  if commands to be executed are registered at a higher rate than
26   *             they can be executed.
27   *     </UL>
28   * <LI>
29   *     The Threads handling the commands are deamon Threads. This may be a problem if you need an application Thread ...
30   *     Moreover it is not guaranteed that all commands will be executed if the JVM abruptly terminates.
31   *     <BR>
32   *      This can be changed .... just ask!
33   *
34   * </UL>
35   *
36   *
37   * @param <T> the nature of the code able to handle the <TT>CommandFor&lt;T&gt;</TT> Objects
38   * @author bernard AMADE
39   */
40  public class ParallelCommandDispatcher<T> {
41  
42      /**
43       * Object of this embedded class are for registering a task to be handled by the executing Threads.
44       * @param <T2> code able to handle the corresponding <TT>CommandFor</TT> Objects.
45       */
46      static class DoIt<T2> implements Runnable {
47          public final T2 executant ;
48          public final CommandFor<T2> command ;
49  
50          DoIt(T2 executant, CommandFor<T2> command) {
51              //System.out.println("#### command submitted : " + command);
52              this.executant = executant;
53              this.command = command;
54          }
55  
56          @Override
57          public void run() {
58              try{
59                  //System.out.println("#### command   executed " + command  );
60                  command.invokeOn(executant);
61              } catch (Exception exc) {
62                 PackCst.CURLOG.log(Level.SEVERE, "while executing :", exc);
63              }
64          }
65      }
66  
67      /**
68       *   ExecutorService that deals with the Threads handling the commands.
69       */
70      protected  ExecutorService loop ;
71  
72      /**
73       * List of all registered agent that may take action.
74       */
75       protected CopyOnWriteArrayList<T> list = new java.util.concurrent.CopyOnWriteArrayList<T>() ;
76  
77  
78      /**
79       * Creates an asynchronous Dispatcher for Commands.
80       * Uses the standard common ExecutorService for this package.
81       */
82      public ParallelCommandDispatcher() {
83          this.loop = PackCst.EXECUTOR_SERVICE ;
84      }
85  
86      /**
87       * Creates an asynchronous Dispatcher for Commands: uses a specific ExecutorService.
88       */
89      public ParallelCommandDispatcher(ExecutorService execService) {
90          this.loop = execService ;
91      }
92  
93      public ParallelCommandDispatcher(boolean singleThread) {
94          if(singleThread) {
95              this.loop   =  PackCst.SINGLE_THREAD ;
96          } else {
97              this.loop = PackCst.EXECUTOR_SERVICE ;
98          }
99      }
100     /**
101      * adds an executant to the list of those going to execute Commands when needed.
102      * @param executant
103      */
104     public void addExecutant(T executant) {
105         list.add(executant) ;
106     }
107 
108     /**
109      * removes an executant form the list
110      *
111      * @param executant
112      */
113 
114     public void removeExecutant(T executant) {
115         list.remove(executant) ;
116     }
117 
118     /**
119      * Send a Command request for all registered executants.
120      * @param command
121      */
122      public void dispatchCommand(CommandFor<T> command) {
123          //System.out.println("# dispatching to " + list.size());
124         for(T executant : list) {
125             loop.submit(new DoIt<T>(executant, command)) ;
126         }
127     }
128 }