| FSMInstance.java |
1 /*
2 * FSMInstance.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 * Valentin Tablan, 05/May/2000
12 *
13 * $Id: FSMInstance.java,v 1.24 2004/07/21 17:10:06 akshay Exp $
14 */
15 package gate.fsm;
16
17 import java.io.Serializable;
18 import java.util.*;
19
20 import gate.*;
21 import gate.jape.RightHandSide;
22 import gate.util.Err;
23 import gate.util.InvalidOffsetException;
24
25 /**
26 * The objects of this class represent instances of working Finite State
27 * Machine during parsing a gate document (annotation set).
28 * In order to completely define the state a FSM is in one needs to store
29 * information regarding:
30 * -the position in the FSM transition graph
31 * -the position in the annotation graph
32 * -the set of bindings that occured up to the current state.
33 * note that a set of bindings is an object of type Map that maps names
34 * (java.lang.String) to bags of annotations (gate.AnnotationSet)
35 */
36 public class FSMInstance implements Comparable, Cloneable, Serializable {
37
38 /** Debug flag */
39 private static final boolean DEBUG = false;
40
41 /** Creates a new FSMInstance object.
42 * @param supportGraph the transition graph of the FSM
43 * @param FSMPosition the state this instance will be in
44 * @param startNode the node in the AnnotationSet where this FSM instance
45 * started the matching
46 * @param AGPosition the node in the AnnotationSet up to which this FSM Instance
47 * advanced during the matching.
48 * @param bindings a HashMap that maps from labels (objects of type String)
49 * to sets of annotations (objects of type AnnotationSet). This map stores
50 * all the bindings that took place during the matching process.
51 * This FSMInstance started the matching on an AnnotationSet from "startNode"
52 * and advanced to "AGPosition"; during this process it traversed the path in
53 * the transition graph "supportGraph" from the initial state to
54 * "FSMPosition" and made the bindings stored in "bindings".
55 */
56 public FSMInstance(FSM supportGraph, State FSMPosition,
57 Node startNode, Node AGPosition, HashMap bindings,
58 Document document) {
59
60 this.supportGraph = supportGraph;
61 this.FSMPosition = FSMPosition;
62 this.startNode = startNode;
63 this.AGPosition = AGPosition;
64 this.bindings = bindings;
65 this.document = document;
66 length = AGPosition.getOffset().longValue() -
67 startNode.getOffset().longValue();
68 fileIndex = FSMPosition.getFileIndex();
69 priority = FSMPosition.getPriority();
70 }
71
72 /** Returns the FSM transition graph that backs this FSM instance
73 * @return an FSM object
74 */
75 public FSM getSupportGraph(){ return supportGraph; }
76
77 /** Returns the position in the support graph for this FSM instance
78 * @return an object of type State
79 */
80 public State getFSMPosition(){ return FSMPosition; }
81
82 /** Sets the position in the support transition graph for this FSM instance
83 * Convenience method for when the state is not known at construction time.
84 */
85 public void setFSMPosition(State newFSMPos) {
86 FSMPosition = newFSMPos;
87 fileIndex = FSMPosition.getFileIndex();
88 priority = FSMPosition.getPriority();
89 }
90
91 /** Returns the index in the Jape definition file of the rule that caused
92 * the generation of the FSM state this instance is in.
93 * This value is correct if and only if this FSM instance is in a final
94 * state of the FSM transition graph.
95 * @return an int value.
96 */
97 public int getFileIndex(){ return fileIndex; }
98
99 /** Returns the node in the AnnotationSet from which this FSM instance
100 * started the matching process.
101 * @return a gate.Node object
102 */
103 public Node getStartAGPosition(){ return startNode; }
104
105 /** Returns the node up to which this FSM instance advanced in the
106 * Annotation graph during the matching process.
107 * @return a gate.Node object
108 */
109 public Node getAGPosition(){ return AGPosition; }
110
111 /** Sets the current position in the AnnotationSet.
112 * Convenience method for cases when this value is not known at construction
113 * time.
114 * @param node a position in the AnnotationSet
115 */
116 public void setAGPosition(Node node){
117 AGPosition = node;
118 length = AGPosition.getOffset().longValue() -
119 startNode.getOffset().longValue();
120 }
121
122 /** Gets the map representing the bindings that took place during the matching
123 * process this FSM instance performed.
124 * @return a HashMap object
125 */
126 public HashMap getBindings() { return bindings; }
127
128 /** Returns the length of the parsed region in the document under scrutiny.
129 * More precisely this is the distnace between the Node in the annotation
130 * graph where the matching started and the current position.
131 * @return a long value
132 */
133 public long getLength() { return length; }
134
135 /** Overrides the hashCode method from Object so this obejcts can be stored in
136 * hash maps and hash sets.
137 */
138 public int hashCode() {
139 return (int)length ^ priority ^ fileIndex ^ bindings.hashCode() ^
140 FSMPosition.getAction().hashCode();
141 }
142
143 public boolean equals(Object other){
144 if(other instanceof FSMInstance){
145 FSMInstance otherFSM = (FSMInstance)other;
146 boolean result = length == otherFSM.length &&
147 priority == otherFSM.priority &&
148 fileIndex == otherFSM.fileIndex &&
149 bindings.equals(otherFSM.bindings) &&
150 FSMPosition.getAction().equals(otherFSM.FSMPosition.getAction());
151 return result;
152 }else{
153 throw new ClassCastException(other.getClass().toString());
154 }
155 }
156
157 /** Returns a clone of this object.
158 * The cloning is done bitwise except for the bindings that are cloned by
159 * themselves
160 * @return an Object value that is actually a FSMInstance object
161 */
162 public Object clone() {
163 //do a classic clone except for bindings which need to be cloned themselves
164 try {
165 FSMInstance clone = (FSMInstance)super.clone();
166 clone.bindings = (HashMap)bindings.clone();
167 return clone;
168 } catch (CloneNotSupportedException cnse) {
169 cnse.printStackTrace(Err.getPrintWriter());
170 return null;
171 }
172 }
173
174 /*
175 public Object clone() {
176 //do a classic clone except for bindings which need to be cloned themselves
177 //Out.println("Clone!");
178 FSMInstance clone = FSMInstance.getNewInstance(this.supportGraph,
179 this.FSMPosition,
180 this.startNode,
181 this.AGPosition,
182 null);
183 clone.bindings = (HashMap)(bindings.clone());
184 return (FSMInstance)clone;
185 }
186 */
187
188 /** Implementation of the compareTo method required by the Comparable
189 * interface. The comparison is based on the size of the matched region and
190 * the index in the definition file of the rule associated to this FSM
191 * instance (which needs to be in a final state)
192 * The order imposed by this method is the priority needed in case of a
193 * multiple match.
194 */
195 public int compareTo(Object obj) {
196 if (obj instanceof FSMInstance) {
197 if(obj == this) return 0;
198 FSMInstance other = (FSMInstance)obj;
199 if(length < other.getLength()) return -1;
200 else if(length > other.getLength()) return 1;
201 //equal length
202 else if(priority < other.priority) return -1;
203 else if(priority > other.priority) return 1;
204 //equal priority
205 else return other.fileIndex - fileIndex;
206 } else throw new ClassCastException(
207 "Attempt to compare a FSMInstance object to an object " +
208 "of type " + obj.getClass()+"!");
209 }
210
211 /** Returns a textual representation of this FSM instance.
212 */
213 public String toString() {
214 String res = "";
215 RightHandSide rhs = getFSMPosition().getAction();
216 if(rhs != null){
217 res += rhs.getPhaseName() + "." + rhs.getRuleName() + ": \"";
218 try{
219 res += document.getContent().getContent(
220 getStartAGPosition().getOffset(),
221 getAGPosition().getOffset()).toString() + "\"";
222 }catch(InvalidOffsetException ioe){
223 ioe.printStackTrace(Err.getPrintWriter());
224 }
225
226 Iterator labelIter = bindings.keySet().iterator();
227 res += "\n{";
228 while(labelIter.hasNext()){
229 String label = (String)labelIter.next();
230 Collection annots = (Collection)bindings.get(label);
231 res += "\n" + label + ": ";
232 Iterator annIter = annots.iterator();
233 while(annIter.hasNext()){
234 Annotation ann = (Annotation)annIter.next();
235 res += ann.getType() + "(\"";
236 try{
237 res += document.getContent().
238 getContent(ann.getStartNode().getOffset(),
239 ann.getEndNode().getOffset()).toString();
240 }catch(InvalidOffsetException ioe){
241 ioe.printStackTrace(Err.getPrintWriter());
242 }
243 res += "\") ";
244 }
245 }
246 res += "\n}";
247 }else{
248 res += "FSM position :" + FSMPosition.getIndex() +
249 "\nFirst matched ANN at:" + startNode.getId() +
250 "\nLast matched ANN at :" + AGPosition.getId() +
251 "\nPriority :" + priority +
252 "\nFile index :" + fileIndex +
253 "\nBindings :" + bindings;
254 }
255 return res;
256 }
257
258 /** The FSM for which this FSMInstance is an instance of. */
259 private FSM supportGraph;
260
261 /** The current state of this FSMInstance */
262 private State FSMPosition;
263
264 /** The place (Node) in the AnnotationSet where the matching started*/
265 private Node AGPosition, startNode;
266
267 /** A map from java.lang.String to gate.AnnotationSet describing all the
268 * bindings that took place during matching.
269 * needs to be HashMap instead of simply Map in order to cloneable
270 */
271 private HashMap bindings;
272
273 /** The size of the matched region in the Annotation Set*/
274 private long length = 0;
275
276 /**
277 * The index in the definition file of the rule from which the AGPosition
278 * state was generated.
279 */
280 private int fileIndex;
281
282
283 private Document document;
284 /**
285 * The priority in the definition file of the rule from which the AGPosition
286 * state was generated.
287 */
288 private int priority;
289
290 /** Static method that provides new FSM instances. This method handles some
291 * basic object pooling in order to reuse the FSMInstance objects.
292 * This is considered to be a good idea because during jape transducing
293 * a large number of FSMIntances are needed for short periods.
294 */
295 public static FSMInstance getNewInstance(FSM supportGraph, State FSMPosition,
296 Node startNode, Node AGPosition,
297 HashMap bindings, Document doc) {
298 FSMInstance res;
299 if(myInstances.isEmpty()) res = new FSMInstance(supportGraph, FSMPosition,
300 startNode, AGPosition,
301 bindings, doc);
302 else {
303 res = (FSMInstance)myInstances.removeFirst();
304 res.supportGraph = supportGraph;
305 res.FSMPosition = FSMPosition;
306 res.startNode = startNode;
307 res.AGPosition = AGPosition;
308 res.bindings = bindings;
309 }
310 return res;
311 }
312
313 /** Static method used to return a FSMInstance that is not needed anymore
314 */
315 public static void returnInstance(FSMInstance ins) {
316 myInstances.addFirst(ins);
317 }
318
319 /** Release all the FSMInstances that are not currently in use */
320 public static void clearInstances() {
321 myInstances = new LinkedList();
322 }
323
324 /** The list of existing instances of type FSMInstance */
325 private static LinkedList myInstances;
326
327 /** The offset in the input List where the last matched annotation was*/
328 static{
329 myInstances = new LinkedList();
330 }
331
332 } // FSMInstance
333