001 /*
002 * SerialController.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Hamish Cunningham, 9/Nov/2000
013 *
014 * $Id: SerialController.java 12936 2010-08-06 15:08:54Z thomas_heitz $
015 */
016
017 package gate.creole;
018
019 import java.util.*;
020
021 import org.apache.log4j.Logger;
022
023 import gate.*;
024 import gate.creole.metadata.*;
025 import gate.event.*;
026 import gate.util.*;
027 import gate.util.profile.Profiler;
028 import gate.util.Out;
029
030 /**
031 * Execute a list of PRs serially.
032 */
033 @CreoleResource(name = "Pipeline",
034 comment = "A simple serial controller for PR pipelines.",
035 helpURL = "http://gate.ac.uk/userguide/sec:developer:apps")
036 public class SerialController extends AbstractController implements
037 CreoleListener,
038 CustomDuplication {
039
040 protected static final Logger log = Logger.getLogger(SerialController.class);
041
042 /** Profiler to track PR execute time */
043 protected Profiler prof;
044 protected HashMap timeMap;
045 protected HashMap<String, Long> prTimeMap;
046
047 public SerialController() {
048 prList = Collections.synchronizedList(new ArrayList());
049 sListener = new InternalStatusListener();
050 prTimeMap = new HashMap<String, Long>();
051
052 if(log.isDebugEnabled()) {
053 prof = new Profiler();
054 prof.enableGCCalling(false);
055 prof.printToSystemOut(true);
056 timeMap = new HashMap();
057 }
058 Gate.getCreoleRegister().addCreoleListener(this);
059 }
060
061 /**
062 * Returns all the {@link gate.ProcessingResource}s contained by thisFeature
063 * controller as an unmodifiable list.
064 */
065 public Collection getPRs() {
066 return Collections.unmodifiableList(prList);
067 }
068
069 /**
070 * Populates this controller from a collection of {@link ProcessingResource}s
071 * (optional operation).
072 *
073 * Controllers that are serializable must implement this method needed by GATE
074 * to restore the contents of the controllers.
075 *
076 * @throws UnsupportedOperationException
077 * if the <tt>setPRs</tt> method is not supported by this
078 * controller.
079 */
080 public void setPRs(Collection prs) {
081 prList.clear();
082 Iterator prIter = prs.iterator();
083 while(prIter.hasNext())
084 add((ProcessingResource)prIter.next());
085 }
086
087 public void add(int index, ProcessingResource pr) {
088 prList.add(index, pr);
089 fireResourceAdded(new ControllerEvent(this, ControllerEvent.RESOURCE_ADDED,
090 pr));
091 }
092
093 public void add(ProcessingResource pr) {
094 prList.add(pr);
095 fireResourceAdded(new ControllerEvent(this, ControllerEvent.RESOURCE_ADDED,
096 pr));
097 }
098
099 public ProcessingResource remove(int index) {
100 ProcessingResource aPr = (ProcessingResource)prList.remove(index);
101 fireResourceRemoved(new ControllerEvent(this,
102 ControllerEvent.RESOURCE_REMOVED, aPr));
103 return aPr;
104 }
105
106 public boolean remove(ProcessingResource pr) {
107 boolean ret = prList.remove(pr);
108 if(ret)
109 fireResourceRemoved(new ControllerEvent(this,
110 ControllerEvent.RESOURCE_REMOVED, pr));
111 return ret;
112 }
113
114 public ProcessingResource set(int index, ProcessingResource pr) {
115 return (ProcessingResource)prList.set(index, pr);
116 }
117
118 /**
119 * Verifies that all PRs have all their required rutime parameters set.
120 */
121 protected void checkParameters() throws ExecutionException {
122 List badPRs;
123 try {
124 badPRs = getOffendingPocessingResources();
125 }
126 catch(ResourceInstantiationException rie) {
127 throw new ExecutionException(
128 "Could not check runtime parameters for the processing resources:\n"
129 + rie.toString());
130 }
131 if(badPRs != null && !badPRs.isEmpty()) { throw new ExecutionException(
132 "Some of the processing resources in this controller have unset "
133 + "runtime parameters:\n" + badPRs.toString()); }
134 }
135
136 /** Run the Processing Resources in sequence. */
137 protected void executeImpl() throws ExecutionException {
138 // check all the PRs have the right parameters
139 checkParameters();
140
141 if(log.isDebugEnabled()) {
142 prof.initRun("Execute controller [" + getName() + "]");
143 }
144
145 // execute all PRs in sequence
146 interrupted = false;
147 for(int i = 0; i < prList.size(); i++) {
148 if(isInterrupted()) {
149
150 throw new ExecutionInterruptedException("The execution of the "
151 + getName() + " application has been abruptly interrupted!"); }
152
153 runComponent(i);
154 if(log.isDebugEnabled()) {
155 prof.checkPoint("~Execute PR ["
156 + ((ProcessingResource)prList.get(i)).getName() + "]");
157 Long timeOfPR =
158 (Long)timeMap.get(((ProcessingResource)prList.get(i)).getName());
159 if(timeOfPR == null)
160 timeMap.put(((ProcessingResource)prList.get(i)).getName(), new Long(
161 prof.getLastDuration()));
162 else timeMap.put(((ProcessingResource)prList.get(i)).getName(),
163 new Long(timeOfPR.longValue() + prof.getLastDuration()));
164 log.debug("Time taken so far by "
165 + ((ProcessingResource)prList.get(i)).getName() + ": "
166 + timeMap.get(((ProcessingResource)prList.get(i)).getName()));
167
168 }
169 }
170
171 if(log.isDebugEnabled()) {
172 prof.checkPoint("Execute controller [" + getName() + "] finished");
173 }
174 fireStatusChanged("Finished running " + getName());
175
176 } // executeImpl()
177
178 /**
179 * Resets the Time taken by various PRs
180 */
181 public void resetPrTimeMap() {
182 prTimeMap.clear();
183 }
184
185 /**
186 * Returns the HashMap that lists the total time taken by each PR
187 * @return
188 */
189 public HashMap<String, Long> getPrTimeMap() {
190 return this.prTimeMap;
191 }
192
193 /**
194 * Executes a {@link ProcessingResource}.
195 */
196 protected void runComponent(int componentIndex) throws ExecutionException {
197 ProcessingResource currentPR =
198 (ProcessingResource)prList.get(componentIndex);
199
200 // create the listeners
201 FeatureMap listeners = Factory.newFeatureMap();
202 listeners.put("gate.event.StatusListener", sListener);
203 int componentProgress = 100 / prList.size();
204 listeners.put("gate.event.ProgressListener", new IntervalProgressListener(
205 componentIndex * componentProgress, (componentIndex + 1)
206 * componentProgress));
207
208 // add the listeners
209 try {
210 AbstractResource.setResourceListeners(currentPR, listeners);
211 }
212 catch(Exception e) {
213 // the listeners setting failed; nothing important
214 log.error("Could not set listeners for " + currentPR.getClass().getName()
215 + "\n" + e.toString() + "\n...nothing to lose any sleep over.");
216 }
217
218 benchmarkFeatures.put(Benchmark.PR_NAME_FEATURE, currentPR.getName());
219
220 long startTime = System.currentTimeMillis();
221 // run the thing
222 Benchmark.executeWithBenchmarking(currentPR,
223 Benchmark.createBenchmarkId(Benchmark.PR_PREFIX + currentPR.getName(),
224 getBenchmarkId()), this, benchmarkFeatures);
225
226 benchmarkFeatures.remove(Benchmark.PR_NAME_FEATURE);
227
228 // calculate the time taken by the PR
229 long timeTakenByThePR = System.currentTimeMillis() - startTime;
230 Long time = prTimeMap.get(currentPR.getName());
231 if(time == null) {
232 time = new Long(0);
233 }
234 time = new Long(time.longValue() + timeTakenByThePR);
235 prTimeMap.put(currentPR.getName(), time);
236
237
238 // remove the listeners
239 try {
240 AbstractResource.removeResourceListeners(currentPR, listeners);
241 }
242 catch(Exception e) {
243 // the listeners removing failed; nothing important
244 log.error("Could not clear listeners for "
245 + currentPR.getClass().getName() + "\n" + e.toString()
246 + "\n...nothing to lose any sleep over.");
247 }
248 }// protected void runComponent(int componentIndex)
249
250 /**
251 * Cleans the internal data and prepares this object to be collected
252 */
253 public void cleanup() {
254 //stop listening to Creole events.
255 Gate.getCreoleRegister().removeCreoleListener(this);
256 // close all PRs in this controller, if not members of other apps.
257 if(prList != null && !prList.isEmpty()) {
258 try {
259 //get all the other controllers
260 List<Resource> allOtherControllers =
261 Gate.getCreoleRegister().getAllInstances("gate.Controller");
262 allOtherControllers.remove(this);
263 //get all the PRs in all the other controllers
264 List<Resource> prsInOtherControllers = new ArrayList<Resource>();
265 for(Resource aController : allOtherControllers){
266 prsInOtherControllers.addAll(((Controller)aController).getPRs());
267 }
268 //remove all PRs in this controller, that are not also in other
269 //controllers
270 // for(Iterator prIter = getPRs().iterator(); prIter.hasNext();){
271 // ProcessingResource aPr = (ProcessingResource)prIter.next();
272 // if(!prsInOtherControllers.contains(aPr)){
273 // prIter.remove();
274 // Factory.deleteResource((Resource)aPr);
275 // }
276 // }
277 for(Object aPr : new ArrayList(getPRs())){
278 if(!prsInOtherControllers.contains(aPr)){
279 Factory.deleteResource((Resource)aPr);
280 }
281 }
282 }
283 catch(GateException e) {
284 //ignore
285 }
286 }
287 }
288
289 /**
290 * Duplicate this controller. We perform a default duplication of
291 * the controller itself, then recursively duplicate its contained
292 * PRs and add these duplicates to the copy.
293 */
294 public Resource duplicate(Factory.DuplicationContext ctx)
295 throws ResourceInstantiationException {
296 // duplicate this controller in the default way - this handles
297 // subclasses nicely
298 Controller c = (Controller)Factory.defaultDuplicate(this, ctx);
299
300 // duplicate each of our PRs
301 List<ProcessingResource> newPRs = new ArrayList<ProcessingResource>();
302 for(Object pr : prList) {
303 newPRs.add((ProcessingResource)Factory.duplicate((Resource)pr, ctx));
304 }
305 // and set this duplicated list as the PRs of the copy
306 c.setPRs(newPRs);
307
308 return c;
309 }
310
311 /** The list of contained PRs */
312 protected List prList;
313
314 /** A proxy for status events */
315 protected StatusListener sListener;
316
317 public void resourceLoaded(CreoleEvent e) {
318 }
319
320 public void resourceUnloaded(CreoleEvent e) {
321 // remove all occurences of the resource from this controller
322 if(e.getResource() instanceof ProcessingResource)
323 // while(prList.remove(e.getResource()));
324 // remove all occurrences of this PR from the controller
325 // Use the controller's remove method (rather than prList's so that
326 // subclasses of this controller type can add their own functionality
327 while(remove((ProcessingResource)e.getResource()))
328 ;
329 // remove links in parameters
330 for(int i = 0; i < prList.size(); i++) {
331 ProcessingResource aPr = (ProcessingResource)prList.get(i);
332 ResourceData rData =
333 (ResourceData)Gate.getCreoleRegister().get(aPr.getClass().getName());
334 if(rData != null) {
335 Iterator rtParamDisjIter =
336 rData.getParameterList().getRuntimeParameters().iterator();
337 while(rtParamDisjIter.hasNext()) {
338 List aDisjunction = (List)rtParamDisjIter.next();
339 Iterator rtParamIter = aDisjunction.iterator();
340 while(rtParamIter.hasNext()) {
341 Parameter aParam = (Parameter)rtParamIter.next();
342 String paramName = aParam.getName();
343 try {
344 if(aPr.getParameterValue(paramName) == e.getResource()) {
345 aPr.setParameterValue(paramName, null);
346 }
347 }
348 catch(ResourceInstantiationException rie) {
349 // nothing to do - this should never happen
350 throw new GateRuntimeException(rie);
351 }
352 }
353 }
354 }
355 }
356 }
357
358 public void resourceRenamed(Resource resource, String oldName, String newName) {
359 }
360
361 public void datastoreOpened(CreoleEvent e) {
362 }
363
364 public void datastoreCreated(CreoleEvent e) {
365 }
366
367 public void datastoreClosed(CreoleEvent e) {
368 }
369
370 } // class SerialController
|