1   /*
2   *  SerialController.java
3   *
4   *  Copyright (c) 1998-2005, 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.26 2006/04/06 13:02:29 valyt 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.GateRuntimeException;
24  import gate.util.profile.Profiler;
25  
26  /** Execute a list of PRs serially.
27   */
28  public class SerialController extends AbstractController
29      implements CreoleListener{
30    private final static boolean DEBUG = false;
31  
32    /** Profiler to track PR execute time */
33    protected Profiler prof;
34  
35    public SerialController(){
36      prList = Collections.synchronizedList(new ArrayList());
37      sListener = new InternalStatusListener();
38  
39      if(DEBUG) {
40        prof = new Profiler();
41        prof.enableGCCalling(false);
42        prof.printToSystemOut(true);
43      }
44      Gate.getCreoleRegister().addCreoleListener(this);
45    }
46  
47    /**
48     * Returns all the {@link gate.ProcessingResource}s contained by this
49     * controller as an unmodifiable list.
50     */
51    public Collection getPRs(){
52      return Collections.unmodifiableList(prList);
53    }
54  
55    /**
56     * Populates this controller from a collection of {@link ProcessingResource}s
57     * (optional operation).
58     *
59     * Controllers that are serializable must implement this method needed by GATE
60     * to restore the contents of the controllers.
61     * @throws UnsupportedOperationException if the <tt>setPRs</tt> method
62     *         is not supported by this controller.
63     */
64    public void setPRs(Collection prs){
65      prList.clear();
66      Iterator prIter = prs.iterator();
67      while(prIter.hasNext()) add((ProcessingResource)prIter.next());
68    }
69  
70    public void add(int index, ProcessingResource pr){
71      prList.add(index, pr);
72      fireResourceAdded(new ControllerEvent(this, 
73              ControllerEvent.RESOURCE_ADDED, pr));
74    }
75  
76    public void add(ProcessingResource pr){
77      prList.add(pr);
78      fireResourceAdded(new ControllerEvent(this, 
79              ControllerEvent.RESOURCE_ADDED, pr));
80    }
81  
82    public ProcessingResource remove(int index){
83      ProcessingResource aPr = (ProcessingResource)prList.remove(index);
84      fireResourceRemoved(new ControllerEvent(this, 
85              ControllerEvent.RESOURCE_REMOVED, aPr));
86      return aPr;
87    }
88  
89    public boolean remove(ProcessingResource pr){
90      boolean ret = prList.remove(pr);
91      if(ret) fireResourceRemoved(new ControllerEvent(this, 
92              ControllerEvent.RESOURCE_REMOVED, pr));
93      return ret;
94    }
95  
96    public ProcessingResource set(int index, ProcessingResource pr){
97      return (ProcessingResource)prList.set(index, pr);
98    }
99  
100   /**
101    * Verifies that all PRs have all their required rutime parameters set.
102    */
103   protected void checkParameters() throws ExecutionException{
104     List badPRs;
105     try{
106       badPRs = getOffendingPocessingResources();
107     }catch(ResourceInstantiationException rie){
108       throw new ExecutionException(
109           "Could not check runtime parameters for the processing resources:\n" +
110           rie.toString());
111     }
112     if(badPRs != null && !badPRs.isEmpty()){
113       throw new ExecutionException(
114           "Some of the processing resources in this controller have unset " +
115           "runtime parameters:\n" +
116           badPRs.toString());
117     }
118   }
119 
120   /** Run the Processing Resources in sequence. */
121   public void execute() throws ExecutionException{
122     //check all the PRs have the right parameters
123     checkParameters();
124 
125     if(DEBUG) {
126       prof.initRun("Execute controller [" + getName() + "]");
127     }
128 
129     //execute all PRs in sequence
130     interrupted = false;
131     for (int i = 0; i < prList.size(); i++){
132       if(isInterrupted()) throw new ExecutionInterruptedException(
133           "The execution of the " + getName() +
134           " application has been abruptly interrupted!");
135 
136       runComponent(i);
137       if (DEBUG) {
138         prof.checkPoint("~Execute PR ["+((ProcessingResource)
139                                    prList.get(i)).getName()+"]");
140       }
141     }
142 
143     if (DEBUG) {
144       prof.checkPoint("Execute controller [" + getName() + "] finished");
145     }
146 
147   } // execute()
148 
149 
150   /**
151    * Executes a {@link ProcessingResource}.
152    */
153   protected void runComponent(int componentIndex) throws ExecutionException{
154     ProcessingResource currentPR = (ProcessingResource)
155                                    prList.get(componentIndex);
156 
157     //create the listeners
158     FeatureMap listeners = Factory.newFeatureMap();
159     listeners.put("gate.event.StatusListener", sListener);
160     int componentProgress = 100 / prList.size();
161     listeners.put("gate.event.ProgressListener",
162                   new IntervalProgressListener(
163                   componentIndex * componentProgress,
164                   (componentIndex +1) * componentProgress)
165                   );
166 
167     //add the listeners
168     try{
169       AbstractResource.setResourceListeners(currentPR, listeners);
170     }catch(Exception e){
171       // the listeners setting failed; nothing important
172       Err.prln("Could not set listeners for " + currentPR.getClass().getName() +
173                "\n" + e.toString() + "\n...nothing to lose any sleep over.");
174     }
175 
176     //run the thing
177     currentPR.execute();
178 
179     //remove the listeners
180     try{
181       AbstractResource.removeResourceListeners(currentPR, listeners);
182     }catch(Exception e){
183       // the listeners removing failed; nothing important
184       Err.prln("Could not clear listeners for " +
185                currentPR.getClass().getName() +
186                "\n" + e.toString() + "\n...nothing to lose any sleep over.");
187     }
188   }//protected void runComponent(int componentIndex)
189 
190   /**
191    * Cleans the internal data and prepares this object to be collected
192    */
193   public void cleanup(){
194     //close all PRs in this controller
195     if(prList != null && !prList.isEmpty()){
196       for(Iterator prIter = new ArrayList(prList).iterator();
197           prIter.hasNext(); 
198           Factory.deleteResource((Resource)prIter.next()));
199     }
200     Gate.getCreoleRegister().removeCreoleListener(this);
201   }
202 
203   /** The list of contained PRs*/
204   protected List prList;
205 
206   /** A proxy for status events*/
207   protected StatusListener sListener;
208   public void resourceLoaded(CreoleEvent e) {
209   }
210   
211   public void resourceUnloaded(CreoleEvent e) {
212     //remove all occurences of the resource from this controller
213     if(e.getResource() instanceof ProcessingResource)
214       while(prList.remove(e.getResource()));
215     //remove links in parameters
216     for(int i = 0; i < prList.size(); i++){
217       ProcessingResource aPr = (ProcessingResource)prList.get(i);
218       ResourceData rData = (ResourceData)Gate.getCreoleRegister().get(
219               aPr.getClass().getName());
220       if(rData != null){
221         Iterator rtParamDisjIter = rData.getParameterList().
222             getRuntimeParameters().iterator();
223         while(rtParamDisjIter.hasNext()){
224           List aDisjunction = (List)rtParamDisjIter.next();
225           Iterator rtParamIter = aDisjunction.iterator();
226           while(rtParamIter.hasNext()){
227             Parameter aParam = (Parameter)rtParamIter.next();
228             String paramName = aParam.getName();
229             try{
230               if(aPr.getParameterValue(paramName) == e.getResource()){
231                 aPr.setParameterValue(paramName, null);
232               }
233             }catch(ResourceInstantiationException rie){
234               //nothing to do - this should never happen
235               throw new GateRuntimeException(rie);
236             }
237           }
238         }
239       }
240     }
241   }
242 
243   public void resourceRenamed(Resource resource, String oldName,
244                               String newName){
245   }
246 
247   public void datastoreOpened(CreoleEvent e) {
248   }
249   public void datastoreCreated(CreoleEvent e) {
250   }
251   public void datastoreClosed(CreoleEvent e) {
252   }
253 
254 } // class SerialController