BaseJapeTests.java
001 /*
002  *  TestConstraints
003  *
004  *  Copyright (c) 1995-2010, 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  *  Eric Sword, 03/09/08
013  *
014  *  $Id: BaseJapeTests.java 13726 2011-04-20 16:31:46Z ian_roberts $
015  */
016 package gate.jape.functest;
017 
018 import gate.Annotation;
019 import gate.AnnotationSet;
020 import gate.Document;
021 import gate.Factory;
022 import gate.FeatureMap;
023 import gate.Gate;
024 import gate.Resource;
025 import gate.creole.AbstractLanguageAnalyser;
026 import gate.creole.ExecutionException;
027 import gate.creole.ResourceInstantiationException;
028 import gate.util.Files;
029 import gate.util.GateException;
030 import gate.util.InvalidOffsetException;
031 import gate.util.OffsetComparator;
032 
033 import java.io.File;
034 import java.io.IOException;
035 import java.io.InputStream;
036 import java.net.MalformedURLException;
037 import java.net.URL;
038 import java.util.Properties;
039 import java.util.Set;
040 import java.util.TreeSet;
041 
042 import junit.framework.TestCase;
043 
044 import org.apache.log4j.BasicConfigurator;
045 import org.apache.log4j.Logger;
046 import org.apache.log4j.PropertyConfigurator;
047 
048 /**
049  * Tests for Constraint predicate logic
050  */
051 public abstract class BaseJapeTests extends TestCase {
052     /** JAPE Transducer under test. CHANGE THIS to test another Transducer */
053     public static final TransducerType transducerType = TransducerType.CLASSIC;
054 
055     private static final Logger logger = Logger.getLogger(BaseJapeTests.class);
056 
057     protected static final String DEFAULT_DATA_FILE = "jape/InputTexts/AveShort";
058 
059     public BaseJapeTests(String name) {
060   super(name);
061   setUpGate()//TODO remove when figure out why TestConstraints won't start
062     }
063 
064     /**
065      * Initializes GATE and sets up plug-ins. The operation is idempotent.
066      */
067     protected static void setUpGate() {
068   if (Gate.isInitialised()) {
069       logger.warn("GATE already intialized and set up for JAPE Transducer tests.");
070       return;
071   }
072 
073   Properties logConfProps = new Properties();
074   InputStream logConfStream = BaseJapeTests.class.getResourceAsStream("log4j-test.properties");
075   assert logConfStream != null "Cannot locate LOG4J properties file";
076   try {
077       logConfProps.load(logConfStream);
078       logConfStream.close();
079   catch (IOException e2) {
080       logger.warn("Unable to load logging properties.");
081       BasicConfigurator.configure();
082   }
083 
084   PropertyConfigurator.configure(logConfProps);
085 
086   if (System.getProperty("gate.home"== null)
087       System.setProperty("gate.home"".");
088   try {
089       Gate.init();
090   catch (GateException e1) {
091       String errMsg = "Unable to initialize GATE";
092       logger.fatal(errMsg);
093       throw new RuntimeException(errMsg);
094   }
095   logger.debug("GATE home is: " + Gate.getGateHome().getAbsolutePath());
096 
097   if (!Gate.getPluginsHome().isDirectory()) {
098       String errMsg = "GATE home and plug-in directory set up failure.";
099       logger.fatal(errMsg);
100       throw new RuntimeException(errMsg);
101   }
102 
103   /** CHANGE THIS if JAPE Transducer need more plug-ins */
104   final File[] plugInsToLoad = new File(Gate.getPluginsHome()"Ontology") };
105 
106   for (File plugInDir : plugInsToLoad) {
107       try {
108     registerCREOLE(plugInDir);
109       catch (GateException ge) {
110     logger.warn(plugInDir.getAbsoluteFile() " was not loaded.");
111       }
112   }
113 
114   try {
115       registerCREOLE((transducerType == TransducerType.CLASSICnew File(Gate.getPluginsHome()"ANNIE": transducerType.getPlugInDir());
116   catch (Exception e) {
117       String errMsg = "JAPE Transducer plug-in cannot be loaded.";
118       logger.fatal(errMsg);
119       throw new RuntimeException(errMsg);
120   }
121     }
122 
123     private static void registerCREOLE(File plugInDirthrows GateException {
124   if (plugInDir == null || !plugInDir.isDirectory()) {
125       throw new IllegalArgumentException(plugInDir.getAbsolutePath()
126         " is not a valid plug-in directory.");
127   }
128   try {
129       File creolePath = plugInDir.getCanonicalFile();
130       Gate.getCreoleRegister().registerDirectories(creolePath.toURI().toURL());
131   catch (IOException e) {
132       throw new GateException(e);
133   }
134     }
135 
136     private static Resource createOntology(String ontologyURLthrows MalformedURLException {
137   FeatureMap params = Factory.newFeatureMap();
138   params.put("rdfXmlURL"new URL(ontologyURL))//TODO: FeatureMap keys should be defined as constants somewhere
139   params.put("loadImports"true);
140   final String ontologyClass = "gate.creole.ontology.impl.sesame.OWLIMOntology";
141   Resource ontology = null;
142   try {
143       ontology = Factory.createResource(ontologyClass, params);
144   catch (ResourceInstantiationException rie) {
145       assert false "Cannot instantiate ontology class: " + ontologyClass;
146   }
147   return ontology;
148     }
149 
150     /**
151      * Executes transducer with the provided parameters and returns transduced annotations ordered
152      
153      @param doc a GATE document with initial annotations 
154      @param japeFile a file with the JAPE grammar
155      @param ontologyURL optional ontology URL. Might be null.
156      @return an ordered set of transduced annotations
157      
158      @throws MalformedURLException
159      @throws ResourceInstantiationException
160      @throws ExecutionException
161      */
162     private Set<Annotation> runTransducer(Document doc, String japeFile, String ontologyURL)
163       throws MalformedURLException, ResourceInstantiationException, ExecutionException {
164 
165   if (doc == null || japeFile == null) {
166       throw new IllegalArgumentException("Document or JAPE file must not be null");
167   }
168   FeatureMap params = Factory.newFeatureMap();
169   URL japeUrl = Files.getGateResource(japeFile);
170   if (japeUrl == null) {
171       throw new IllegalArgumentException("Resource with relative path: " + japeFile + " is missing.");
172   }
173 
174   switch (transducerType) {
175   case PLUS:
176   case PDAPLUS: {
177       params.put("sourceType""JAPE")//TODO: FeatureMap keys should be defined as constants somewhere
178       params.put("sourceURL", japeUrl);
179   }
180       break;
181   case CLASSIC:
182   case PDA: {
183       params.put("grammarURL", japeUrl);
184   }
185       break;
186   default:
187       String errMsg = "Unknown JAPE transducer type";
188       logger.fatal(errMsg);
189       throw new IllegalArgumentException(errMsg);
190   }
191 
192   params.put("encoding""UTF-8");
193 
194   final String outputAsName = "Output";
195   params.put("outputASName", outputAsName);
196 
197   if (ontologyURL != null) {
198       Resource ontology = createOntology(ontologyURL);
199       params.put("ontology", ontology);
200   }
201 
202   AbstractLanguageAnalyser transducer = (AbstractLanguageAnalyserFactory.createResource(
203     transducerType.getFqdnClass(), params);
204   transducer.setDocument(doc);
205   transducer.execute();
206 
207   Set<Annotation> orderedResults = new TreeSet<Annotation>(new OffsetComparator());
208   orderedResults.addAll(doc.getAnnotations(outputAsName));
209   return orderedResults;
210     }
211 
212     /* Test Utility Methods */
213     protected Set<Annotation> doTest(String docResourcePath, String japeResourcePath, AnnotationCreator ac,
214       String ontologyURLthrows Exception {
215 
216   Document doc = Factory.newDocument(Files.getGateResourceAsString(docResourcePath));
217   return doTest(doc, japeResourcePath, ac, ontologyURL);
218     }
219 
220     protected Set<Annotation> doTest(String docResourcePath, String japeResourcePath, AnnotationCreator ac)
221       throws Exception {
222   return doTest(docResourcePath, japeResourcePath, ac, null);
223     }
224 
225     protected Set<Annotation> doTest(Document doc, String japeResourcePath, AnnotationCreator ac,
226       String ontologyURLthrows Exception {
227   if (ac != null)
228       ac.annotate(doc);
229   Set<Annotation> orderedResults = runTransducer(doc, japeResourcePath, ontologyURL);
230   return orderedResults;
231     }
232 
233     /* Result Comparison */
234     /**
235      * Compares 2 ordered sets of annotations by comparison of the rules that created them.
236      */
237     protected static void compareResults(String[] expectedResults, Set<Annotation> actualResults) {
238   int i = 0;
239 
240   assertEquals("Number of the expected and transducet annotations must be equal.",
241     expectedResults.length, actualResults.size());
242 
243   for (Annotation annot : actualResults) {
244       String ruleName = (Stringannot.getFeatures().get("rule");
245       assertEquals("Annotation must be created by rule: " + expectedResults[i], expectedResults[i],
246         ruleName);
247       i++;
248   }
249     }
250 
251     protected final static void compareStartOffsets(Set<Annotation> res, int... startOffsets) {
252   assertEquals(startOffsets.length, res.size());
253   int i = 0;
254   for (Annotation annot : res) {
255       assertEquals("Annotation " + annot.getId() " must start at position " + startOffsets[i],
256         startOffsets[i], annot.getStartNode().getOffset().intValue());
257       i++;
258   }
259     }
260 
261     protected final static void compareEndOffsets(Set<Annotation> res, int... endOffsets) {
262   assertEquals(endOffsets.length, res.size());
263   int i = 0;
264   for (Annotation annot : res) {
265       assertEquals("Annotation  " + annot.getId() " msut end at position " + endOffsets[i],
266         endOffsets[i], annot.getEndNode().getOffset().intValue());
267       i++;
268   }
269     }
270 
271     /* Utility Classes */
272 
273     /**
274      * Callback interface used in the doTest method.
275      
276      @version $Revision$
277      @author esword
278      */
279     public static interface AnnotationCreator {
280   //public void setDoc(Document doc);
281 
282   public AnnotationSet createAnnots(Document docthrows InvalidOffsetException;
283   
284   public void annotate(Document docthrows InvalidOffsetException;
285 
286   //public AnnotationCreator addInc(String type);
287 
288   //public AnnotationCreator add(int start, int end, String type) throws InvalidOffsetException;
289 
290   //public AnnotationCreator add(int start, int end, String type, FeatureMap fm) throws InvalidOffsetException;
291 
292   //public AnnotationCreator add(String type);
293     }
294 
295     public static abstract class BaseAnnotationCreator implements AnnotationCreator {
296   protected AnnotationSet as;
297   protected int curOffset = 0;
298   protected int dfltAnnotLen = 2;
299   protected static FeatureMap emptyFeat = Factory.newFeatureMap();
300 
301   public BaseAnnotationCreator() {}
302 
303   public final void annotate(Document docthrows InvalidOffsetException {
304       as = doc.getAnnotations();
305       createAnnots(doc);
306   }
307 
308   /**
309    * Add an annotation of the given type over the given range. Does not
310    * increment curOffset.
311    @throws InvalidOffsetException 
312    */
313   protected AnnotationCreator add(int start, int end, String typethrows InvalidOffsetException {
314       return add(start, end, type, emptyFeat);
315   }
316 
317   /**
318    * Add an annotation of the given type over the given range. Does not
319    * increment curOffset.
320    @throws InvalidOffsetException 
321    */
322   protected AnnotationCreator add(int start, int end, String type, FeatureMap fm)
323     throws InvalidOffsetException {
324       as.add(new Long(start)new Long(end), type, fm);
325       return this;
326   }
327 
328   /**
329    * Add an annotation of the given type at the current offset and
330    * increment the placement counter.
331    @throws InvalidOffsetException 
332    */
333   protected AnnotationCreator addInc(String typethrows InvalidOffsetException {
334       add(type);
335       curOffset += dfltAnnotLen;
336       return this;
337   }
338 
339   /**
340    * Add annot at the current offset
341    @throws InvalidOffsetException 
342    */
343   protected AnnotationCreator add(String typethrows InvalidOffsetException {
344       as.add(new Long(curOffset)new Long(curOffset + dfltAnnotLen), type, emptyFeat);
345       return this;
346   }
347     }
348 
349 }