1   /*
2    *  DatabaseCorpusImpl.java
3    *
4    *  Copyright (c) 1998-2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Marin Dimitrov, 05/Nov/2001
12   *
13   *  $Id: DatabaseCorpusImpl.java,v 1.7 2001/11/12 17:14:12 kalina Exp $
14   */
15  
16  package gate.corpora;
17  
18  import java.util.*;
19  
20  import junit.framework.*;
21  
22  import gate.*;
23  import gate.persist.*;
24  import gate.annotation.*;
25  import gate.creole.*;
26  import gate.event.*;
27  import gate.util.*;
28  
29  
30  public class DatabaseCorpusImpl extends CorpusImpl
31                                  implements DatastoreListener,
32                                             EventAwareLanguageResource {
33  
34  
35    private boolean featuresChanged;
36    private boolean nameChanged;
37    /**
38     * The listener for the events coming from the features.
39     */
40    protected EventsHandler eventHandler;
41  
42  
43    public DatabaseCorpusImpl(String _name,
44                              DatabaseDataStore _ds,
45                              Long _persistenceID,
46                              FeatureMap _features,
47                              Vector _dbDocs) {
48  
49      super();
50  
51      this.name = _name;
52      this.dataStore = _ds;
53      this.lrPersistentId = _persistenceID;
54      this.features = _features;
55      this.supportList = _dbDocs;
56  
57      this.featuresChanged = false;
58      this.nameChanged = false;
59  
60      //3. add the listeners for the features
61      if (eventHandler == null)
62        eventHandler = new EventsHandler();
63      this.features.addFeatureMapListener(eventHandler);
64  
65  
66      //4. add self as listener for the data store, so that we'll know when the DS is
67      //synced and we'll clear the isXXXChanged flags
68      this.dataStore.addDatastoreListener(this);
69    }
70  
71    public boolean add(Object o){
72  
73      Assert.assertNotNull(o);
74      boolean result = false;
75  
76      //accept only documents
77      if (false == o instanceof Document) {
78        throw new IllegalArgumentException();
79      }
80  
81      Document doc = (Document)o;
82  
83      //assert docs are either transient or from the same datastore
84      if (isValidForAdoption(doc)) {
85        result = super.add(doc);
86      }
87  
88      if (result) {
89        fireDocumentAdded(new CorpusEvent(this,
90                                          doc,
91                                          this.supportList.size()-1,
92                                          CorpusEvent.DOCUMENT_ADDED));
93      }
94  
95      return result;
96    }
97  
98  
99    public void add(int index, Object element){
100 
101     Assert.assertNotNull(element);
102     Assert.assertTrue(index >= 0);
103 
104     long    collInitialSize = this.supportList.size();
105 
106     //accept only documents
107     if (false == element instanceof Document) {
108       throw new IllegalArgumentException();
109     }
110 
111     Document doc = (Document)element;
112 
113     //assert docs are either transient or from the same datastore
114     if (isValidForAdoption(doc)) {
115       super.add(index,doc);
116 
117       //if added then fire event
118       if (this.supportList.size() > collInitialSize) {
119         fireDocumentAdded(new CorpusEvent(this,
120                                           doc,
121                                           index,
122                                           CorpusEvent.DOCUMENT_ADDED));
123       }
124     }
125   }
126 
127 
128 
129   public boolean addAll(Collection c){
130 
131     boolean collectionChanged = false;
132 
133     Iterator it = c.iterator();
134     while (it.hasNext()) {
135       Document doc = (Document)it.next();
136       if (isValidForAdoption(doc)) {
137         collectionChanged |= add(doc);
138       }
139     }
140 
141     return collectionChanged;
142   }
143 
144 
145   public boolean addAll(int index, Collection c){
146 
147     Assert.assertTrue(index >=0);
148 
149     //funny enough add(index,element) returns void and not boolean
150     //so we can't use it
151     boolean collectionChanged = false;
152     int collInitialSize = this.supportList.size();
153     int currIndex = index;
154 
155     Iterator it = c.iterator();
156     while (it.hasNext()) {
157       Document doc = (Document)it.next();
158       if (isValidForAdoption(doc)) {
159         add(currIndex++,doc);
160       }
161     }
162 
163     return (this.supportList.size() > collInitialSize);
164   }
165 
166 
167   private boolean isValidForAdoption(LanguageResource lr) {
168 
169     Long lrID = (Long)lr.getLRPersistenceId();
170 
171     if (null == lrID ||
172         (this.getDataStore() != null && lr.getDataStore().equals(this.getDataStore()))) {
173       return true;
174     }
175     else {
176       return false;
177     }
178   }
179 
180   public void resourceAdopted(DatastoreEvent evt){
181   }
182 
183   public void resourceDeleted(DatastoreEvent evt){
184 
185     Assert.assertNotNull(evt);
186     Long  deletedID = (Long)evt.getResourceID();
187     Assert.assertNotNull(deletedID);
188 
189     //unregister self as listener from the DataStore
190     if (deletedID.equals(this.getLRPersistenceId())) {
191       //someone deleted this corpus
192       this.supportList.clear();
193       getDataStore().removeDatastoreListener(this);
194     }
195 
196     //check if the ID is of a document the corpus contains
197     Iterator it = this.supportList.iterator();
198     while (it.hasNext()) {
199       Document doc = (Document)it.next();
200       if (doc.getLRPersistenceId().equals(deletedID)) {
201         this.supportList.remove(doc);
202         break;
203       }
204     }
205 
206 
207   }
208 
209   public void resourceWritten(DatastoreEvent evt){
210     Assert.assertNotNull(evt);
211     Assert.assertNotNull(evt.getResourceID());
212 
213     //is the event for us?
214     if (evt.getResourceID().equals(this.getLRPersistenceId())) {
215       //wow, the event is for me
216       //clear all flags, the content is synced with the DB
217           this.featuresChanged =
218             this.nameChanged = false;
219     }
220   }
221 
222   public boolean isResourceChanged(int changeType) {
223 
224     switch(changeType) {
225 
226       case EventAwareLanguageResource.RES_FEATURES:
227         return this.featuresChanged;
228       case EventAwareLanguageResource.RES_NAME:
229         return this.nameChanged;
230       default:
231         throw new IllegalArgumentException();
232     }
233 
234   }
235 
236   /** Sets the name of this resource*/
237   public void setName(String name){
238     super.setName(name);
239 
240     this.nameChanged = true;
241   }
242 
243 
244   /** Set the feature set */
245   public void setFeatures(FeatureMap features) {
246     //1. save them first, so we can remove the listener
247     FeatureMap oldFeatures = this.features;
248 
249     super.setFeatures(features);
250 
251     this.featuresChanged = true;
252 
253     //4. sort out the listeners
254     if (eventHandler != null)
255       oldFeatures.removeFeatureMapListener(eventHandler);
256     else
257       eventHandler = new EventsHandler();
258     this.features.addFeatureMapListener(eventHandler);
259   }
260 
261 
262   /**
263    * All the events from the features are handled by
264    * this inner class.
265    */
266   class EventsHandler implements gate.event.FeatureMapListener {
267     public void featureMapUpdated(){
268       //tell the document that its features have been updated
269       featuresChanged = true;
270     }
271   }
272 
273   /**
274    * Overriden to remove the features listener, when the document is closed.
275    */
276   public void cleanup() {
277     super.cleanup();
278     if (eventHandler != null)
279       this.features.removeFeatureMapListener(eventHandler);
280   }///inner class EventsHandler
281 
282 }