Batch.java
001 /*
002  * Batch.java - transducer class
003  
004  * Copyright (c) 1995-2012, 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 software,
008  * licenced under the GNU Library General Public License, Version 2, June 1991
009  * (in the distribution as file licence.html, and also available at
010  * http://gate.ac.uk/gate/licence.html).
011  
012  * Hamish Cunningham, 10/08/98
013  
014  * $Id: Batch.java 17768 2014-04-03 14:37:54Z markagreenwood $
015  
016  * DEVELOPER NOTES:
017  
018  * This is one that got away; the relation between constructors, initTransducer
019  * and parseTransducer are totally screwy and get worse every time I add
020  * something (e.g. support for resource loading). We should probably junk this
021  * whole thing and start again....
022  */
023 
024 package gate.jape;
025 
026 import gate.AnnotationSet;
027 import gate.Controller;
028 import gate.Corpus;
029 import gate.Document;
030 import gate.Factory;
031 import gate.Gate;
032 import gate.creole.ExecutionException;
033 import gate.creole.ontology.Ontology;
034 import gate.event.ProgressListener;
035 import gate.event.StatusListener;
036 import gate.util.Benchmarkable;
037 import gate.util.GateClassLoader;
038 
039 import java.io.IOException;
040 import java.net.URL;
041 import java.util.Iterator;
042 import java.util.Vector;
043 
044 /**
045  * Batch processing of JAPE transducers against documents or collections.
046  * Construction will parse or deserialise a transducer as required.
047  */
048 public class Batch implements JapeConstants, Benchmarkable {
049 
050   private static final long serialVersionUID = -5787362511680231837L;
051 
052   /** The URL that points to a .jape file */
053   private URL japeURL;
054 
055   /** The encoding used for reading the grammar file(s) */
056   private String encoding;
057 
058   /** The JAPE transducer. */
059   private Transducer transducer;
060 
061   private ActionContext actionContext;
062 
063   private transient GateClassLoader classLoader = null;
064 
065   public void setActionContext(ActionContext ac) {
066     actionContext = ac;
067   }
068 
069   @Override
070   public void finalize() throws Throwable {
071     Gate.getClassLoader().forgetClassLoader(classLoader);
072     super.finalize();
073   }
074 
075   /**
076    * Create a fully initialised instance.
077    <P>
078    <CODE>japeFileName</CODE>: the name of a .jape or .ser transducer file.
079    * This may be an absolute path, or may a .jar that lives somewhere on the
080    * classpath.
081    */
082   public Batch(URL url, String encodingthrows JapeException {
083     this.japeURL = url;
084     this.encoding = encoding;
085     this.classLoader =
086         Gate.getClassLoader().getDisposableClassLoader(
087             url.toExternalForm() + System.currentTimeMillis()true);
088     parseJape();
089     linkListeners();
090   // full init constructor
091 
092   public Batch(URL url, String encoding, StatusListener sListener)
093       throws JapeException {
094 
095     this.addStatusListener(sListener);
096     this.japeURL = url;
097     this.encoding = encoding;
098     this.classLoader =
099         Gate.getClassLoader().getDisposableClassLoader(
100             url.toExternalForm() + System.currentTimeMillis()true);
101     parseJape();
102     linkListeners();
103   // full init constructor
104 
105   private void readObject(java.io.ObjectInputStream inthrows IOException,
106       ClassNotFoundException {
107     classLoader = Gate.getClassLoader().getDisposableClassLoader(in.toString(),true);
108     in.defaultReadObject();
109     // now recreate the listeners
110     linkListeners();
111   }
112 
113   /**
114    * Creates inner listeners that forward events from the transducer object to
115    * our own listeners.
116    */
117   protected void linkListeners() {
118     if(transducer != null) {
119       transducer.addStatusListener(new StatusListener() {
120         @Override
121         public void statusChanged(String text) {
122           fireStatusChanged(text);
123         }
124       });
125 
126       transducer.addProgressListener(new ProgressListener() {
127         @Override
128         public void progressChanged(int value) {
129           fireProgressChanged(value);
130         }
131 
132         @Override
133         public void processFinished() {
134           fireProcessFinished();
135         }
136       });
137     }
138   }
139 
140   /**
141    * Notifies this PR that it should stop its execution as soon as possible.
142    */
143   public synchronized void interrupt() {
144     transducer.interrupt();
145   }
146 
147   /** Get the transducer. */
148   public Transducer getTransducer() {
149     return transducer;
150   }
151 
152   /** Parse a jape file from {@link #japeURL} and store the transducer. */
153   private void parseJape() throws JapeException {
154     try {
155       gate.jape.parser.ParseCpsl parser =
156           Factory.newJapeParser(japeURL, encoding);
157 
158       StatusListener listener = null;
159       listener = new StatusListener() {
160         @Override
161         public void statusChanged(String text) {
162           fireStatusChanged(text);
163         }
164       };
165       parser.addStatusListener(listener);
166       transducer = parser.MultiPhaseTransducer();
167       parser.removeStatusListener(listener);
168       // the call to finish needs to be handled from here now as it
169       // was removed from the .jj file
170       transducer.addStatusListener(listener);
171       transducer.finish(classLoader);
172       transducer.removeStatusListener(listener);
173 
174     catch(gate.jape.parser.ParseException e) {
175       throw new JapeException("Batch: error parsing transducer: "
176           + e.getMessage());
177     catch(java.io.IOException e) {
178       throw new JapeException("Batch: couldn't open JAPE file: "
179           + e.getMessage());
180     }
181   // parseJape
182 
183   /** Process the given collection. */
184   public void transduce(Corpus collthrows JapeException, ExecutionException {
185     // for each doc run the transducer
186     Iterator<Document> iter = coll.iterator();
187     while(iter.hasNext()) {
188       Document doc = iter.next();
189       transduce(doc, doc.getAnnotations(), doc.getAnnotations());
190     }
191   // transduce(coll)
192 
193   /** Process a single document. */
194   public void transduce(Document docthrows JapeException, ExecutionException {
195     transduce(doc, doc.getAnnotations(), doc.getAnnotations());
196   // transduce(doc)
197 
198   /** Process a single document. */
199   public void transduce(Document doc, AnnotationSet inputAS,
200       AnnotationSet outputASthrows JapeException, ExecutionException {
201     // no need to transduce empty document
202     if(inputAS == null || inputAS.isEmpty()) return;
203     transducer.setActionContext(actionContext);
204     transducer.transduce(doc, inputAS, outputAS);
205 
206   // transduce(doc)
207 
208   public void setFeatures(gate.FeatureMap newFeatures) {
209     features = newFeatures;
210   }
211 
212   public gate.FeatureMap getFeatures() {
213     return features;
214   }
215 
216   public synchronized void removeProgressListener(ProgressListener l) {
217     if(progressListeners != null && progressListeners.contains(l)) {
218       @SuppressWarnings("unchecked")
219       Vector<ProgressListener> v =
220           (Vector<ProgressListener>)progressListeners.clone();
221       v.removeElement(l);
222       progressListeners = v;
223     }
224   }
225 
226   public synchronized void addProgressListener(ProgressListener l) {
227     @SuppressWarnings("unchecked")
228     Vector<ProgressListener> v =
229         progressListeners == null
230             new Vector<ProgressListener>(2)
231             (Vector<ProgressListener>)progressListeners.clone();
232     if(!v.contains(l)) {
233       v.addElement(l);
234       progressListeners = v;
235     }
236   }
237 
238   // ProcessProgressReporter implementation ends here
239 
240   private gate.FeatureMap features;
241 
242   private transient Vector<ProgressListener> progressListeners;
243 
244   private transient Vector<StatusListener> statusListeners;
245 
246   private boolean enableDebugging;
247 
248   protected void fireProgressChanged(int e) {
249     if(progressListeners != null) {
250       int count = progressListeners.size();
251       for(int i = 0; i < count; i++) {
252         progressListeners.elementAt(i).progressChanged(e);
253       }
254     }
255   }
256 
257   protected void fireProcessFinished() {
258     if(progressListeners != null) {
259       int count = progressListeners.size();
260       for(int i = 0; i < count; i++) {
261         progressListeners.elementAt(i).processFinished();
262       }
263     }
264   }
265 
266   public synchronized void removeStatusListener(StatusListener l) {
267     if(statusListeners != null && statusListeners.contains(l)) {
268       @SuppressWarnings("unchecked")
269       Vector<StatusListener> v =
270           (Vector<StatusListener>)statusListeners.clone();
271       v.removeElement(l);
272       statusListeners = v;
273     }
274   }
275 
276   public synchronized void addStatusListener(StatusListener l) {
277     @SuppressWarnings("unchecked")
278     Vector<StatusListener> v =
279         statusListeners == null
280             new Vector<StatusListener>(2)
281             (Vector<StatusListener>)statusListeners.clone();
282     if(!v.contains(l)) {
283       v.addElement(l);
284       statusListeners = v;
285     }
286   }
287 
288   protected void fireStatusChanged(String e) {
289     if(statusListeners != null) {
290       int count = statusListeners.size();
291       for(int i = 0; i < count; i++) {
292         statusListeners.elementAt(i).statusChanged(e);
293       }
294     }
295   }
296 
297   /**
298    * Sets the ontology to be used by the transducers
299    
300    @param ontology
301    */
302   public void setOntology(gate.creole.ontology.Ontology ontology) {
303     transducer.setOntology(ontology);
304   }
305 
306   public boolean isEnableDebugging() {
307     return enableDebugging;
308   }
309 
310   public void setEnableDebugging(boolean enableDebugging) {
311     this.enableDebugging = enableDebugging;
312     // propagate
313     if(transducer != nulltransducer.setEnableDebugging(enableDebugging);
314   }
315 
316   @Override
317   public String getBenchmarkId() {
318     return transducer.getBenchmarkId();
319   }
320 
321   @Override
322   public void setBenchmarkId(String benchmarkId) {
323     transducer.setBenchmarkId(benchmarkId);
324   }
325 
326   public void runControllerExecutionAbortedBlock(ActionContext ac,
327       Controller c, Throwable t, Ontology othrows ExecutionException {
328     transducer.runControllerExecutionAbortedBlock(ac, c, t, o);
329   }
330 
331   public void runControllerExecutionFinishedBlock(ActionContext ac,
332       Controller c, Ontology othrows ExecutionException {
333     transducer.runControllerExecutionFinishedBlock(ac, c, o);
334   }
335 
336   public void runControllerExecutionStartedBlock(ActionContext ac,
337       Controller c, Ontology othrows ExecutionException {
338     transducer.runControllerExecutionStartedBlock(ac, c, o);
339   }
340 // class Batch