1   /*
2    *  Copyright (c) 1998-2001, 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.14 2002/07/12 13:25:57 valyt Exp $
12   */
13  
14  package gate.annotation;
15  
16  import java.util.*;
17  
18  import junit.framework.*;
19  
20  import gate.event.*;
21  import gate.*;
22  import gate.util.*;
23  import gate.corpora.*;
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  
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  
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   } // construction from collection
133 
134 
135   public String toString() {
136     return super.toString()
137               + "added annots: " + addedAnnotations
138               + "removed annots: " + removedAnnotations
139               + "updated annots: " + updatedAnnotations;
140   }
141 
142 
143 //  /** Two AnnotationSet are equal if their name, the documents of which belong
144 //    *  to the AnnotationSets and annotations from the sets are the same
145 //    */
146 //  public boolean equals(Object other) {
147 //
148 //    if (false == other instanceof DatabaseAnnotationSetImpl) {
149 //      return super.equals(other);
150 //    }
151 //
152 //    boolean result = true;
153 //
154 //    if (!super.equals((AnnotationSet)other)) {
155 //      return false;
156 //    }
157 //
158 //    DatabaseAnnotationSetImpl target = (DatabaseAnnotationSetImpl)other;
159 //
160 //    result = result && this.addedAnnotations.equals(target.addedAnnotations)
161 //                    && this.removedAnnotations.equals(target.removedAnnotations)
162 //                    && this.updatedAnnotations.equals(target.updatedAnnotations);
163 //
164 //    //FINALLY - CHECK THAT THE SET IS FROM THE SAME DOCUMENT *INSTANCE*
165 //    //DO *NOT* USE EQUALS()
166 //    result = result && ( this.getDocument() == target.getDocument());
167 //
168 //    return result;
169 //  } // equals
170 
171   /**
172    * All the events from the document or its annotation sets are handled by
173    * this inner class.
174    */
175 /*  class EventsHandler implements AnnotationListener
176                                  AnnotationSetListener{
177 
178 
179     public void annotationAdded(gate.event.AnnotationSetEvent e) {
180       AnnotationSet set = (AnnotationSet)e.getSource();
181       String setName = set.getName();
182       if (setName != DatabaseAnnotationSetImpl.this.name &&
183           ! setName.equals(DatabaseAnnotationSetImpl.this.name))
184         return;
185       Annotation ann = e.getAnnotation();
186       ann.addAnnotationListener(this);
187       DatabaseAnnotationSetImpl.this.addedAnnotations.add(ann);
188     }
189 
190     public void annotationRemoved(AnnotationSetEvent e){
191       AnnotationSet set = (AnnotationSet)e.getSource();
192       String setName = set.getName();
193       if (setName != DatabaseAnnotationSetImpl.this.name &&
194           ! setName.equals(DatabaseAnnotationSetImpl.this.name))
195         return;
196       Annotation ann = e.getAnnotation();
197       ann.removeAnnotationListener(this);
198 
199       //1. check if this annot is in the newly created annotations set
200       if (addedAnnotations.contains(ann)) {
201         //a new annotatyion that was deleted afterwards, remove it from all sets
202         DatabaseAnnotationSetImpl.this.addedAnnotations.remove(ann);
203         return;
204       }
205       //2. check if the annotation was updated, if so, remove it from the
206       //update list
207       if (updatedAnnotations.contains(ann)) {
208         DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(ann);
209       }
210 
211       DatabaseAnnotationSetImpl.this.removedAnnotations.add(ann);
212     }
213 
214 
215     public void annotationUpdated(AnnotationEvent e){
216       Annotation ann = (Annotation) e.getSource();
217 
218       //check if the annotation is newly created
219       //if so, do not add it to the update list, since it was not stored in the
220       //database yet, so the most recent value will be inserted into the DB upon
221       //DataStore::sync()
222       if (addedAnnotations.contains(ann)) {
223         return;
224       }
225 
226       DatabaseAnnotationSetImpl.this.updatedAnnotations.add(ann);
227     }
228 
229   }//inner class EventsHandler
230 
231 */
232 
233   /**
234    * Called by a datastore when a new resource has been adopted
235    */
236   public void resourceAdopted(DatastoreEvent evt){
237     Assert.assertNotNull(evt);
238     Assert.assertNotNull(evt.getResourceID());
239 
240     //check if this is our resource
241     //rememeber -  a data store handles many resources
242     if (evt.getResourceID().equals(this.doc.getLRPersistenceId()))  {
243 //System.out.println("ASNAME=["+this.getName()+"], resourceAdopted() called");
244       //we're synced wtith the DB now
245       clearChangeLists();
246     }
247   }
248 
249   /**
250    * Called by a datastore when a resource has been deleted
251    */
252   public void resourceDeleted(DatastoreEvent evt){
253 
254     Assert.assertNotNull(evt);
255     Assert.assertNotNull(evt.getResourceID());
256 
257     //check if this is our resource
258     //rememeber -  a data store handles many resources
259     if (evt.getResourceID().equals(this.doc.getLRPersistenceId()))  {
260 //System.out.println("ASNAME=["+this.getName()+"],resourceDeleted() called");
261 
262       //unregister self
263 //this is not the correct way, since the resource is null in this case
264 //      DataStore ds = (DataStore)evt.getResource();
265       DataStore ds = this.doc.getDataStore();
266       if (ds != null)
267         ds.removeDatastoreListener(this);
268     }
269 
270   }//resourceDeleted
271 
272   /**
273    * Called by a datastore when a resource has been wrote into the datastore
274    */
275   public void resourceWritten(DatastoreEvent evt){
276     Assert.assertNotNull(evt);
277     Assert.assertNotNull(evt.getResourceID());
278 
279     //check if this is our resource
280     //rememeber -  a data store handles many resources
281     if (evt.getResourceID().equals(this.doc.getLRPersistenceId()))  {
282 //System.out.println("ASNAME=["+this.getName()+"],resourceWritten() called");
283 
284       //clear lists with updates - we're synced with the DB
285       clearChangeLists();
286     }
287   }
288 
289 
290   private void clearChangeLists() {
291 
292     //ok, we're synced now, clear all lists with changed IDs
293     synchronized(this) {
294 //System.out.println("clearing lists...");
295       this.addedAnnotations.clear();
296       this.updatedAnnotations.clear();
297       this.removedAnnotations.clear();
298     }
299   }
300 
301   public Collection getAddedAnnotations() {
302 //System.out.println("getAddedIDs() called");
303     HashSet result = new HashSet();
304     result.addAll(this.addedAnnotations);
305 
306     return result;
307   }
308 
309 
310   public Collection getChangedAnnotations() {
311 //System.out.println("getChangedIDs() called");
312     HashSet result = new HashSet();
313     result.addAll(this.updatedAnnotations);
314 
315     return result;
316   }
317 
318 
319   public Collection getRemovedAnnotations() {
320 //System.out.println("getremovedIDs() called...");
321     HashSet result = new HashSet();
322     result.addAll(this.removedAnnotations);
323 
324     return result;
325   }
326 
327   public void annotationUpdated(AnnotationEvent e){
328     Annotation ann = (Annotation) e.getSource();
329 
330     //check if the annotation is newly created
331     //if so, do not add it to the update list, since it was not stored in the
332     //database yet, so the most recent value will be inserted into the DB upon
333     //DataStore::sync()
334     if (false == this.addedAnnotations.contains(ann)) {
335       this.updatedAnnotations.add(ann);
336     }
337   }
338 
339   /** Add an existing annotation. Returns true when the set is modified. */
340   public boolean add(Object o) throws ClassCastException {
341 
342     boolean result = super.add(o);
343 
344     if (true == result) {
345       //register as listener for update events from this annotation
346       Annotation ann = (Annotation)o;
347       ann.addAnnotationListener(this);
348 
349       //add to the newly created annotations set
350       this.addedAnnotations.add(ann);
351     }
352 
353     return result;
354   }
355 
356   /** Remove an element from this set. */
357   public boolean remove(Object o) throws ClassCastException {
358 
359     boolean result = super.remove(o);
360 
361     if (true == result) {
362       //UNregister as listener for update events from this annotation
363       Annotation ann = (Annotation)o;
364       ann.removeAnnotationListener(this);
365 
366       //1. check if this annot is in the newly created annotations set
367       if (this.addedAnnotations.contains(ann)) {
368         //a new annotation that was deleted afterwards, remove it from all sets
369         this.addedAnnotations.remove(ann);
370       }
371       else {
372 
373         //2. check if the annotation was updated, if so, remove it from the
374         //update list
375         if (this.updatedAnnotations.contains(ann)) {
376           this.updatedAnnotations.remove(ann);
377         }
378 
379         //3. add to the list with deleted anns
380         this.removedAnnotations.add(ann);
381       }
382     }
383 
384     return result;
385   }
386 
387 
388 
389 }