| DatabaseAnnotationSetImpl.java |
1 /*
2 * Copyright (c) 1998-2004, 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.20 2004/07/21 17:10:02 akshay 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 }