001 /*
002 * Copyright (c) 1995-2010, The University of Sheffield. See the file
003 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004 *
005 * This file is part of GATE (see http://gate.ac.uk/), and is free
006 * software, licenced under the GNU Library General Public License,
007 * Version 2, June 1991 (in the distribution as file licence.html,
008 * and also available at http://gate.ac.uk/gate/licence.html).
009 *
010 * Kalina Bontcheva 21/10/2001
011 *
012 * $Id: DatabaseAnnotationSetImpl.java 12006 2009-12-01 17:24:28Z thomas_heitz $
013 */
014 package gate.annotation;
015
016 import java.util.*;
017 import junit.framework.Assert;
018 import gate.*;
019 import gate.corpora.DatabaseDocumentImpl;
020 import gate.corpora.DocumentImpl;
021 import gate.event.*;
022
023 // import gate.persist.*;
024 public class DatabaseAnnotationSetImpl extends AnnotationSetImpl
025 implements
026 DatastoreListener,
027 EventAwareAnnotationSet,
028 AnnotationListener {
029 /**
030 * The listener for the events coming from the document (annotations and
031 * annotation sets added or removed).
032 */
033 // = protected EventsHandler eventHandler;
034 protected HashSet<Annotation> addedAnnotations = new HashSet<Annotation>();
035 protected HashSet<Annotation> removedAnnotations = new HashSet<Annotation>();
036 protected HashSet<Annotation> updatedAnnotations = new HashSet<Annotation>();
037 private boolean validating = false;
038
039 public void assertValid() {
040 if(validating) return;
041 validating = true;
042 // avoid recursion
043 // doc can't be null
044 Assert.assertNotNull(this.doc);
045 // doc.assertValid();
046 validating = false;
047 }
048
049 /** Construction from Document. */
050 public DatabaseAnnotationSetImpl(Document doc) {
051 super(doc);
052 // preconditions
053 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
054 // = eventHandler = new EventsHandler();
055 // = this.addAnnotationSetListener(eventHandler);
056 // add self as listener for sync events from the document's datastore
057 // 00 doc.getDataStore().removeDatastoreListener(this);
058 doc.getDataStore().addDatastoreListener(this);
059 // ((VerboseHashMap)annotsById).setOwner(this);
060 } // construction from document
061
062 /** Construction from Document and name. */
063 public DatabaseAnnotationSetImpl(Document doc, String name) {
064 super(doc, name);
065 // preconditions
066 Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
067 // = eventHandler = new EventsHandler();
068 // = this.addAnnotationSetListener(eventHandler);
069 // add self as listener for sync events from the document's datastore
070 // 00 doc.getDataStore().removeDatastoreListener(this);
071 doc.getDataStore().addDatastoreListener(this);
072 // ((VerboseHashMap)annotsById).setOwner(this);
073 } // construction from document and name
074
075 /** Construction from Document and name. */
076 public DatabaseAnnotationSetImpl(Document doc, AnnotationSet c) {
077 this(c);
078 this.doc = (DocumentImpl)doc;
079 // add self as listener for sync events from the document's datastore
080 // 00 doc.getDataStore().removeDatastoreListener(this);
081 // 00 doc.getDataStore().addDatastoreListener(this);
082 } // construction from document and name
083
084 /** Construction from Document and name. */
085 public DatabaseAnnotationSetImpl(Document doc, String name, AnnotationSet c) {
086 this(doc, c);
087 this.name = name;
088 // add self as listener for sync events from the document's datastore
089 // 00 doc.getDataStore().removeDatastoreListener(this);
090 doc.getDataStore().addDatastoreListener(this);
091 } // construction from document and name
092
093 /** Construction from Collection (which must be an AnnotationSet) */
094 public DatabaseAnnotationSetImpl(AnnotationSet c) throws ClassCastException {
095 super(c);
096 // also copy the name, because that super one doesn't
097 AnnotationSet as = (AnnotationSet)c;
098 this.name = as.getName();
099 // = eventHandler = new EventsHandler();
100 // = this.addAnnotationSetListener(eventHandler);
101 Iterator<Annotation> iter = this.iterator();
102 while(iter.hasNext())
103 iter.next().addAnnotationListener(this);
104 Document doc = as.getDocument();
105 // add self as listener for sync events from the document's datastore
106 // 00 doc.getDataStore().removeDatastoreListener(this);
107 doc.getDataStore().addDatastoreListener(this);
108 // ((VerboseHashMap)annotsById).setOwner(this);
109 } // construction from collection
110
111 public String toString() {
112 return super.toString() + "added annots: " + addedAnnotations
113 + "removed annots: " + removedAnnotations + "updated annots: "
114 + updatedAnnotations;
115 }
116
117 // /** Two AnnotationSet are equal if their name, the documents of which
118 // belong
119 // * to the AnnotationSets and annotations from the sets are the same
120 // */
121 // public boolean equals(Object other) {
122 //
123 // if (false == other instanceof DatabaseAnnotationSetImpl) {
124 // return super.equals(other);
125 // }
126 //
127 // boolean result = true;
128 //
129 // if (!super.equals((AnnotationSet)other)) {
130 // return false;
131 // }
132 //
133 // DatabaseAnnotationSetImpl target = (DatabaseAnnotationSetImpl)other;
134 //
135 // result = result && this.addedAnnotations.equals(target.addedAnnotations)
136 // && this.removedAnnotations.equals(target.removedAnnotations)
137 // && this.updatedAnnotations.equals(target.updatedAnnotations);
138 //
139 // //FINALLY - CHECK THAT THE SET IS FROM THE SAME DOCUMENT *INSTANCE*
140 // //DO *NOT* USE EQUALS()
141 // result = result && ( this.getDocument() == target.getDocument());
142 //
143 // return result;
144 // } // equals
145 /**
146 * All the events from the document or its annotation sets are handled by this
147 * inner class.
148 */
149 /*
150 * class EventsHandler implements AnnotationListener AnnotationSetListener{
151 *
152 *
153 * public void annotationAdded(gate.event.AnnotationSetEvent e) {
154 * AnnotationSet set = (AnnotationSet)e.getSource(); String setName =
155 * set.getName(); if (setName != DatabaseAnnotationSetImpl.this.name && !
156 * setName.equals(DatabaseAnnotationSetImpl.this.name)) return; Annotation ann =
157 * e.getAnnotation(); ann.addAnnotationListener(this);
158 * DatabaseAnnotationSetImpl.this.addedAnnotations.add(ann); }
159 *
160 * public void annotationRemoved(AnnotationSetEvent e){ AnnotationSet set =
161 * (AnnotationSet)e.getSource(); String setName = set.getName(); if (setName !=
162 * DatabaseAnnotationSetImpl.this.name && !
163 * setName.equals(DatabaseAnnotationSetImpl.this.name)) return; Annotation ann =
164 * e.getAnnotation(); ann.removeAnnotationListener(this);
165 *
166 * //1. check if this annot is in the newly created annotations set if
167 * (addedAnnotations.contains(ann)) { //a new annotatyion that was deleted
168 * afterwards, remove it from all sets
169 * DatabaseAnnotationSetImpl.this.addedAnnotations.remove(ann); return; } //2.
170 * check if the annotation was updated, if so, remove it from the //update
171 * list if (updatedAnnotations.contains(ann)) {
172 * DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(ann); }
173 *
174 * DatabaseAnnotationSetImpl.this.removedAnnotations.add(ann); }
175 *
176 *
177 * public void annotationUpdated(AnnotationEvent e){ Annotation ann =
178 * (Annotation) e.getSource();
179 *
180 * //check if the annotation is newly created //if so, do not add it to the
181 * update list, since it was not stored in the //database yet, so the most
182 * recent value will be inserted into the DB upon //DataStore::sync() if
183 * (addedAnnotations.contains(ann)) { return; }
184 *
185 * DatabaseAnnotationSetImpl.this.updatedAnnotations.add(ann); }
186 *
187 * }//inner class EventsHandler
188 *
189 */
190 /**
191 * Called by a datastore when a new resource has been adopted
192 */
193 public void resourceAdopted(DatastoreEvent evt) {
194 Assert.assertNotNull(evt);
195 Assert.assertNotNull(evt.getResourceID());
196 // check if this is our resource
197 // rememeber - a data store handles many resources
198 if(evt.getResourceID().equals(this.doc.getLRPersistenceId())) {
199 // System.out.println("ASNAME=["+this.getName()+"], resourceAdopted()
200 // called");
201 // we're synced wtith the DB now
202 clearChangeLists();
203 }
204 }
205
206 /**
207 * Called by a datastore when a resource has been deleted
208 */
209 public void resourceDeleted(DatastoreEvent evt) {
210 Assert.assertNotNull(evt);
211 Assert.assertNotNull(evt.getResourceID());
212 // check if this is our resource
213 // rememeber - a data store handles many resources
214 if(evt.getResourceID().equals(this.doc.getLRPersistenceId())) {
215 // System.out.println("ASNAME=["+this.getName()+"],resourceDeleted()
216 // called");
217 // unregister self
218 // this is not the correct way, since the resource is null in this case
219 // DataStore ds = (DataStore)evt.getResource();
220 DataStore ds = this.doc.getDataStore();
221 if(ds != null) ds.removeDatastoreListener(this);
222 }
223 }// resourceDeleted
224
225 /**
226 * Called by a datastore when a resource has been wrote into the datastore
227 */
228 public void resourceWritten(DatastoreEvent evt) {
229 Assert.assertNotNull(evt);
230 Assert.assertNotNull(evt.getResourceID());
231 // check if this is our resource
232 // rememeber - a data store handles many resources
233 if(evt.getResourceID().equals(this.doc.getLRPersistenceId())) {
234 // System.out.println("ASNAME=["+this.getName()+"],resourceWritten()
235 // called");
236 // clear lists with updates - we're synced with the DB
237 clearChangeLists();
238 }
239 }
240
241 private void clearChangeLists() {
242 // ok, we're synced now, clear all lists with changed IDs
243 synchronized(this) {
244 // System.out.println("clearing lists...");
245 this.addedAnnotations.clear();
246 this.updatedAnnotations.clear();
247 this.removedAnnotations.clear();
248 }
249 }
250
251 public Collection<Annotation> getAddedAnnotations() {
252 // System.out.println("getAddedIDs() called");
253 HashSet<Annotation> result = new HashSet<Annotation>();
254 result.addAll(this.addedAnnotations);
255 return result;
256 }
257
258 public Collection<Annotation> getChangedAnnotations() {
259 // System.out.println("getChangedIDs() called");
260 HashSet<Annotation> result = new HashSet<Annotation>();
261 result.addAll(this.updatedAnnotations);
262 return result;
263 }
264
265 public Collection<Annotation> getRemovedAnnotations() {
266 // System.out.println("getremovedIDs() called...");
267 HashSet<Annotation> result = new HashSet<Annotation>();
268 result.addAll(this.removedAnnotations);
269 return result;
270 }
271
272 public void annotationUpdated(AnnotationEvent e) {
273 Annotation ann = (Annotation)e.getSource();
274 // check if the annotation is newly created
275 // if so, do not add it to the update list, since it was not stored in the
276 // database yet, so the most recent value will be inserted into the DB upon
277 // DataStore::sync()
278 if(false == this.addedAnnotations.contains(ann)) {
279 this.updatedAnnotations.add(ann);
280 }
281 // sanity check
282 Assert.assertTrue(false == this.removedAnnotations.contains(ann));
283 }
284
285 /** Add an existing annotation. Returns true when the set is modified. */
286 public boolean add(Annotation o) throws ClassCastException {
287 // check if this annotation was removed beforehand
288 // if so then just delete it from the list of annotations waiting for
289 // persistent removal
290 if(this.removedAnnotations.contains(o)) {
291 this.removedAnnotations.remove(o);
292 }
293 boolean result = super.add(o);
294 if(true == result) {
295 // register as listener for update events from this annotation
296 o.addAnnotationListener(this);
297 // add to the newly created annotations set
298 this.addedAnnotations.add(o);
299 }
300 return result;
301 }
302
303 /**
304 *
305 * @param e
306 */
307 protected void fireAnnotationRemoved(AnnotationSetEvent e) {
308 if(annotationSetListeners != null) {
309 Vector listeners = annotationSetListeners;
310 int count = listeners.size();
311 for(int i = 0; i < count; i++) {
312 ((AnnotationSetListener)listeners.elementAt(i)).annotationRemoved(e);
313 }
314 }
315 }
316
317 /** Remove an element from this set. */
318 public boolean remove(Object o) throws ClassCastException {
319 boolean result = super.remove(o);
320 if(true == result) {
321 // UNregister as listener for update events from this annotation
322 Annotation ann = (Annotation)o;
323 ann.removeAnnotationListener(this);
324 // 1. check if this annot is in the newly created annotations set
325 if(this.addedAnnotations.contains(ann)) {
326 // a new annotation that was deleted afterwards, remove it from all sets
327 this.addedAnnotations.remove(ann);
328 } else {
329 // 2. check if the annotation was updated, if so, remove it from the
330 // update list
331 if(this.updatedAnnotations.contains(ann)) {
332 this.updatedAnnotations.remove(ann);
333 }
334 // 3. add to the list with deleted anns
335 this.removedAnnotations.add(ann);
336 }
337 }
338 return result;
339 }
340
341 public Iterator<Annotation> iterator() {
342 return new DatabaseAnnotationSetIterator();
343 }
344
345 class DatabaseAnnotationSetIterator
346 extends
347 AnnotationSetImpl.AnnotationSetIterator {
348 public void remove() {
349 super.remove();
350 Annotation annRemoved = lastNext;
351 // UNregister as listener for update events from this annotation
352 annRemoved.removeAnnotationListener(DatabaseAnnotationSetImpl.this);
353 // 1. check if this annot is in the newly created annotations set
354 if(DatabaseAnnotationSetImpl.this.addedAnnotations.contains(annRemoved)) {
355 // a new annotation that was deleted afterwards, remove it from all sets
356 DatabaseAnnotationSetImpl.this.addedAnnotations.remove(annRemoved);
357 } else {
358 // 2. check if the annotation was updated, if so, remove it from the
359 // update list
360 if(DatabaseAnnotationSetImpl.this.updatedAnnotations
361 .contains(annRemoved)) {
362 DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(annRemoved);
363 }
364 // 3. add to the list with deleted anns
365 DatabaseAnnotationSetImpl.this.removedAnnotations.add(annRemoved);
366 }
367 }
368 }
369 }
|