FSMInstance.java |
1 /* 2 * FSMInstance.java 3 * 4 * Copyright (c) 1998-2005, 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.25 2005/01/11 13:51:34 ian 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