AnnotationDeletePR.java
001 /*
002  *  AnnotationDeletePR.java
003  *
004  *  Copyright (c) 1995-2012, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  *
012  *  Kalina Bontcheva, 19/10/2001
013  *
014  *  $Id: AnnotationDeletePR.java 17588 2014-03-08 07:50:36Z markagreenwood $
015  */
016 
017 package gate.creole.annotdelete;
018 
019 import gate.Annotation;
020 import gate.AnnotationSet;
021 import gate.GateConstants;
022 import gate.ProcessingResource;
023 import gate.Resource;
024 import gate.creole.ANNIEConstants;
025 import gate.creole.AbstractLanguageAnalyser;
026 import gate.creole.ExecutionException;
027 import gate.creole.ResourceInstantiationException;
028 import gate.creole.metadata.CreoleParameter;
029 import gate.creole.metadata.CreoleResource;
030 import gate.creole.metadata.Optional;
031 import gate.creole.metadata.RunTime;
032 import gate.util.GateRuntimeException;
033 
034 import java.util.ArrayList;
035 import java.util.HashSet;
036 import java.util.Iterator;
037 import java.util.List;
038 import java.util.Map;
039 
040 /**
041  * This class is the implementation of a processing resource which
042  * deletes all annotations and sets other than 'original markups'.
043  * If put at the start of an application, it'll ensure that the
044  * document is restored to its clean state before being processed.
045  */
046 @CreoleResource(name = "Document Reset PR", icon = "document-reset",
047         comment = "Remove named annotation sets or reset the default annotation set",
048         helpURL = "http://gate.ac.uk/userguide/sec:misc-creole:reset")
049 public class AnnotationDeletePR extends AbstractLanguageAnalyser
050   implements ProcessingResource {
051 
052   private static final long serialVersionUID = 4738446480871610387L;
053 
054   public static final String
055     TRANSD_DOCUMENT_PARAMETER_NAME = "document";
056 
057   public static final String
058     TRANSD_ANNOT_TYPES_PARAMETER_NAME = "annotationTypes";
059 
060   public static final String
061     TRANSD_SETS_KEEP_PARAMETER_NAME = "setsToKeep";
062 
063   public static final String
064     TRANSD_SETS_KEEP_ORIGIANL_MARKUPS_ANNOT_SET = "keppOriginalMarkupsAS";
065   
066   protected String markupSetName = GateConstants.ORIGINAL_MARKUPS_ANNOT_SET_NAME;
067   protected List<String> annotationTypes;
068   protected List<String> setsToKeep;
069   protected List<String> setsToRemove = null;
070   protected Boolean keepOriginalMarkupsAS;
071   
072   /**
073    * This parameter specifies the names of sets to remove or reset. If this 
074    * list is empty or null, it will be ignored. If this list is not empty,
075    * all the other parameters of this PR are ignored. In order to include
076    * the default annotation set in this list, add a list entry that is either
077    * null or an empty String.
078    @param setsToRemove a List of String that contains the names of  
079    * annotation sets to remove.
080    */
081   @RunTime
082   @Optional
083   @CreoleParameter(
084     comment = "A list of annotation set names to reset/remove. If non-empty, ignore the parameters which specify what to keep" 
085     )
086   public void setSetsToRemove(List<String> setsToRemove) {
087     this.setsToRemove = setsToRemove;
088   }
089   public List<String> getSetsToRemove() {
090     return this.setsToRemove;
091   }  
092   
093   
094   /** Initialise this resource, and return it. */
095   @Override
096   public Resource init() throws ResourceInstantiationException
097   {
098     return super.init();
099   // init()
100 
101   /**
102   * Reinitialises the processing resource. After calling this method the
103   * resource should be in the state it is after calling init.
104   * If the resource depends on external resources (such as rules files) then
105   * the resource will re-read those resources. If the data used to create
106   * the resource has changed since the resource has been created then the
107   * resource will change too after calling reInit().
108   */
109   @Override
110   public void reInit() throws ResourceInstantiationException
111   {
112     init();
113   // reInit()
114 
115   /** Run the resource. */
116   @Override
117   public void execute() throws ExecutionException {
118 
119     if(document == null)
120       throw new GateRuntimeException("No document to process!");
121     
122     
123     
124     Object matchesMapObject = document.getFeatures().get(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME);
125     @SuppressWarnings("unchecked")
126     Map<String, List<List<Integer>>> matchesMap =
127             matchesMapObject instanceof Map
128                     (Map<String, List<List<Integer>>>)matchesMapObject
129                     null;
130 
131     if(setsToRemove != null && !setsToRemove.isEmpty()) {
132       // just remove or empty the sets in this list and ignore
133       // everything else
134       for(String setName : setsToRemove) {
135         if(setName == null || setName.equals("")) {
136           // clear the default annotation set
137           if (annotationTypes == null || annotationTypes.isEmpty()) {
138             document.getAnnotations().clear();
139             removeFromDocumentCorefData( (String)null, matchesMap);
140           else {
141             removeSubSet(document.getAnnotations(), matchesMap);
142           }
143           
144           //empty the relation set associated with the annotation set
145           document.getAnnotations().getRelations().clear();
146         else {
147           // remove this named set
148           if (annotationTypes == null || annotationTypes.isEmpty()) {
149             document.removeAnnotationSet(setName);
150             removeFromDocumentCorefDatasetName, matchesMap);
151           else {
152             removeSubSet(document.getAnnotations(setName), matchesMap);
153           }
154         }
155       }
156       if(matchesMap != null) {
157         document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
158                                    matchesMap);
159       }
160     else {
161       // ignore the setsToRemove parameter and process according to 
162       // the other parameters
163       
164       // determine which sets to keep
165       List<String> keepSets = new ArrayList<String>();
166       if(setsToKeep != nullkeepSets.addAll(setsToKeep);
167       if(keepOriginalMarkupsAS.booleanValue() && 
168          !keepSets.contains(markupSetName)) {
169           keepSets.add(markupSetName);
170       }
171 
172       //Unless we've been asked to keep it, first clear the default set,
173       //which cannot be removed
174       if(!keepSets.contains(null&& !keepSets.contains("")) {
175         if (annotationTypes == null || annotationTypes.isEmpty()) {
176           document.getAnnotations().clear();
177           removeFromDocumentCorefData( (String)null, matchesMap);
178         else {
179           removeSubSet(document.getAnnotations(), matchesMap);
180         }
181         //empty the relation set associated with the annotation set
182         document.getAnnotations().getRelations().clear();
183       }
184 
185       //get the names of all sets
186       Map<String,AnnotationSet> namedSets = document.getNamedAnnotationSets();
187       //nothing left to do if there are no named sets
188       if (namedSets != null && !namedSets.isEmpty()) {
189         //loop through the sets and delete them all unless
190         //we've been asked to keep them
191         List<String> setNames = new ArrayList<String>(namedSets.keySet());
192         Iterator<String> iter = setNames.iterator();
193         String setName;
194     
195         while (iter.hasNext()) {
196           setName = iter.next();
197           //check first whether this is the original markups or one of the sets
198           //that we want to keep
199           if (setName != null) {
200             // skip named sets from setsToKeep
201             if(keepSets.contains(setName)) continue;
202   
203             if (annotationTypes == null || annotationTypes.isEmpty()) {
204               document.removeAnnotationSet(setName);
205               removeFromDocumentCorefDatasetName, matchesMap);
206             else {
207               removeSubSet(document.getAnnotations(setName), matchesMap);
208             }
209           }//if
210         }
211       }
212 
213       // and finally we add it to the document
214       if(matchesMap != null) {
215         document.getFeatures().put(ANNIEConstants.DOCUMENT_COREF_FEATURE_NAME,
216                                    matchesMap);
217       }
218     // if(setsToRemove != null && !setsToRemove.isEmpty())
219   // execute()
220 
221   // method to update the Document-Coref-data
222   private void removeFromDocumentCorefData(String currentSet, Map<String,List<List<Integer>>> matchesMap) {
223     if(matchesMap == null)
224       return;
225 
226     // if this is defaultAnnotationSet, we cannot remove this
227     if(currentSet == null) {
228       List<List<Integer>> matches = matchesMap.get(currentSet);
229       if (matches == null || matches.size() == 0) {
230         // do nothing
231         return;
232       }
233       else {
234         matchesMap.put(currentSet, new ArrayList<List<Integer>>());
235       }
236     else {
237       // we remove this set from the Coref Data
238       matchesMap.remove(currentSet);
239     }
240   }
241 
242   // method to update the Document-Coref-data
243   private void removeAnnotationsFromCorefData(AnnotationSet annotations, String setName, Map<String,List<List<Integer>>> matchesMap) {
244     if(matchesMap == null) {
245       return;
246     }
247 
248     List<List<Integer>> matches = matchesMap.get(setName);
249     if(matches == null)
250       return;
251 
252     // each element in the matches is a group of annotation IDs
253     // so for each annotation we will have to traverse through all the lists and
254     // find out the annotation and remove it
255     List<Annotation> annots = new ArrayList<Annotation>(annotations);
256     for(int i=0; i<annots.size(); i++) {
257       Annotation toRemove = annots.get(i);
258       Iterator<List<Integer>> idIters = matches.iterator();
259       List<Integer> ids = new ArrayList<Integer>();
260       while(idIters.hasNext()) {
261         ids = idIters.next();
262         if(ids.remove(toRemove.getId())) {
263           // yes removed
264           break;
265         }
266       }
267       if(ids.size()==0) {
268         matches.remove(ids);
269       }
270     }
271     // and finally see if there is any group available
272     if(matches.size()==0) {
273       matchesMap.remove(setName);
274     }
275   }
276 
277   /* End */
278 
279   private void removeSubSet(AnnotationSet theSet, Map<String,List<List<Integer>>> matchMap) {
280     AnnotationSet toRemove = theSet.get(new HashSet<String>(annotationTypes));
281     if (toRemove == null || toRemove.isEmpty())
282       return;
283     theSet.removeAll(toRemove);
284     removeAnnotationsFromCorefData(toRemove, theSet.getName(), matchMap);
285   }//removeSubSet
286 
287   public void setMarkupASName(String newMarkupASName) {
288     markupSetName = newMarkupASName;
289   }
290 
291   public String  getMarkupASName() {
292     return markupSetName;
293   }
294 
295   public List<String> getAnnotationTypes() {
296     return this.annotationTypes;
297   }
298 
299   @RunTime
300   @Optional
301   @CreoleParameter(comment="The annotation types to delete otherwise delete all")
302   public void setAnnotationTypes(List<String> newTypes) {
303     annotationTypes = newTypes;
304   }
305 
306   public List<String> getSetsToKeep() {
307     return this.setsToKeep;
308   }
309 
310   @RunTime
311   @Optional
312   @CreoleParameter(comment="The annotation sets to keep otherwise delete all", defaultValue="Key")
313   public void setSetsToKeep(List<String> newSetNames) {
314     //we need to modify this list sometimes, so to make sure it's not some
315     //unmodifiable version, we'll create our own
316     setsToKeep = newSetNames != null ?
317             new ArrayList<String>(newSetNames):
318             new ArrayList<String>();
319   }
320 
321   public Boolean getKeepOriginalMarkupsAS() {
322     return keepOriginalMarkupsAS;
323   }
324 
325   @RunTime
326   @Optional
327   @CreoleParameter(comment="Should we keep the 'Original markups' annotation set?", defaultValue="true")
328   public void setKeepOriginalMarkupsAS(Boolean emptyDefaultAnnotationSet) {
329     this.keepOriginalMarkupsAS = emptyDefaultAnnotationSet;
330   }
331 
332 
333 // class AnnotationSetTransfer