001 /*
002 * FSMInstance.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 * Valentin Tablan, 05/May/2000
013 *
014 * $Id: FSMInstance.java 12370 2010-03-17 09:01:13Z ian_roberts $
015 */
016 package gate.fsm;
017
018 import java.io.Serializable;
019 import java.util.*;
020
021 import gate.*;
022 import gate.jape.RightHandSide;
023 import gate.util.Err;
024 import gate.util.InvalidOffsetException;
025
026 /**
027 * The objects of this class represent instances of working Finite State
028 * Machine during parsing a gate document (annotation set).
029 * In order to completely define the state a FSM is in one needs to store
030 * information regarding:
031 * -the position in the FSM transition graph
032 * -the position in the annotation graph
033 * -the set of bindings that occured up to the current state.
034 * note that a set of bindings is an object of type Map that maps names
035 * (java.lang.String) to bags of annotations (gate.AnnotationSet)
036 */
037 public class FSMInstance implements Comparable, Cloneable, Serializable {
038
039 /** Debug flag */
040 private static final boolean DEBUG = false;
041
042 /** Creates a new FSMInstance object.
043 * @param supportGraph the transition graph of the FSM
044 * @param FSMPosition the state this instance will be in
045 * @param startNode the node in the AnnotationSet where this FSM instance
046 * started the matching
047 * @param AGPosition the node in the AnnotationSet up to which this FSM Instance
048 * advanced during the matching.
049 * @param bindings a HashMap that maps from labels (objects of type String)
050 * to sets of annotations (objects of type AnnotationSet). This map stores
051 * all the bindings that took place during the matching process.
052 * This FSMInstance started the matching on an AnnotationSet from "startNode"
053 * and advanced to "AGPosition"; during this process it traversed the path in
054 * the transition graph "supportGraph" from the initial state to
055 * "FSMPosition" and made the bindings stored in "bindings".
056 */
057 public FSMInstance(FSM supportGraph, State FSMPosition,
058 Node startNode, Node AGPosition,
059 HashMap<String, AnnotationSet> bindings,
060 Document document) {
061
062 this.supportGraph = supportGraph;
063 this.FSMPosition = FSMPosition;
064 this.startNode = startNode;
065 this.AGPosition = AGPosition;
066 this.bindings = bindings;
067 this.document = document;
068 length = AGPosition.getOffset().longValue() -
069 startNode.getOffset().longValue();
070 fileIndex = FSMPosition.getFileIndex();
071 priority = FSMPosition.getPriority();
072 }
073
074 /** Returns the FSM transition graph that backs this FSM instance
075 * @return an FSM object
076 */
077 public FSM getSupportGraph(){ return supportGraph; }
078
079 /** Returns the position in the support graph for this FSM instance
080 * @return an object of type State
081 */
082 public State getFSMPosition(){ return FSMPosition; }
083
084 /** Sets the position in the support transition graph for this FSM instance
085 * Convenience method for when the state is not known at construction time.
086 */
087 public void setFSMPosition(State newFSMPos) {
088 FSMPosition = newFSMPos;
089 fileIndex = FSMPosition.getFileIndex();
090 priority = FSMPosition.getPriority();
091 }
092
093 /** Returns the index in the Jape definition file of the rule that caused
094 * the generation of the FSM state this instance is in.
095 * This value is correct if and only if this FSM instance is in a final
096 * state of the FSM transition graph.
097 * @return an int value.
098 */
099 public int getFileIndex(){ return fileIndex; }
100
101 /** Returns the node in the AnnotationSet from which this FSM instance
102 * started the matching process.
103 * @return a gate.Node object
104 */
105 public Node getStartAGPosition(){ return startNode; }
106
107 /** Returns the node up to which this FSM instance advanced in the
108 * Annotation graph during the matching process.
109 * @return a gate.Node object
110 */
111 public Node getAGPosition(){ return AGPosition; }
112
113 /** Sets the current position in the AnnotationSet.
114 * Convenience method for cases when this value is not known at construction
115 * time.
116 * @param node a position in the AnnotationSet
117 */
118 public void setAGPosition(Node node){
119 AGPosition = node;
120 length = AGPosition.getOffset().longValue() -
121 startNode.getOffset().longValue();
122 }
123
124 /** Gets the map representing the bindings that took place during the matching
125 * process this FSM instance performed.
126 * @return a HashMap object
127 */
128 public HashMap<String, AnnotationSet> getBindings() { return bindings; }
129
130 /** Returns the length of the parsed region in the document under scrutiny.
131 * More precisely this is the distnace between the Node in the annotation
132 * graph where the matching started and the current position.
133 * @return a long value
134 */
135 public long getLength() { return length; }
136
137 /** Overrides the hashCode method from Object so this obejcts can be stored in
138 * hash maps and hash sets.
139 */
140 public int hashCode() {
141 return (int)length ^ priority ^ fileIndex ^ bindings.hashCode() ^
142 FSMPosition.getAction().hashCode();
143 }
144
145 public boolean equals(Object other){
146 if(other instanceof FSMInstance){
147 FSMInstance otherFSM = (FSMInstance)other;
148 boolean result = length == otherFSM.length &&
149 priority == otherFSM.priority &&
150 fileIndex == otherFSM.fileIndex &&
151 bindings.equals(otherFSM.bindings) &&
152 FSMPosition.getAction().equals(otherFSM.FSMPosition.getAction());
153 return result;
154 }else{
155 throw new ClassCastException(other.getClass().toString());
156 }
157 }
158
159 /** Returns a clone of this object.
160 * The cloning is done bitwise except for the bindings that are cloned by
161 * themselves
162 * @return an Object value that is actually a FSMInstance object
163 */
164 public Object clone() {
165 //do a classic clone except for bindings which need to be cloned themselves
166 try {
167 FSMInstance clone = (FSMInstance)super.clone();
168 clone.bindings = (HashMap)bindings.clone();
169 return clone;
170 } catch (CloneNotSupportedException cnse) {
171 cnse.printStackTrace(Err.getPrintWriter());
172 return null;
173 }
174 }
175
176 /*
177 public Object clone() {
178 //do a classic clone except for bindings which need to be cloned themselves
179 //Out.println("Clone!");
180 FSMInstance clone = FSMInstance.getNewInstance(this.supportGraph,
181 this.FSMPosition,
182 this.startNode,
183 this.AGPosition,
184 null);
185 clone.bindings = (HashMap)(bindings.clone());
186 return (FSMInstance)clone;
187 }
188 */
189
190 /** Implementation of the compareTo method required by the Comparable
191 * interface. The comparison is based on the size of the matched region and
192 * the index in the definition file of the rule associated to this FSM
193 * instance (which needs to be in a final state)
194 * The order imposed by this method is the priority needed in case of a
195 * multiple match.
196 */
197 public int compareTo(Object obj) {
198 if (obj instanceof FSMInstance) {
199 if(obj == this) return 0;
200 FSMInstance other = (FSMInstance)obj;
201 if(length < other.getLength()) return -1;
202 else if(length > other.getLength()) return 1;
203 //equal length
204 else if(priority < other.priority) return -1;
205 else if(priority > other.priority) return 1;
206 //equal priority
207 else return other.fileIndex - fileIndex;
208 } else throw new ClassCastException(
209 "Attempt to compare a FSMInstance object to an object " +
210 "of type " + obj.getClass()+"!");
211 }
212
213 /** Returns a textual representation of this FSM instance.
214 */
215 public String toString() {
216 String res = "";
217 RightHandSide rhs = getFSMPosition().getAction();
218 if(rhs != null){
219 res += rhs.getPhaseName() + "." + rhs.getRuleName() + ": \"";
220 try{
221 res += document.getContent().getContent(
222 getStartAGPosition().getOffset(),
223 getAGPosition().getOffset()).toString() + "\"";
224 }catch(InvalidOffsetException ioe){
225 ioe.printStackTrace(Err.getPrintWriter());
226 }
227
228 Iterator<String> labelIter = bindings.keySet().iterator();
229 res += "\n{";
230 while(labelIter.hasNext()){
231 String label = (String)labelIter.next();
232 Collection<Annotation> annots = bindings.get(label);
233 res += "\n" + label + ": ";
234 Iterator<Annotation> annIter = annots.iterator();
235 while(annIter.hasNext()){
236 Annotation ann = annIter.next();
237 res += ann.getType() + "(\"";
238 try{
239 res += document.getContent().
240 getContent(ann.getStartNode().getOffset(),
241 ann.getEndNode().getOffset()).toString();
242 }catch(InvalidOffsetException ioe){
243 ioe.printStackTrace(Err.getPrintWriter());
244 }
245 res += "\") ";
246 }
247 }
248 res += "\n}";
249 }else{
250 res += "FSM position :" + FSMPosition.getIndex() +
251 "\nFirst matched ANN at:" + startNode.getId() +
252 "\nLast matched ANN at :" + AGPosition.getId() +
253 "\nPriority :" + priority +
254 "\nFile index :" + fileIndex +
255 "\nBindings :" + bindings;
256 }
257 return res;
258 }
259
260 /** The FSM for which this FSMInstance is an instance of. */
261 private FSM supportGraph;
262
263 /** The current state of this FSMInstance */
264 private State FSMPosition;
265
266 /** The place (Node) in the AnnotationSet where the matching started*/
267 private Node AGPosition, startNode;
268
269 /** A map from java.lang.String to gate.AnnotationSet describing all the
270 * bindings that took place during matching.
271 * needs to be HashMap instead of simply Map in order to cloneable
272 */
273 private HashMap<String, AnnotationSet> bindings;
274
275 /** The size of the matched region in the Annotation Set*/
276 private long length = 0;
277
278 /**
279 * The index in the definition file of the rule from which the AGPosition
280 * state was generated.
281 */
282 private int fileIndex;
283
284
285 private Document document;
286 /**
287 * The priority in the definition file of the rule from which the AGPosition
288 * state was generated.
289 */
290 private int priority;
291
292 /** Static method that provides new FSM instances. This method handles some
293 * basic object pooling in order to reuse the FSMInstance objects.
294 * This is considered to be a good idea because during jape transducing
295 * a large number of FSMIntances are needed for short periods.
296 */
297 public static FSMInstance getNewInstance(FSM supportGraph, State FSMPosition,
298 Node startNode, Node AGPosition,
299 HashMap<String, AnnotationSet> bindings,
300 Document doc) {
301 FSMInstance res;
302 if(myInstances.isEmpty()) res = new FSMInstance(supportGraph, FSMPosition,
303 startNode, AGPosition,
304 bindings, doc);
305 else {
306 res = (FSMInstance)myInstances.removeFirst();
307 res.supportGraph = supportGraph;
308 res.FSMPosition = FSMPosition;
309 res.startNode = startNode;
310 res.AGPosition = AGPosition;
311 res.bindings = bindings;
312 }
313 return res;
314 }
315
316 /** Static method used to return a FSMInstance that is not needed anymore
317 */
318 public static void returnInstance(FSMInstance ins) {
319 myInstances.addFirst(ins);
320 }
321
322 /** Release all the FSMInstances that are not currently in use */
323 public static void clearInstances() {
324 myInstances = new LinkedList();
325 }
326
327 /** The list of existing instances of type FSMInstance */
328 private static LinkedList myInstances;
329
330 /** The offset in the input List where the last matched annotation was*/
331 static{
332 myInstances = new LinkedList();
333 }
334
335 } // FSMInstance
|