AnnotationSetTransfer.java
001 /*
002  * AnnotationSetTransfer.java
003  *
004  * Copyright (c) 2009, The University of Sheffield.
005  *
006  * This file is part of GATE (see http://gate.ac.uk/), and is free software,
007  * licenced under the GNU Library General Public License, Version 2, June 1991
008  * (in the distribution as file licence.html, and also available at
009  * http://gate.ac.uk/gate/licence.html).
010  *
011  * Mark A. Greenwood, 7/10/2009
012  */
013 package gate.creole.annotransfer;
014 
015 import gate.Annotation;
016 import gate.AnnotationSet;
017 import gate.Factory;
018 import gate.FeatureMap;
019 import gate.GateConstants;
020 import gate.ProcessingResource;
021 import gate.Resource;
022 import gate.creole.AbstractLanguageAnalyser;
023 import gate.creole.ExecutionException;
024 import gate.creole.ResourceInstantiationException;
025 import gate.util.BomStrippingInputStreamReader;
026 import gate.util.InvalidOffsetException;
027 
028 import java.io.BufferedReader;
029 import java.io.IOException;
030 import java.io.Serializable;
031 import java.net.URL;
032 import java.util.ArrayList;
033 import java.util.HashMap;
034 import java.util.Iterator;
035 import java.util.List;
036 import java.util.Map;
037 
038 import org.apache.commons.io.IOUtils;
039 
040 /**
041  * This plugin allows the names of annotations and features to be
042  * changed as well as transfered from one annotation set to another.
043  * Think of it as an extended version of the old AnnotationSet Transfer
044  * plugin.
045  
046  @author Mark A. Greenwood
047  */
048 public class AnnotationSetTransfer extends AbstractLanguageAnalyser
049                                                                    implements
050                                                                    ProcessingResource,
051                                                                    Serializable {
052 
053   private static final long serialVersionUID = 3502991817151932971L;
054 
055   private String tagASName = GateConstants.ORIGINAL_MARKUPS_ANNOT_SET_NAME;
056 
057   private String outputASName, inputASName, textTagName;
058 
059   private URL configURL;
060 
061   private Boolean copyAnnotations, transferAllUnlessFound;
062 
063   private gate.AnnotationSet bodyAnnotations = null;
064 
065   private List<String> annotationTypes = null;
066 
067   Map<String, Mapping> mappings = new HashMap<String, Mapping>();
068 
069   @Override
070   public Resource init() throws ResourceInstantiationException {
071     return this;
072   }
073 
074   @Override
075   public void execute() throws ExecutionException {
076     AnnotationSet inputAS = document.getAnnotations(inputASName);
077     AnnotationSet outputAS = document.getAnnotations(outputASName);
078     AnnotationSet tagAS = document.getAnnotations(tagASName);
079     AnnotationSet annotsToTransfer = null;
080 
081     boolean newID = copyAnnotations && inputAS.equals(outputAS);
082 
083     mappings.clear();
084 
085     // TODO clean this up so we don't have to repeat ourselves
086     if(configURL != null) {
087 
088       BufferedReader in = null;
089       try {
090         in = new BomStrippingInputStreamReader(configURL
091                 .openStream());
092 
093         String line = in.readLine();
094         while(line != null) {
095           if(!line.trim().equals("")) {
096             String[] data = line.split("="2);
097             String oldName = data[0].trim();
098             String newName = data.length == ? data[1].trim() null;
099             mappings.put(oldName, new Mapping(oldName, newName));
100           }
101           line = in.readLine();
102         }
103       }
104       catch(IOException ioe) {
105         ioe.printStackTrace();
106       }
107       finally {
108         IOUtils.closeQuietly(in);
109       }
110     }
111     else if(annotationTypes != null) {
112       for(String type : annotationTypes) {
113         String[] data = type.split("="2);
114         String oldName = data[0].trim();
115         String newName = data.length == ? data[1].trim() null;
116 
117         mappings.put(oldName, new Mapping(oldName, newName));
118       }
119     }
120     // else
121     // throw new
122     // ExecutionException("The annotation list and URL cannot both be null");
123 
124     if(mappings.size() 0) {
125       annotsToTransfer = inputAS.get(mappings.keySet());
126     }
127     else {
128       // transfer everything
129       annotsToTransfer = inputAS.get();
130     }
131     // in case of no one annotation from some of annotationTypes
132     if(annotsToTransfer == null || annotsToTransfer.size() == 0return;
133     // check if we have a BODY annotation
134     // if not, just copy all
135     if(textTagName == null || textTagName.equals("")) {
136       // remove from input set unless we copy only
137       if(!copyAnnotationsinputAS.removeAll(annotsToTransfer);
138       transferAnnotations(new ArrayList<Annotation>(annotsToTransfer),
139               outputAS, newID);
140 
141       return;
142     }
143     // get the BODY annotation
144     bodyAnnotations = tagAS.get(textTagName);
145     if(bodyAnnotations == null || bodyAnnotations.isEmpty()) {
146       // outputAS.addAll(inputAS);
147       if(transferAllUnlessFound) {
148         // remove from input set unless we copy only
149         if(!copyAnnotationsinputAS.removeAll(annotsToTransfer);
150         transferAnnotations(new ArrayList<Annotation>(annotsToTransfer),
151                 outputAS, newID);
152       }
153       return;
154     }
155     List<Annotation> annots2Move = new ArrayList<Annotation>();
156     Iterator<Annotation> bodyIter = bodyAnnotations.iterator();
157     while(bodyIter.hasNext()) {
158       Annotation bodyAnn = bodyIter.next();
159       Long start = bodyAnn.getStartNode().getOffset();
160       Long end = bodyAnn.getEndNode().getOffset();
161       // get all annotations we want transferred
162       AnnotationSet annots2Copy = annotsToTransfer.getContained(start, end);
163       // copy them to the new set and delete them from the old one
164       annots2Move.addAll(annots2Copy);
165     }
166     if(!copyAnnotationsinputAS.removeAll(annots2Move);
167     transferAnnotations(annots2Move, outputAS, newID);
168   }
169 
170   private void transferAnnotations(List<Annotation> toTransfer,
171           AnnotationSet to, boolean newIDthrows ExecutionException {
172     for(Annotation annot : toTransfer) {
173       Mapping m = mappings.get(annot.getType());
174 
175       String name = (m == null || m.newName == null
176               ? annot.getType()
177               : m.newName);
178 
179       try {
180         FeatureMap params = Factory.newFeatureMap();
181         params.putAll(annot.getFeatures());
182         if(newID) {
183           to.add(annot.getStartNode().getOffset(), annot.getEndNode()
184                   .getOffset(), name, params);
185         }
186         else {
187           to.add(annot.getId(), annot.getStartNode().getOffset(), annot
188                   .getEndNode().getOffset(), name, params);
189         }
190       }
191       catch(InvalidOffsetException e) {
192         throw new ExecutionException(e);
193       }
194     }
195   }
196 
197   public void setTagASName(String newTagASName) {
198     // if given an empty string, set to the default set
199     if("".equals(newTagASName))
200       tagASName = null;
201     else tagASName = newTagASName;
202   }
203 
204   public String getTagASName() {
205     return tagASName;
206   }
207 
208   public void setInputASName(String newInputASName) {
209     inputASName = newInputASName;
210   }
211 
212   public String getInputASName() {
213     return inputASName;
214   }
215 
216   public void setOutputASName(String newOutputASName) {
217     outputASName = newOutputASName;
218   }
219 
220   public String getOutputASName() {
221     return outputASName;
222   }
223 
224   public void setTextTagName(String newTextTagName) {
225     textTagName = newTextTagName;
226   }
227 
228   public String getTextTagName() {
229     return textTagName;
230   }
231 
232   public List<String> getAnnotationTypes() {
233     return annotationTypes;
234   }
235 
236   public void setAnnotationTypes(List<String> newTypes) {
237     annotationTypes = newTypes;
238   }
239 
240   public void setConfigURL(URL url) {
241     configURL = url;
242   }
243 
244   public URL getConfigURL() {
245     return configURL;
246   }
247 
248   public Boolean getCopyAnnotations() {
249     return this.copyAnnotations;
250   }
251 
252   public void setCopyAnnotations(Boolean copyAnnotations) {
253     this.copyAnnotations = copyAnnotations;
254   }
255 
256   public Boolean getTransferAllUnlessFound() {
257     return this.transferAllUnlessFound;
258   }
259 
260   public void setTransferAllUnlessFound(Boolean value) {
261     this.transferAllUnlessFound = value;
262   }
263 
264   static class Mapping implements Serializable {
265     
266     private static final long serialVersionUID = 4708558248536631082L;
267     
268     String oldName, newName;
269 
270     // TODO implement the renaming of features as well as annotations
271     // Map<String, String> features = new HashMap<String, String>();
272 
273     public Mapping(String oldName, String newName) {
274       this.oldName = oldName;
275       this.newName = newName;
276     }
277 
278     @Override
279     public String toString() {
280       StringBuilder result = new StringBuilder();
281       result.append(oldName);
282       if(newName != null) {
283         result.append("=").append(newName);
284       }
285       return result.toString();
286     }
287   }
288 }