1   /*
2   *  SerialController.java
3   *
4   *  Copyright (c) 1998-2004, The University of Sheffield.
5   *
6   *  This file is part of GATE (see http://gate.ac.uk/), and is free
7   *  software, licenced under the GNU Library General Public License,
8   *  Version 2, June 1991 (in the distribution as file licence.html,
9   *  and also available at http://gate.ac.uk/gate/licence.html).
10  *
11  *  Hamish Cunningham, 9/Nov/2000
12  *
13  *  $Id: SerialController.java,v 1.23 2004/07/21 17:10:03 akshay Exp $
14   */
15  
16  package gate.creole;
17  
18  import java.util.*;
19  
20  import gate.*;
21  import gate.event.*;
22  import gate.util.Err;
23  import gate.util.profile.Profiler;
24  
25  /** Execute a list of PRs serially.
26   */
27  public class SerialController extends AbstractController
28      implements CreoleListener{
29    private final static boolean DEBUG = false;
30  
31    /** Profiler to track PR execute time */
32    protected Profiler prof;
33  
34    public SerialController(){
35      prList = Collections.synchronizedList(new ArrayList());
36      sListener = new InternalStatusListener();
37  
38      if(DEBUG) {
39        prof = new Profiler();
40        prof.enableGCCalling(false);
41        prof.printToSystemOut(true);
42      }
43    }
44  
45    /**
46     * Returns all the {@link gate.ProcessingResource}s contained by this
47     * controller as an unmodifiable list.
48     */
49    public Collection getPRs(){
50      return Collections.unmodifiableList(prList);
51    }
52  
53    /**
54     * Populates this controller from a collection of {@link ProcessingResource}s
55     * (optional operation).
56     *
57     * Controllers that are serializable must implement this method needed by GATE
58     * to restore the contents of the controllers.
59     * @throws UnsupportedOperationException if the <tt>setPRs</tt> method
60     *         is not supported by this controller.
61     */
62    public void setPRs(Collection prs){
63      prList.clear();
64      Iterator prIter = prs.iterator();
65      while(prIter.hasNext()) add((ProcessingResource)prIter.next());
66    }
67  
68    public void add(int index, ProcessingResource pr){
69      prList.add(index, pr);
70      fireResourceAdded(new ControllerEvent(this, 
71              ControllerEvent.RESOURCE_ADDED, pr));
72    }
73  
74    public void add(ProcessingResource pr){
75      prList.add(pr);
76      fireResourceAdded(new ControllerEvent(this, 
77              ControllerEvent.RESOURCE_ADDED, pr));
78    }
79  
80    public ProcessingResource remove(int index){
81      ProcessingResource aPr = (ProcessingResource)prList.remove(index);
82      fireResourceRemoved(new ControllerEvent(this, 
83              ControllerEvent.RESOURCE_REMOVED, aPr));
84      return aPr;
85    }
86  
87    public boolean remove(ProcessingResource pr){
88      boolean ret = prList.remove(pr);
89      if(ret) fireResourceRemoved(new ControllerEvent(this, 
90              ControllerEvent.RESOURCE_REMOVED, pr));
91      return ret;
92    }
93  
94    public ProcessingResource set(int index, ProcessingResource pr){
95      return (ProcessingResource)prList.set(index, pr);
96    }
97  
98    /**
99     * Verifies that all PRs have all their required rutime parameters set.
100    */
101   protected void checkParameters() throws ExecutionException{
102     List badPRs;
103     try{
104       badPRs = getOffendingPocessingResources();
105     }catch(ResourceInstantiationException rie){
106       throw new ExecutionException(
107           "Could not check runtime parameters for the processing resources:\n" +
108           rie.toString());
109     }
110     if(badPRs != null && !badPRs.isEmpty()){
111       throw new ExecutionException(
112           "Some of the processing resources in this controller have unset " +
113           "runtime parameters:\n" +
114           badPRs.toString());
115     }
116   }
117 
118   /** Run the Processing Resources in sequence. */
119   public void execute() throws ExecutionException{
120     //check all the PRs have the right parameters
121     checkParameters();
122 
123     if(DEBUG) {
124       prof.initRun("Execute controller [" + getName() + "]");
125     }
126 
127     //execute all PRs in sequence
128     interrupted = false;
129     for (int i = 0; i < prList.size(); i++){
130       if(isInterrupted()) throw new ExecutionInterruptedException(
131           "The execution of the " + getName() +
132           " application has been abruptly interrupted!");
133 
134       runComponent(i);
135       if (DEBUG) {
136         prof.checkPoint("~Execute PR ["+((ProcessingResource)
137                                    prList.get(i)).getName()+"]");
138       }
139     }
140 
141     if (DEBUG) {
142       prof.checkPoint("Execute controller [" + getName() + "] finished");
143     }
144 
145   } // execute()
146 
147 
148   /**
149    * Executes a {@link ProcessingResource}.
150    */
151   protected void runComponent(int componentIndex) throws ExecutionException{
152     ProcessingResource currentPR = (ProcessingResource)
153                                    prList.get(componentIndex);
154 
155     //create the listeners
156     FeatureMap listeners = Factory.newFeatureMap();
157     listeners.put("gate.event.StatusListener", sListener);
158     int componentProgress = 100 / prList.size();
159     listeners.put("gate.event.ProgressListener",
160                   new IntervalProgressListener(
161                   componentIndex * componentProgress,
162                   (componentIndex +1) * componentProgress)
163                   );
164 
165     //add the listeners
166     try{
167       AbstractResource.setResourceListeners(currentPR, listeners);
168     }catch(Exception e){
169       // the listeners setting failed; nothing important
170       Err.prln("Could not set listeners for " + currentPR.getClass().getName() +
171                "\n" + e.toString() + "\n...nothing to lose any sleep over.");
172     }
173 
174     //run the thing
175     currentPR.execute();
176 
177     //remove the listeners
178     try{
179       AbstractResource.removeResourceListeners(currentPR, listeners);
180     }catch(Exception e){
181       // the listeners removing failed; nothing important
182       Err.prln("Could not clear listeners for " +
183                currentPR.getClass().getName() +
184                "\n" + e.toString() + "\n...nothing to lose any sleep over.");
185     }
186   }//protected void runComponent(int componentIndex)
187 
188   /**
189    * Cleans the internal data and prepares this object to be collected
190    */
191   public void cleanup(){
192     // Diana desire to remove PR-s
193     Resource res;
194     for(int i=0; i<prList.size(); ++i) {
195       res = (Resource) prList.get(i);
196       Factory.deleteResource(res);
197     } // for
198     prList.clear();
199   }
200 
201   /** The list of contained PRs*/
202   protected List prList;
203 
204   /** A proxy for status events*/
205   protected StatusListener sListener;
206   public void resourceLoaded(CreoleEvent e) {
207   }
208   public void resourceUnloaded(CreoleEvent e) {
209     //remove all occurences of the resource from this controller
210     if(e.getResource() instanceof ProcessingResource)
211       while(prList.remove(e.getResource()));
212   }
213 
214   public void resourceRenamed(Resource resource, String oldName,
215                               String newName){
216   }
217 
218   public void datastoreOpened(CreoleEvent e) {
219   }
220   public void datastoreCreated(CreoleEvent e) {
221   }
222   public void datastoreClosed(CreoleEvent e) {
223   }
224 
225 } // class SerialController