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.CLASSIC) ? new 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 plugInDir) throws 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 ontologyURL) throws 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 = (AbstractLanguageAnalyser) Factory.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 ontologyURL) throws 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 ontologyURL) throws 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 = (String) annot.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 doc) throws InvalidOffsetException;
283
284 public void annotate(Document doc) throws 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 doc) throws 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 type) throws 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 type) throws 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 type) throws InvalidOffsetException {
344 as.add(new Long(curOffset), new Long(curOffset + dfltAnnotLen), type, emptyFeat);
345 return this;
346 }
347 }
348
349 }
|