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.11 2001/11/09 17:50:21 kalina 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  
31    /**
32     * The listener for the events coming from the document (annotations and
33     * annotation sets added or removed).
34     */
35    protected EventsHandler eventHandler;
36  
37    protected HashSet addedAnnotations = new HashSet();
38    protected HashSet removedAnnotations = new HashSet();
39    protected HashSet updatedAnnotations = new HashSet();
40  
41    private boolean validating = false;
42  
43    public void assertValid() {
44  
45      if (validating)
46        return;
47  
48      validating = true;
49      //avoid recursion
50  
51      //doc can't be null
52      Assert.assertNotNull(this.doc);
53      //doc.assertValid();
54  
55      validating = false;
56    }
57  
58    /** Construction from Document. */
59    public DatabaseAnnotationSetImpl(Document doc) {
60  
61      super(doc);
62  
63      //preconditions
64      Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
65  
66      eventHandler = new EventsHandler();
67      this.addAnnotationSetListener(eventHandler);
68  
69      //add self as listener for sync events from the document's datastore
70      doc.getDataStore().removeDatastoreListener(this);
71      doc.getDataStore().addDatastoreListener(this);
72  
73    } // construction from document
74  
75    /** Construction from Document and name. */
76    public DatabaseAnnotationSetImpl(Document doc, String name) {
77      super(doc, name);
78  
79      //preconditions
80      Assert.assertTrue(doc instanceof DatabaseDocumentImpl);
81  
82      eventHandler = new EventsHandler();
83      this.addAnnotationSetListener(eventHandler);
84  
85      //add self as listener for sync events from the document's datastore
86      doc.getDataStore().removeDatastoreListener(this);
87      doc.getDataStore().addDatastoreListener(this);
88  
89    } // construction from document and name
90  
91  
92    /** Construction from Document and name. */
93    public DatabaseAnnotationSetImpl(Document doc, Collection c) {
94      this(c);
95      this.doc = (DocumentImpl) doc;
96      //add self as listener for sync events from the document's datastore
97      doc.getDataStore().removeDatastoreListener(this);
98      doc.getDataStore().addDatastoreListener(this);
99    } // construction from document and name
100 
101   /** Construction from Document and name. */
102   public DatabaseAnnotationSetImpl(Document doc, String name, Collection c) {
103     this(doc,c);
104     this.name = name;
105     //add self as listener for sync events from the document's datastore
106     doc.getDataStore().removeDatastoreListener(this);
107     doc.getDataStore().addDatastoreListener(this);
108   } // construction from document and name
109 
110 
111   /** Construction from Collection (which must be an AnnotationSet) */
112   public DatabaseAnnotationSetImpl(Collection c) throws ClassCastException {
113 
114     super(c);
115 
116     //also copy the name, because that super one doesn't
117     this.name = ((AnnotationSet) c).getName();
118 
119     eventHandler = new EventsHandler();
120     this.addAnnotationSetListener(eventHandler);
121 
122     Iterator iter = this.iterator();
123     while(iter.hasNext())
124       ((Annotation) iter.next()).addAnnotationListener(eventHandler);
125 
126   } // construction from collection
127 
128 
129   public String toString() {
130     return super.toString()
131               + "added annots: " + addedAnnotations
132               + "removed annots: " + removedAnnotations
133               + "updated annots: " + updatedAnnotations;
134   }
135 
136   /**
137    * All the events from the document or its annotation sets are handled by
138    * this inner class.
139    */
140   class EventsHandler implements AnnotationListener,
141                                  AnnotationSetListener{
142 
143     public void annotationAdded(gate.event.AnnotationSetEvent e) {
144       AnnotationSet set = (AnnotationSet)e.getSource();
145       String setName = set.getName();
146       if (setName != DatabaseAnnotationSetImpl.this.name &&
147           ! setName.equals(DatabaseAnnotationSetImpl.this.name))
148         return;
149       Annotation ann = e.getAnnotation();
150       ann.addAnnotationListener(this);
151       DatabaseAnnotationSetImpl.this.addedAnnotations.add(ann);
152     }
153 
154     public void annotationRemoved(AnnotationSetEvent e){
155       AnnotationSet set = (AnnotationSet)e.getSource();
156       String setName = set.getName();
157       if (setName != DatabaseAnnotationSetImpl.this.name &&
158           ! setName.equals(DatabaseAnnotationSetImpl.this.name))
159         return;
160       Annotation ann = e.getAnnotation();
161       ann.removeAnnotationListener(this);
162 
163       //1. check if this annot is in the newly created annotations set
164       if (addedAnnotations.contains(ann)) {
165         //a new annotatyion that was deleted afterwards, remove it from all sets
166         DatabaseAnnotationSetImpl.this.addedAnnotations.remove(ann);
167         return;
168       }
169       //2. check if the annotation was updated, if so, remove it from the
170       //update list
171       if (updatedAnnotations.contains(ann)) {
172         DatabaseAnnotationSetImpl.this.updatedAnnotations.remove(ann);
173       }
174 
175       DatabaseAnnotationSetImpl.this.removedAnnotations.add(ann);
176     }
177 
178     public void annotationUpdated(AnnotationEvent e){
179       Annotation ann = (Annotation) e.getSource();
180 
181       //check if the annotation is newly created
182       //if so, do not add it to the update list, since it was not stored in the
183       //database yet, so the most recent value will be inserted into the DB upon
184       //DataStore::sync()
185       if (addedAnnotations.contains(ann)) {
186         return;
187       }
188 
189       DatabaseAnnotationSetImpl.this.updatedAnnotations.add(ann);
190     }
191 
192   }//inner class EventsHandler
193 
194 
195 
196   /**
197    * Called by a datastore when a new resource has been adopted
198    */
199   public void resourceAdopted(DatastoreEvent evt){
200     Assert.assertNotNull(evt);
201     Assert.assertNotNull(evt.getResourceID());
202 
203     //check if this is our resource
204     //rememeber -  a data store handles many resources
205     if (evt.getResourceID().equals(this.doc.getLRPersistenceId()))  {
206 //System.out.println("ASNAME=["+this.getName()+"], resourceAdopted() called");
207       //we're synced wtith the DB now
208       clearChangeLists();
209     }
210   }
211 
212   /**
213    * Called by a datastore when a resource has been deleted
214    */
215   public void resourceDeleted(DatastoreEvent evt){
216 
217     Assert.assertNotNull(evt);
218     Assert.assertNotNull(evt.getResourceID());
219 
220     //check if this is our resource
221     //rememeber -  a data store handles many resources
222     if (evt.getResourceID().equals(this.doc.getLRPersistenceId()))  {
223 //System.out.println("ASNAME=["+this.getName()+"],resourceDeleted() called");
224 
225       //unregister self
226 //this is not the correct way, since the resource is null in this case
227 //      DataStore ds = (DataStore)evt.getResource();
228       DataStore ds = this.doc.getDataStore();
229       if (ds != null)
230         ds.removeDatastoreListener(this);
231     }
232 
233   }//resourceDeleted
234 
235   /**
236    * Called by a datastore when a resource has been wrote into the datastore
237    */
238   public void resourceWritten(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()+"],resourceWritten() called");
246 
247       //clear lists with updates - we're synced with the DB
248       clearChangeLists();
249     }
250   }
251 
252 
253   private void clearChangeLists() {
254 
255     //ok, we're synced now, clear all lists with changed IDs
256     synchronized(this) {
257 //System.out.println("clearing lists...");
258       this.addedAnnotations.clear();
259       this.updatedAnnotations.clear();
260       this.removedAnnotations.clear();
261     }
262   }
263 
264   public Collection getAddedAnnotations() {
265 //System.out.println("getAddedIDs() called");
266     HashSet result = new HashSet();
267     result.addAll(this.addedAnnotations);
268 
269     return result;
270   }
271 
272 
273   public Collection getChangedAnnotations() {
274 //System.out.println("getChangedIDs() called");
275     HashSet result = new HashSet();
276     result.addAll(this.updatedAnnotations);
277 
278     return result;
279   }
280 
281 
282   public Collection getRemovedAnnotations() {
283 //System.out.println("getremovedIDs() called...");
284     HashSet result = new HashSet();
285     result.addAll(this.removedAnnotations);
286 
287     return result;
288   }
289 
290 }