1   /*
2    *  SinglePhaseTransducer.java - transducer class
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, 24/07/98
12   *
13   *  $Id: SinglePhaseTransducer.java,v 1.74 2004/07/21 17:10:08 akshay Exp $
14   */
15  
16  
17  package gate.jape;
18  
19  import java.util.*;
20  
21  import gate.*;
22  import gate.annotation.AnnotationSetImpl;
23  import gate.creole.ExecutionException;
24  import gate.creole.ExecutionInterruptedException;
25  import gate.event.ProgressListener;
26  import gate.fsm.*;
27  import gate.util.*;
28  
29  // by Shafirin Andrey start
30  import debugger.resources.pr.TraceContainer;
31  import debugger.resources.pr.RuleTrace;
32  import debugger.resources.SPTLock;
33  import debugger.resources.PhaseController;
34  // by Shafirin Andrey end
35  
36  /**
37    * Represents a complete CPSL grammar, with a phase name, options and
38    * rule set (accessible by name and by sequence).
39    * Implements a transduce method taking a Document as input.
40    * Constructs from String or File.
41    */
42  public class SinglePhaseTransducer
43  extends Transducer implements JapeConstants, java.io.Serializable
44  {
45    /** Debug flag */
46    private static final boolean DEBUG = false;
47  
48  // by Shafirin Andrey start
49      PhaseController phaseController = null;
50      TraceContainer rulesTrace = null;
51      RuleTrace currRuleTrace = null;
52  
53      public PhaseController getPhaseController() {
54          return phaseController;
55      }
56  
57      public void setPhaseController(PhaseController phaseController) {
58          this.phaseController = phaseController;
59      }
60  // by Shafirin Andrey end
61  
62  
63    /** Construction from name. */
64    public SinglePhaseTransducer(String name) {
65      this.name = name;
66      rules = new PrioritisedRuleList();
67      finishedAlready = false;
68    } // Construction from name
69  
70    /** Type of rule application (constants defined in JapeConstants). */
71    private int ruleApplicationStyle = BRILL_STYLE;
72  
73    /** Set the type of rule application (types defined in JapeConstants). */
74    public void setRuleApplicationStyle(int style) {
75      ruleApplicationStyle = style;
76    }
77  
78    /** The list of rules in this transducer. Ordered by priority and
79      * addition sequence (which will be file position if they come from
80      * a file).
81      */
82    private PrioritisedRuleList rules;
83  
84    FSM fsm;
85  
86    public FSM getFSM(){
87      return fsm;
88    }
89  
90    /** Add a rule. */
91    public void addRule(Rule rule) {
92      rules.add(rule);
93    } // addRule
94  
95    /** The values of any option settings given. */
96    private java.util.HashMap optionSettings = new java.util.HashMap();
97  
98    /** Add an option setting. If this option is set already, the new
99      * value overwrites the previous one.
100     */
101   public void setOption(String name, String setting) {
102     optionSettings.put(name, setting);
103   } // setOption
104 
105   /** Get the value for a particular option. */
106   public String getOption(String name) {
107     return (String) optionSettings.get(name);
108   } // getOption
109 
110   /** Whether the finish method has been called or not. */
111   private boolean finishedAlready;
112 
113   /** Finish: replace dynamic data structures with Java arrays; called
114     * after parsing.
115     */
116    public void finish() {
117      // both MPT and SPT have finish called on them by the parser...
118      if (finishedAlready)
119        return;
120      else
121        finishedAlready = true;
122 
123        //each rule has a RHS which has a string for java code
124        //those strings need to be compiled now
125      Map actionClasses = new HashMap(rules.size());
126      for (Iterator i = rules.iterator(); i.hasNext(); ) {
127        Rule rule = (Rule) i.next();
128        rule.finish();
129        actionClasses.put(rule.getRHS().getActionClassName(),
130                          rule.getRHS().getActionClassString());
131      }
132      try{
133        gate.util.Javac.loadClasses(actionClasses);
134      }catch(Exception e){
135        throw new GateRuntimeException(
136           "Compile error while loading Jape transducer \"" + name + "\"!");
137      }
138 
139     //build the finite state machine transition graph
140     fsm = new FSM(this);
141     //clear the old style data structures
142     rules.clear();
143     rules = null;
144   } // finish
145 
146 //dam: was
147 //  private void addAnnotationsByOffset(Map map, SortedSet keys, Set annotations){
148   private void addAnnotationsByOffset(/*Map map,*/ SimpleSortedSet keys, Set annotations){
149     Iterator annIter = annotations.iterator();
150     while(annIter.hasNext()){
151       Annotation ann = (Annotation)annIter.next();
152       //ignore empty annotations
153       long offset = ann.getStartNode().getOffset().longValue();
154       if(offset == ann.getEndNode().getOffset().longValue())
155         continue;
156 //dam: was
157 /*
158 //      Long offset = ann.getStartNode().getOffset();
159 
160       List annsAtThisOffset = null;
161       if(keys.add(offset)){
162         annsAtThisOffset = new LinkedList();
163         map.put(offset, annsAtThisOffset);
164       }else{
165         annsAtThisOffset = (List)map.get(offset);
166       }
167       annsAtThisOffset.add(ann);
168 */
169 //dam: end
170       keys.add(offset, ann);
171     }
172   }//private void addAnnotationsByOffset()
173 
174 
175   /**
176     * Transduce a document using the annotation set provided and the current
177     * rule application style.
178     */
179   public void transduce(Document doc, AnnotationSet inputAS,
180                         AnnotationSet outputAS) throws JapeException,
181                                                        ExecutionException {
182     interrupted = false;
183     fireProgressChanged(0);
184 
185     //the input annotations will be read from this map
186     //maps offset to list of annotations
187     SimpleSortedSet offsets = new SimpleSortedSet();
188     SimpleSortedSet annotationsByOffset = offsets;
189 
190     //select only the annotations of types specified in the input list
191     if(input.isEmpty()) {
192         addAnnotationsByOffset(offsets, inputAS);
193     } else {
194       Iterator typesIter = input.iterator();
195       AnnotationSet ofOneType = null;
196       while(typesIter.hasNext()){
197         ofOneType = inputAS.get((String)typesIter.next());
198         if(ofOneType != null){
199           addAnnotationsByOffset(offsets, ofOneType);
200         }
201       }
202     }
203 
204     if(annotationsByOffset.isEmpty()){
205       fireProcessFinished();
206       return;
207     }
208 
209     annotationsByOffset.sort();
210     //define data structures
211     //FSM instances that haven't blocked yet
212     java.util.ArrayList activeFSMInstances = new java.util.ArrayList();
213 
214     // FSM instances that have reached a final state
215     // This is a list and the contained objects are sorted by the length
216     // of the document content covered by the matched annotations
217     java.util.ArrayList acceptingFSMInstances = new ArrayList();
218     FSMInstance currentFSM;
219 
220 
221     //find the first node of the document
222     Node startNode = ((Annotation)
223             ((ArrayList)annotationsByOffset.get(offsets.first())).get(0)).
224             getStartNode();
225 
226     //used to calculate the percentage of processing done
227     long lastNodeOff = doc.getContent().size().longValue();
228 
229     //the offset of the node where the matching currently starts
230     //the value -1 marks no more annotations to parse
231     long startNodeOff = startNode.getOffset().longValue();
232 
233     //used to decide when to fire progress events
234     long oldStartNodeOff = 0;
235 
236     // by Shafirin Andrey start (according to Vladimir Karasev)
237     if (gate.Gate.isEnableJapeDebug()) {
238       // by Shafirin Andrey --> if (null != phaseController) {
239       if (null != phaseController) {
240         rulesTrace = new TraceContainer();
241         rulesTrace.putPhaseCut(this, inputAS);
242       }
243     }
244     // by Shafirin Andrey end
245 
246     //the big while for the actual parsing
247     while(startNodeOff != -1){
248       //while there are more annotations to parse
249       //create initial active FSM instance starting parsing from new startNode
250       //currentFSM = FSMInstance.getNewInstance(
251       currentFSM = new FSMInstance(
252                   fsm,
253                   fsm.getInitialState(),//fresh start
254                   startNode,//the matching starts form the current startNode
255                   startNode,//current position in AG is the start position
256                   new java.util.HashMap(),//no bindings yet!
257                   doc
258                   );
259 
260       // at this point ActiveFSMInstances should always be empty!
261       activeFSMInstances.clear();
262       acceptingFSMInstances.clear();
263       activeFSMInstances.add(currentFSM);
264 
265       //far each active FSM Instance, try to advance
266       whileloop2:
267       while(!activeFSMInstances.isEmpty()){
268         if(interrupted) throw new ExecutionInterruptedException(
269           "The execution of the \"" + getName() +
270           "\" Jape transducer has been abruptly interrupted!");
271 
272         // take the first active FSM instance
273         currentFSM = (FSMInstance)activeFSMInstances.remove(0);
274 
275         // process the current FSM instance
276         if(currentFSM.getFSMPosition().isFinal()){
277           //the current FSM is in a final state
278           acceptingFSMInstances.add(currentFSM.clone());
279           //if we're only looking for the shortest stop here
280           if(ruleApplicationStyle == FIRST_STYLE) break whileloop2;
281         }
282 
283         //get all the annotations that start where the current FSM finishes
284         SimpleSortedSet offsetsTailSet = offsets.tailSet(currentFSM.
285                 getAGPosition().getOffset().longValue());
286         ArrayList paths;
287         long theFirst = offsetsTailSet.first();
288         if(theFirst <0) continue;
289         paths = (ArrayList)annotationsByOffset.get(theFirst);
290         if(paths.isEmpty()) continue;
291         Iterator pathsIter = paths.iterator();
292         Annotation onePath;
293         State currentState = currentFSM.getFSMPosition();
294         Iterator transitionsIter;
295         //foreach possible annotation
296         while(pathsIter.hasNext()){
297           onePath = (Annotation)pathsIter.next();
298           transitionsIter = currentState.getTransitions().iterator();
299           Transition currentTransition;
300           Constraint[] currentConstraints;
301           transitionsWhile:
302           while(transitionsIter.hasNext()){
303             currentTransition = (Transition)transitionsIter.next();
304             //check if the current transition can use the current annotation (path)
305             currentConstraints =
306                          currentTransition.getConstraints().getConstraints();
307             String annType;
308             //introduce index of the constraint to process
309             int currentConstraintsindex = -1;
310             //we assume that all annotations in a constraint are of the same type
311             for(int i = 0; i<currentConstraints.length; i++){
312               annType = currentConstraints[i].getAnnotType();
313               //if wrong type try next transition
314               if(!annType.equals(onePath.getType()))continue transitionsWhile;
315               currentConstraintsindex = i;
316               break;
317             }
318 
319             /* ontotext.bp: always try to subsume using an ontology; */
320             /*if null then the ordinary subsume method is started*/
321             if(onePath.getFeatures().
322                     subsumes(ontology,
323                              currentConstraints[currentConstraintsindex].
324                              getAttributeSeq())){
325               //we have a match
326               //create a new FSMInstance, advance it over the current annotation
327               //take care of the bindings  and add it to ActiveFSM
328               FSMInstance newFSMI = (FSMInstance)currentFSM.clone();
329               newFSMI.setAGPosition(onePath.getEndNode());
330               newFSMI.setFSMPosition(currentTransition.getTarget());
331 
332               // by Shafirin Andrey start (according to Vladimir Karasev)
333               if(gate.Gate.isEnableJapeDebug()) {
334                 if (null != phaseController) {
335                   currRuleTrace = rulesTrace.getStateContainer(currentFSM.
336                       getFSMPosition());
337                   if (currRuleTrace == null) {
338                     currRuleTrace = new RuleTrace(newFSMI.getFSMPosition(), doc);
339                     currRuleTrace.addAnnotation(onePath);
340                     currRuleTrace.putPattern(onePath,
341                                              currentConstraints[currentConstraintsindex].
342                                              getAttributeSeq());
343                     rulesTrace.add(currRuleTrace);
344                   }
345                   else {
346                     currRuleTrace.addState(newFSMI.getFSMPosition());
347                     currRuleTrace.addAnnotation(onePath);
348                     currRuleTrace.putPattern(onePath,
349                                              currentConstraints[currentConstraintsindex].
350                                              getAttributeSeq());
351                   }
352                 }
353               }
354               // by Shafirin Andrey end
355 
356               //bindings
357               java.util.Map binds = newFSMI.getBindings();
358               java.util.Iterator labelsIter =
359                                  currentTransition.getBindings().iterator();
360               String oneLabel;
361               AnnotationSet boundAnnots, newSet;
362               while(labelsIter.hasNext()){
363                 oneLabel = (String)labelsIter.next();
364                 boundAnnots = (AnnotationSet)binds.get(oneLabel);
365                 if(boundAnnots != null)
366                   newSet = new AnnotationSetImpl((AnnotationSet)boundAnnots);
367                 else
368                   newSet = new AnnotationSetImpl(doc);
369                 newSet.add(onePath);
370                 binds.put(oneLabel, newSet);
371 
372               }//while(labelsIter.hasNext())
373               activeFSMInstances.add(newFSMI);
374             }//if match
375           }//while(transitionsIter.hasNext())
376         }//while(pathsIter.hasNext())
377       }//while(!activeFSMInstances.isEmpty())
378 
379       //FIRE THE RULE
380       long lastAGPosition = -1;
381       if(acceptingFSMInstances.isEmpty()){
382         //no rule to fire, advance to the next input offset
383         lastAGPosition = startNodeOff + 1;
384       } else if(ruleApplicationStyle == BRILL_STYLE) {
385         // fire the rules corresponding to all accepting FSM instances
386         java.util.Iterator accFSMIter = acceptingFSMInstances.iterator();
387         FSMInstance currentAcceptor;
388         RightHandSide currentRHS;
389         lastAGPosition = startNode.getOffset().longValue();
390 
391         while(accFSMIter.hasNext()){
392           currentAcceptor = (FSMInstance) accFSMIter.next();
393           currentRHS = currentAcceptor.getFSMPosition().getAction();
394 
395           // by Shafirin Andrey start
396           // debugger callback
397           if (gate.Gate.isEnableJapeDebug()) {
398             if (null != phaseController) {
399               SPTLock lock = new SPTLock();
400               phaseController.TraceTransit(rulesTrace);
401               rulesTrace = new TraceContainer();
402               phaseController.RuleMatched(lock, this, currentRHS, doc,
403                                           currentAcceptor.getBindings(),
404                                           inputAS, outputAS);
405             }
406           }
407           // by Shafirin Andrey end
408 
409           currentRHS.transduce(doc, currentAcceptor.getBindings(),
410                                inputAS, outputAS, ontology);
411 
412           // by Shafirin Andrey start
413           // debugger callback
414           if (gate.Gate.isEnableJapeDebug()) {
415             if (null != phaseController) {
416               SPTLock lock = new SPTLock();
417               phaseController.RuleFinished(lock, this, currentRHS, doc,
418                                            currentAcceptor.getBindings(),
419                                            inputAS, outputAS);
420             }
421           }
422           // by Shafirin Andrey end
423 
424           long currentAGPosition = currentAcceptor.getAGPosition().getOffset().longValue();
425           if(currentAGPosition > lastAGPosition)
426             lastAGPosition = currentAGPosition;
427         }
428       } else if(ruleApplicationStyle == APPELT_STYLE ||
429                 ruleApplicationStyle == FIRST_STYLE ||
430                 ruleApplicationStyle == ONCE_STYLE) {
431 
432         // AcceptingFSMInstances is an ordered structure:
433         // just execute the longest (last) rule
434         Collections.sort(acceptingFSMInstances, Collections.reverseOrder());
435         Iterator accFSMIter = acceptingFSMInstances.iterator();
436         FSMInstance currentAcceptor = (FSMInstance)accFSMIter.next();
437         if(isDebugMode()){
438           //see if we have any conflicts
439           Iterator accIter = acceptingFSMInstances.iterator();
440           FSMInstance anAcceptor;
441           List conflicts = new ArrayList();
442           while(accIter.hasNext()){
443             anAcceptor = (FSMInstance)accIter.next();
444             if(anAcceptor.equals(currentAcceptor)){
445               conflicts.add(anAcceptor);
446             }else{
447               break;
448             }
449           }
450           if(conflicts.size() > 1){
451             Out.prln("\nConflicts found during matching:" +
452                      "\n================================");
453             accIter = conflicts.iterator();
454             int i = 0;
455             while(accIter.hasNext()){
456               Out.prln(i++ + ") " + accIter.next().toString());
457             }
458           }
459         }
460         RightHandSide currentRHS = currentAcceptor.getFSMPosition().getAction();
461 
462         // by Shafirin Andrey start
463         // debugger callback
464         if(gate.Gate.isEnableJapeDebug()) {
465           if (null != phaseController) {
466             SPTLock lock = new SPTLock();
467             rulesTrace.leaveLast(currentRHS);
468             phaseController.TraceTransit(rulesTrace);
469             rulesTrace = new TraceContainer();
470             phaseController.RuleMatched(lock, this, currentRHS, doc,
471                                         currentAcceptor.getBindings(),
472                                         inputAS, outputAS);
473           }
474         }
475         // by Shafirin Andrey end
476 
477         currentRHS.transduce(doc, currentAcceptor.getBindings(),
478                              inputAS, outputAS, ontology);
479 
480         // by Shafirin Andrey start
481         // debugger callback
482         if(gate.Gate.isEnableJapeDebug()) {
483           if (null != phaseController) {
484             SPTLock lock = new SPTLock();
485             phaseController.RuleFinished(lock, this, currentRHS, doc,
486                                          currentAcceptor.getBindings(),
487                                          inputAS, outputAS);
488           }
489         }
490         // by Shafirin Andrey end
491 
492         //if in matchGroup mode check other possible patterns in this span
493         if(isMatchGroupMode()) {
494           //Out.prln("Jape grammar in MULTI application style.");
495           // ~bp:  check for other matching fsm instances with same length,
496           // priority and rule index : if such execute them also.
497           String currentAcceptorString = null;
498           multiModeWhile: while(accFSMIter.hasNext()) {
499             FSMInstance rivalAcceptor =(FSMInstance) accFSMIter.next();
500             //get rivals that match the same document segment
501             //makes use of the semantic difference between the compareTo and 
502             //equals methods on FSMInstance
503             if(rivalAcceptor.compareTo(currentAcceptor)==0){
504               // gets the rivals that are NOT COMPLETELY IDENTICAL with the
505               // current acceptor.
506               if(!rivalAcceptor.equals(currentAcceptor)){
507                 if (isDebugMode()){ /*depends on the debug option in the transducer */
508                   if (currentAcceptorString == null) {
509                     // first rival
510                     currentAcceptorString = currentAcceptor.toString();
511                     Out.prln("~Jape Grammar Transducer : "+
512                     "\nConcurrent Patterns by length,priority and index (all transduced):");
513                     Out.prln(currentAcceptorString);
514                     Out.prln("bindings : "+currentAcceptor.getBindings());
515                     Out.prln("Rivals Follow: ");
516                   }
517                   Out.prln(rivalAcceptor);
518                   Out.prln("bindings : "+rivalAcceptor.getBindings());
519                 }// DEBUG
520                 currentRHS = rivalAcceptor.getFSMPosition().getAction();
521   
522                 // by Shafirin Andrey start
523                 // debugger callback
524                 if(gate.Gate.isEnableJapeDebug()) {
525                   if (null != phaseController) {
526                     SPTLock lock = new SPTLock();
527                     rulesTrace.leaveLast(currentRHS);
528                     phaseController.TraceTransit(rulesTrace);
529                     rulesTrace = new TraceContainer();
530                     phaseController.RuleMatched(lock, this, currentRHS, doc,
531                                                 rivalAcceptor.getBindings(),
532                                                 inputAS, outputAS);
533                   }
534                 }
535                 // by Shafirin Andrey end
536   
537                 currentRHS.transduce(doc, rivalAcceptor.getBindings(),
538                                      inputAS, outputAS, ontology);
539   
540                 // by Shafirin Andrey start
541                 // debugger callback
542                 if(gate.Gate.isEnableJapeDebug()) {
543                   if (null != phaseController) {
544                     SPTLock lock = new SPTLock();
545                     phaseController.RuleFinished(lock, this, currentRHS, doc,
546                                                  rivalAcceptor.getBindings(),
547                                                  inputAS, outputAS);
548                   }
549                 }
550                 // by Shafirin Andrey end
551               } // equal rival
552             }else{
553               //if rival is not equal this means that there are no further
554               // equal rivals (since the list is sorted)
555               break multiModeWhile;
556             }
557           } // while there are fsm instances
558         } // matchGroupMode
559 
560         //if in ONCE mode stop after first match
561         if(ruleApplicationStyle == ONCE_STYLE) return;
562 
563         //advance in AG
564         lastAGPosition = currentAcceptor.getAGPosition().getOffset().longValue();
565       }else throw new RuntimeException("Unknown rule application style!");
566 
567 
568       //advance on input
569       SimpleSortedSet OffsetsTailSet = offsets.tailSet(lastAGPosition);
570       long theFirst = OffsetsTailSet.first();
571       if( theFirst < 0){
572         //no more input, phew! :)
573         startNodeOff = -1;
574         fireProcessFinished();
575       }else{
576         long nextKey = theFirst;
577         startNode = ((Annotation)
578                       ((ArrayList)annotationsByOffset.get(nextKey)).get(0)). //nextKey
579                     getStartNode();
580         startNodeOff = startNode.getOffset().longValue();
581 
582         //eliminate the possibility for infinite looping
583         if(oldStartNodeOff == startNodeOff){
584           //we are about to step twice in the same place, ...skip ahead
585           lastAGPosition = startNodeOff + 1;
586           OffsetsTailSet = offsets.tailSet(lastAGPosition);
587           theFirst = OffsetsTailSet.first();
588           if(theFirst < 0){
589             //no more input, phew! :)
590             startNodeOff = -1;
591             fireProcessFinished();
592           }else{
593             nextKey = theFirst;
594             startNode = ((Annotation)
595                           ((List)annotationsByOffset.get(theFirst)).get(0)).
596                         getStartNode();
597             startNodeOff =startNode.getOffset().longValue();
598           }
599         }//if(oldStartNodeOff == startNodeOff)
600         //fire the progress event
601         if(startNodeOff - oldStartNodeOff > 256){
602           if(isInterrupted()) throw new ExecutionInterruptedException(
603             "The execution of the \"" + getName() +
604             "\" Jape transducer has been abruptly interrupted!");
605 
606           fireProgressChanged((int)(100 * startNodeOff / lastNodeOff));
607           oldStartNodeOff = startNodeOff;
608         }
609       }
610     }//while(startNodeOff != -1)
611     fireProcessFinished();
612 
613     // by Shafirin Andrey start (according to Vladimir Karasev)
614     if(gate.Gate.isEnableJapeDebug()) {
615       if (null != phaseController) {
616         phaseController.TraceTransit(rulesTrace);
617       }
618     }
619     // by Shafirin Andrey end
620 
621   } // transduce
622 
623 
624   /** Clean up (delete action class files, for e.g.). */
625   public void cleanUp() {
626 //    for(DListIterator i = rules.begin(); ! i.atEnd(); i.advance())
627 //      ((Rule) i.get()).cleanUp();
628   } // cleanUp
629 
630   /** A string representation of this object. */
631   public String toString() {
632     return toString("");
633   } // toString()
634 
635   /** A string representation of this object. */
636   public String toString(String pad) {
637     String newline = Strings.getNl();
638     String newPad = Strings.addPadding(pad, INDENT_PADDING);
639 
640     StringBuffer buf =
641       new StringBuffer(pad + "SPT: name(" + name + "); ruleApplicationStyle(");
642 
643     switch(ruleApplicationStyle) {
644       case APPELT_STYLE: buf.append("APPELT_STYLE); "); break;
645       case BRILL_STYLE:  buf.append("BRILL_STYLE); ");  break;
646       default: break;
647     }
648 
649     buf.append("rules(" + newline);
650     Iterator rulesIterator = rules.iterator();
651     while(rulesIterator.hasNext())
652       buf.append(((Rule) rulesIterator.next()).toString(newPad) + " ");
653 
654     buf.append(newline + pad + ")." + newline);
655 
656     return buf.toString();
657   } // toString(pad)
658 
659   //needed by fsm
660   public PrioritisedRuleList getRules() {
661     return rules;
662   }
663 
664   /**
665     * Adds a new type of input annotations used by this transducer.
666     * If the list of input types is empty this transducer will parse all the
667     * annotations in the document otherwise the types not found in the input
668     * list will be completely ignored! To be used with caution!
669     */
670   public void addInput(String ident) {
671     input.add(ident);
672   }
673   public synchronized void removeProgressListener(ProgressListener l) {
674     if (progressListeners != null && progressListeners.contains(l)) {
675       Vector v = (Vector) progressListeners.clone();
676       v.removeElement(l);
677       progressListeners = v;
678     }
679   }
680   public synchronized void addProgressListener(ProgressListener l) {
681     Vector v = progressListeners == null ? new Vector(2) : (Vector) progressListeners.clone();
682     if (!v.contains(l)) {
683       v.addElement(l);
684       progressListeners = v;
685     }
686   }
687 
688   /**
689     * Defines the types of input annotations that this transducer reads. If this
690     * set is empty the transducer will read all the annotations otherwise it
691     * will only "see" the annotations of types found in this list ignoring all
692     * other types of annotations.
693     */
694  // by Shafirin Andrey start (modifier changed to public)
695   public java.util.Set input = new java.util.HashSet();
696   //java.util.Set input = new java.util.HashSet();
697   // by Shafirin Andrey end
698   private transient Vector progressListeners;
699 
700   protected void fireProgressChanged(int e) {
701     if (progressListeners != null) {
702       Vector listeners = progressListeners;
703       int count = listeners.size();
704       for (int i = 0; i < count; i++) {
705         ((ProgressListener) listeners.elementAt(i)).progressChanged(e);
706       }
707     }
708   }
709   protected void fireProcessFinished() {
710     if (progressListeners != null) {
711       Vector listeners = progressListeners;
712       int count = listeners.size();
713       for (int i = 0; i < count; i++) {
714         ((ProgressListener) listeners.elementAt(i)).processFinished();
715       }
716     }
717   }
718   public int getRuleApplicationStyle() {
719     return ruleApplicationStyle;
720   }
721 
722   /*
723   private void writeObject(ObjectOutputStream oos) throws IOException {
724     Out.prln("writing spt");
725     oos.defaultWriteObject();
726     Out.prln("finished writing spt");
727   } // writeObject
728   */
729 
730 
731 } // class SinglePhaseTransducer
732 
733 /*
734 class SimpleSortedSet {
735 
736     static final int INCREMENT = 1023;
737     int[] theArray = new int[INCREMENT];
738     Object[] theObject = new Object[INCREMENT];
739     int tsindex = 0;
740     int size = 0;
741     public static int avesize = 0;
742     public static int maxsize = 0;
743     public static int avecount = 0;
744     public SimpleSortedSet()
745     {
746         avecount++;
747         java.util.Arrays.fill(theArray, Integer.MAX_VALUE);
748     }
749 
750     public Object get(int elValue)
751     {
752         int index = java.util.Arrays.binarySearch(theArray, elValue);
753         if (index >=0)
754             return theObject[index];
755         return null;
756     }
757 
758     public boolean add(int elValue, Object o)
759     {
760         int index = java.util.Arrays.binarySearch(theArray, elValue);
761         if (index >=0)
762         {
763             ((ArrayList)theObject[index]).add(o);
764             return false;
765         }
766         if (size == theArray.length)
767         {
768             int[] temp = new int[theArray.length + INCREMENT];
769             Object[] tempO = new Object[theArray.length + INCREMENT];
770             System.arraycopy(theArray, 0, temp, 0, theArray.length);
771             System.arraycopy(theObject, 0, tempO, 0, theArray.length);
772             java.util.Arrays.fill(temp, theArray.length, temp.length , Integer.MAX_VALUE);
773             theArray = temp;
774             theObject = tempO;
775         }
776         index = ~index;
777         System.arraycopy(theArray, index, theArray, index+1, size - index );
778         System.arraycopy(theObject, index, theObject, index+1, size - index );
779         theArray[index] = elValue;
780         theObject[index] = new ArrayList();
781         ((ArrayList)theObject[index]).add(o);
782         size++;
783         return true;
784     }
785     public int first()
786     {
787         if (tsindex >= size) return -1;
788         return theArray[tsindex];
789     }
790 
791     public Object getFirst()
792     {
793         if (tsindex >= size) return null;
794         return theObject[tsindex];
795     }
796 
797     public SimpleSortedSet tailSet(int elValue)
798     {
799         if (tsindex < theArray.length && elValue != theArray[tsindex])
800         {
801             if (tsindex<(size-1) && elValue > theArray[tsindex] &&
802                 elValue <= theArray[tsindex+1])
803                 {
804                     tsindex++;
805                    return this;
806                 }
807             int index = java.util.Arrays.binarySearch(theArray, elValue);
808             if (index < 0)
809                 index = ~index;
810             tsindex = index;
811         }
812         return this;
813     }
814 
815     public boolean isEmpty()
816     {
817         return size ==0;
818     }
819 };
820 */