DatabaseAnnotationSetImpl.java |
1 /* 2 * Copyright (c) 1998-2005, The University of Sheffield. 3 * 4 * This file is part of GATE (see http://gate.ac.uk/), and is free 5 * software, licenced under the GNU Library General Public License, 6 * Version 2, June 1991 (in the distribution as file licence.html, 7 * and also available at http://gate.ac.uk/gate/licence.html). 8 * 9 * Kalina Bontcheva 21/10/2001 10 * 11 * $Id: DatabaseAnnotationSetImpl.java,v 1.21 2005/01/11 13:51:30 ian Exp $ 12 */ 13 14 package gate.annotation; 15 16 import java.util.*; 17 18 import junit.framework.Assert; 19 20 import gate.*; 21 import gate.corpora.DatabaseDocumentImpl; 22 import gate.corpora.DocumentImpl; 23 import gate.event.*; 24 //import gate.persist.*; 25 26 27 public class DatabaseAnnotationSetImpl extends AnnotationSetImpl 28 implements DatastoreListener, 29 EventAwareAnnotationSet, 30 AnnotationListener { 31 32 /** 33 * The listener for the events coming from the document (annotations and 34 * annotation sets added or removed). 35 */ 36 //= protected EventsHandler eventHandler; 37 38 protected HashSet addedAnnotations = new HashSet(); 39 protected HashSet removedAnnotations = new HashSet(); 40 protected HashSet updatedAnnotations = new HashSet(); 41 42 private boolean validating = false; 43 44 public void assertValid() { 45 46 if (validating) 47 return; 48 49 validating = true; 50 //avoid recursion 51 52 //doc can't be null 53 Assert.assertNotNull(this.doc); 54 //doc.assertValid(); 55 56 validating = false; 57 } 58 59 /** Construction from Document. */ 60 public DatabaseAnnotationSetImpl(Document doc) { 61 62 super(doc); 63 64 //preconditions 65 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 66 67 //= eventHandler = new EventsHandler(); 68 //= this.addAnnotationSetListener(eventHandler); 69 70 //add self as listener for sync events from the document's datastore 71 //00 doc.getDataStore().removeDatastoreListener(this); 72 doc.getDataStore().addDatastoreListener(this); 73 // ((VerboseHashMap)annotsById).setOwner(this); 74 } // construction from document 75 76 /** Construction from Document and name. */ 77 public DatabaseAnnotationSetImpl(Document doc, String name) { 78 super(doc, name); 79 80 //preconditions 81 Assert.assertTrue(doc instanceof DatabaseDocumentImpl); 82 83 //= eventHandler = new EventsHandler(); 84 //= this.addAnnotationSetListener(eventHandler); 85 86 //add self as listener for sync events from the document's datastore 87 //00 doc.getDataStore().removeDatastoreListener(this); 88 doc.getDataStore().addDatastoreListener(this); 89 // ((VerboseHashMap)annotsById).setOwner(this); 90 } // construction from document and name 91 92 93 /** Construction from Document and name. */ 94 public DatabaseAnnotationSetImpl(Document doc, Collection c) { 95 this(c); 96 this.doc = (DocumentImpl) doc; 97 //add self as listener for sync events from the document's datastore 98 //00 doc.getDataStore().removeDatastoreListener(this); 99 //00 doc.getDataStore().addDatastoreListener(this); 100 } // construction from document and name 101 102 /** Construction from Document and name. */ 103 public DatabaseAnnotationSetImpl(Document doc, String name, Collection c) { 104 this(doc,c); 105 this.name = name; 106 //add self as listener for sync events from the document's datastore 107 //00 doc.getDataStore().removeDatastoreListener(this); 108 doc.getDataStore().addDatastoreListener(this); 109 } // construction from document and name 110 111 112 /** Construction from Collection (which must be an AnnotationSet) */ 113 public DatabaseAnnotationSetImpl(Collection c) throws ClassCastException { 114 115 super(c); 116 117 //also copy the name, because that super one doesn't 118 AnnotationSet as = (AnnotationSet) c; 119 this.name = as.getName(); 120 121 //= eventHandler = new EventsHandler(); 122 //= this.addAnnotationSetListener(eventHandler); 123 124 Iterator iter = this.iterator(); 125 while(iter.hasNext()) 126 ((Annotation) iter.next()).addAnnotationListener(this); 127 128 Document doc = as.getDocument(); 129 //add self as listener for sync events from the document's datastore 130 //00 doc.getDataStore().removeDatastoreListener(this); 131 doc.getDataStore().addDatastoreListener(this); 132 133 // ((VerboseHashMap)annotsById).setOwner(this); 134 } // construction from collection 135 136 137 public String toString() { 138 return super.toString() 139 + "added annots: " + addedAnnotations 140 + "removed annots: " + removedAnnotations 141 + "updated annots: " + updatedAnnotations; 142 } 143 144 145 // /** Two AnnotationSet are equal if their name, the documents of which belong 146 // * to the AnnotationSets and annotations from the sets are the same 147 // */ 148 // public boolean equals(Object other) { 149 // 150 // if (false == other instanceof DatabaseAnnotationSetImpl) { 151 // return super.equals(other); 152 // } 153 // 154 // boolean result = true; 155 // 156 // if (!super.equals((AnnotationSet)other)) { 157 // return false; 158 // } 159 // 160 // DatabaseAnnotationSetImpl target = (DatabaseAnnotationSetImpl)other; 161 // 162 // result = result && this.addedAnnotations.equals(target.addedAnnotations) 163 // && this.removedAnnotations.equals(target.removedAnnotations) 164 // && this.updatedAnnotations.equals(target.updatedAnnotations); 165 // 166 // //FINALLY - CHECK THAT THE SET IS FROM THE SAME DOCUMENT *INSTANCE* 167 // //DO *NOT* USE EQUALS() 168 // result = result && ( this.getDocument() == target.getDocument()); 169 // 170 // return result; 171 // } // equals 172 173 /** 174 * All the events from the document or its annotation sets are handled by 175 * this inner class. 176 */ 177 /* class EventsHandler implements AnnotationListener 178 AnnotationSetListener{ 179 180 181 public void annotationAdded(gate.event.AnnotationSetEvent e) { 182 AnnotationSet set = (AnnotationSet)e.getSource(); 183 String setName = set.getName(); 184 if (setName != DatabaseAnnotationSetImpl.this.name && 185 ! setName.equals(DatabaseAnnotationSetImpl.this.name)) 186 return; 187 Annotation ann = e.getAnnotation(); 188 ann.addAnnotationListener(this); 189 DatabaseAnnotationSetImpl.this.addedAnnotations.add(ann); 190 } 191 192 public void annotationRemoved(AnnotationSetEvent e){ 193 AnnotationSet set = (AnnotationSet)e.getSource(); 194 String setName = set.getName(); 195 if (setName != DatabaseAnnotationSetImpl.this.name && 196 ! setName.equals(DatabaseAnnotationSetImpl.this.name)) 197 return; 198 Annotation ann = e.getAnnotation(); 199 ann.removeAnnotationListener(this); 200 201 //1. check if this annot is in the newly created annotations set 202 if (addedAnnotations.contains(ann)) { 203 //a new annotatyion that was deleted afterwards, remove it from all sets 204 DatabaseAnnotationSetImpl.this.addedAnnotations.remove(ann); 205 return; 206 } 207 //2. check if the annotation was updated, if so, remove it from the 208 //update list 209 if (updatedAnnotations.contains(ann)) { 210 DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(ann); 211 } 212 213 DatabaseAnnotationSetImpl.this.removedAnnotations.add(ann); 214 } 215 216 217 public void annotationUpdated(AnnotationEvent e){ 218 Annotation ann = (Annotation) e.getSource(); 219 220 //check if the annotation is newly created 221 //if so, do not add it to the update list, since it was not stored in the 222 //database yet, so the most recent value will be inserted into the DB upon 223 //DataStore::sync() 224 if (addedAnnotations.contains(ann)) { 225 return; 226 } 227 228 DatabaseAnnotationSetImpl.this.updatedAnnotations.add(ann); 229 } 230 231 }//inner class EventsHandler 232 233 */ 234 235 /** 236 * Called by a datastore when a new resource has been adopted 237 */ 238 public void resourceAdopted(DatastoreEvent evt){ 239 Assert.assertNotNull(evt); 240 Assert.assertNotNull(evt.getResourceID()); 241 242 //check if this is our resource 243 //rememeber - a data store handles many resources 244 if (evt.getResourceID().equals(this.doc.getLRPersistenceId())) { 245 //System.out.println("ASNAME=["+this.getName()+"], resourceAdopted() called"); 246 //we're synced wtith the DB now 247 clearChangeLists(); 248 } 249 } 250 251 /** 252 * Called by a datastore when a resource has been deleted 253 */ 254 public void resourceDeleted(DatastoreEvent evt){ 255 256 Assert.assertNotNull(evt); 257 Assert.assertNotNull(evt.getResourceID()); 258 259 //check if this is our resource 260 //rememeber - a data store handles many resources 261 if (evt.getResourceID().equals(this.doc.getLRPersistenceId())) { 262 //System.out.println("ASNAME=["+this.getName()+"],resourceDeleted() called"); 263 264 //unregister self 265 //this is not the correct way, since the resource is null in this case 266 // DataStore ds = (DataStore)evt.getResource(); 267 DataStore ds = this.doc.getDataStore(); 268 if (ds != null) 269 ds.removeDatastoreListener(this); 270 } 271 272 }//resourceDeleted 273 274 /** 275 * Called by a datastore when a resource has been wrote into the datastore 276 */ 277 public void resourceWritten(DatastoreEvent evt){ 278 Assert.assertNotNull(evt); 279 Assert.assertNotNull(evt.getResourceID()); 280 281 //check if this is our resource 282 //rememeber - a data store handles many resources 283 if (evt.getResourceID().equals(this.doc.getLRPersistenceId())) { 284 //System.out.println("ASNAME=["+this.getName()+"],resourceWritten() called"); 285 286 //clear lists with updates - we're synced with the DB 287 clearChangeLists(); 288 } 289 } 290 291 292 private void clearChangeLists() { 293 294 //ok, we're synced now, clear all lists with changed IDs 295 synchronized(this) { 296 //System.out.println("clearing lists..."); 297 this.addedAnnotations.clear(); 298 this.updatedAnnotations.clear(); 299 this.removedAnnotations.clear(); 300 } 301 } 302 303 public Collection getAddedAnnotations() { 304 //System.out.println("getAddedIDs() called"); 305 HashSet result = new HashSet(); 306 result.addAll(this.addedAnnotations); 307 308 return result; 309 } 310 311 312 public Collection getChangedAnnotations() { 313 //System.out.println("getChangedIDs() called"); 314 HashSet result = new HashSet(); 315 result.addAll(this.updatedAnnotations); 316 317 return result; 318 } 319 320 321 public Collection getRemovedAnnotations() { 322 //System.out.println("getremovedIDs() called..."); 323 HashSet result = new HashSet(); 324 result.addAll(this.removedAnnotations); 325 326 return result; 327 } 328 329 public void annotationUpdated(AnnotationEvent e){ 330 Annotation ann = (Annotation) e.getSource(); 331 332 //check if the annotation is newly created 333 //if so, do not add it to the update list, since it was not stored in the 334 //database yet, so the most recent value will be inserted into the DB upon 335 //DataStore::sync() 336 if (false == this.addedAnnotations.contains(ann)) { 337 this.updatedAnnotations.add(ann); 338 } 339 340 //sanity check 341 Assert.assertTrue(false == this.removedAnnotations.contains(ann)); 342 } 343 344 345 /** Add an existing annotation. Returns true when the set is modified. */ 346 public boolean add(Object o) throws ClassCastException { 347 348 //check if this annotation was removed beforehand 349 //if so then just delete it from the list of annotations waiting for persistent removal 350 if (this.removedAnnotations.contains(o)) { 351 this.removedAnnotations.remove(o); 352 } 353 354 boolean result = super.add(o); 355 356 if (true == result) { 357 //register as listener for update events from this annotation 358 Annotation ann = (Annotation)o; 359 ann.addAnnotationListener(this); 360 361 //add to the newly created annotations set 362 this.addedAnnotations.add(ann); 363 } 364 365 return result; 366 } 367 368 369 /** 370 * 371 * @param e 372 */ 373 protected void fireAnnotationRemoved(AnnotationSetEvent e) { 374 if (annotationSetListeners != null) { 375 Vector listeners = annotationSetListeners; 376 int count = listeners.size(); 377 for (int i = 0; i < count; i++) { 378 ((AnnotationSetListener) listeners.elementAt(i)).annotationRemoved(e); 379 } 380 } 381 } 382 383 /** Remove an element from this set. */ 384 public boolean remove(Object o) throws ClassCastException { 385 386 boolean result = super.remove(o); 387 388 if (true == result) { 389 //UNregister as listener for update events from this annotation 390 Annotation ann = (Annotation)o; 391 ann.removeAnnotationListener(this); 392 393 //1. check if this annot is in the newly created annotations set 394 if (this.addedAnnotations.contains(ann)) { 395 //a new annotation that was deleted afterwards, remove it from all sets 396 this.addedAnnotations.remove(ann); 397 } 398 else { 399 400 //2. check if the annotation was updated, if so, remove it from the 401 //update list 402 if (this.updatedAnnotations.contains(ann)) { 403 this.updatedAnnotations.remove(ann); 404 } 405 406 //3. add to the list with deleted anns 407 this.removedAnnotations.add(ann); 408 } 409 } 410 411 return result; 412 } 413 414 public Iterator iterator() { return new DatabaseAnnotationSetIterator(); } 415 416 417 class DatabaseAnnotationSetIterator extends AnnotationSetImpl.AnnotationSetIterator { 418 419 public void remove() { 420 421 super.remove(); 422 423 Annotation annRemoved = (Annotation)lastNext; 424 425 //UNregister as listener for update events from this annotation 426 annRemoved.removeAnnotationListener(DatabaseAnnotationSetImpl.this); 427 428 //1. check if this annot is in the newly created annotations set 429 if (DatabaseAnnotationSetImpl.this.addedAnnotations.contains(annRemoved)) { 430 //a new annotation that was deleted afterwards, remove it from all sets 431 DatabaseAnnotationSetImpl.this.addedAnnotations.remove(annRemoved); 432 } 433 else { 434 435 //2. check if the annotation was updated, if so, remove it from the 436 //update list 437 if (DatabaseAnnotationSetImpl.this.updatedAnnotations.contains(annRemoved)) { 438 DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(annRemoved); 439 } 440 441 //3. add to the list with deleted anns 442 DatabaseAnnotationSetImpl.this.removedAnnotations.add(annRemoved); 443 } 444 } 445 446 } 447 448 449 }