Merge branch 'maintenance/3.1.x' into bugfix/UIMA-6404-Ruta-anchor-with-quantifier-ignores-matches
diff --git a/ruta-core/.gitignore b/ruta-core/.gitignore
new file mode 100644
index 0000000..862d276
--- /dev/null
+++ b/ruta-core/.gitignore
@@ -0,0 +1,2 @@
+input/
+TypeSystem.xml
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java b/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java
index 3778925..a6e28b1 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java
@@ -1151,7 +1151,11 @@
if (cas.getTypeSystem().subsumes(type, windowAnnotation.getType())) {
if (!sensitiveToVisibility || isVisible(windowAnnotation)) {
- result.add(windowAnnotation);
+ // the window defined by a BLOCK could actually have already been removed, thus we do not
+ // want to return it
+ if (cas.getAnnotationIndex(windowAnnotation.getType()).contains(windowAnnotation)) {
+ result.add(windowAnnotation);
+ }
}
}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/engine/RutaTestUtils.java b/ruta-core/src/main/java/org/apache/uima/ruta/engine/RutaTestUtils.java
index 5769578..d5230a4 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/engine/RutaTestUtils.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/engine/RutaTestUtils.java
@@ -19,14 +19,18 @@
package org.apache.uima.ruta.engine;
+import static org.apache.uima.fit.factory.TypeSystemDescriptionFactory.createTypeSystemDescription;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -34,6 +38,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.regex.Pattern;
import org.apache.uima.UIMAFramework;
import org.apache.uima.analysis_engine.AnalysisEngine;
@@ -60,6 +65,19 @@
public class RutaTestUtils {
+ public static final boolean DEBUG_MODE = isDebugging();
+
+ private static boolean isDebugging() {
+
+ Pattern debugPattern = Pattern.compile("-Xdebug|jdwp");
+ for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
+ if (debugPattern.matcher(arg).find()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static class TestFeature {
public String name;
@@ -151,24 +169,8 @@
AnalysisEngineDescription aed = (AnalysisEngineDescription) specifier;
TypeSystemDescription basicTypeSystem = aed.getAnalysisEngineMetaData().getTypeSystem();
- for (int i = 1; i <= amount; i++) {
- basicTypeSystem.addType(TYPE + i, "Type for Testing", "uima.tcas.Annotation");
- }
-
- if (complexTypes != null) {
- Set<Entry<String, String>> entrySet = complexTypes.entrySet();
- for (Entry<String, String> entry : entrySet) {
- String name = entry.getKey();
- TypeDescription addType = basicTypeSystem.addType(name, "Type for Testing",
- entry.getValue());
- if (features != null) {
- List<TestFeature> list = features.get(name);
- for (TestFeature f : list) {
- addType.addFeature(f.name, f.description, f.range);
- }
- }
- }
- }
+ addTestTypes(basicTypeSystem);
+ addAdditionalTypes(complexTypes, features, basicTypeSystem);
Collection<TypeSystemDescription> tsds = new ArrayList<TypeSystemDescription>();
tsds.add(basicTypeSystem);
@@ -248,23 +250,8 @@
ResourceSpecifier specifier = UIMAFramework.getXMLParser().parseResourceSpecifier(in);
AnalysisEngineDescription aed = (AnalysisEngineDescription) specifier;
TypeSystemDescription basicTypeSystem = aed.getAnalysisEngineMetaData().getTypeSystem();
- for (int i = 1; i <= 50; i++) {
- basicTypeSystem.addType("org.apache.uima.T" + i, "Type for Testing", "uima.tcas.Annotation");
- }
- if (complexTypes != null) {
- Set<Entry<String, String>> entrySet = complexTypes.entrySet();
- for (Entry<String, String> entry : entrySet) {
- String name = entry.getKey();
- TypeDescription addType = basicTypeSystem.addType(name, "Type for Testing",
- entry.getValue());
- if (features != null) {
- List<TestFeature> list = features.get(name);
- for (TestFeature f : list) {
- addType.addFeature(f.name, f.description, f.range);
- }
- }
- }
- }
+ addTestTypes(basicTypeSystem);
+ addAdditionalTypes(complexTypes, features, basicTypeSystem);
Collection<TypeSystemDescription> tsds = new ArrayList<TypeSystemDescription>();
tsds.add(basicTypeSystem);
TypeSystemDescription mergeTypeSystems = CasCreationUtils.mergeTypeSystems(tsds);
@@ -282,6 +269,31 @@
return cas;
}
+ public static void addTestTypes(TypeSystemDescription typeSystemDescription) {
+ for (int i = 1; i <= 50; i++) {
+ typeSystemDescription.addType("org.apache.uima.T" + i, "Type for Testing",
+ "uima.tcas.Annotation");
+ }
+ }
+
+ private static void addAdditionalTypes(Map<String, String> complexTypes,
+ Map<String, List<TestFeature>> features, TypeSystemDescription typeSystemDescription) {
+ if (complexTypes != null) {
+ Set<Entry<String, String>> entrySet = complexTypes.entrySet();
+ for (Entry<String, String> entry : entrySet) {
+ String name = entry.getKey();
+ TypeDescription addType = typeSystemDescription.addType(name, "Type for Testing",
+ entry.getValue());
+ if (features != null) {
+ List<TestFeature> list = features.get(name);
+ for (TestFeature f : list) {
+ addType.addFeature(f.name, f.description, f.range);
+ }
+ }
+ }
+ }
+ }
+
public static void printAnnotations(CAS cas, int typeId) {
Type t = getTestType(cas, typeId);
AnnotationIndex<AnnotationFS> ai = cas.getAnnotationIndex(t);
@@ -366,4 +378,34 @@
}
}
+ public static void storeTypeSystem() {
+ storeTypeSystem(Collections.emptyMap(), Collections.emptyMap());
+ }
+
+ public static void storeTypeSystem(Map<String, String> complexTypes,
+ Map<String, List<TestFeature>> features) {
+
+ File tsFile = new File("TypeSystem.xml");
+
+ try {
+
+ TypeSystemDescription typeSystemDescription = createTypeSystemDescription();
+ addTestTypes(typeSystemDescription);
+ addAdditionalTypes(complexTypes, features, typeSystemDescription);
+ try (OutputStream os = new FileOutputStream(tsFile)) {
+ typeSystemDescription.toXML(os);
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static Map<String, Object> getDebugParams() {
+ Map<String, Object> params = new LinkedHashMap<>();
+ params.put(RutaEngine.PARAM_DEBUG, true);
+ params.put(RutaEngine.PARAM_DEBUG_WITH_MATCHES, true);
+ params.put(RutaEngine.PARAM_CREATED_BY, true);
+ return params;
+ }
+
}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java b/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
index f85c809..6b99ab1 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
@@ -126,8 +126,8 @@
return result;
}
- protected void doneMatching(RuleMatch ruleMatch, RuleApply ruleApply, RutaStream stream,
- InferenceCrowd crowd) {
+ protected void doneMatching(RuleMatch ruleMatch, RuleApply ruleApply, RuleElement entryPoint,
+ RutaStream stream, InferenceCrowd crowd) {
if (!ruleMatch.isApplied()) {
ruleApply.add(ruleMatch, stream);
RutaRule rule = ruleMatch.getRule();
@@ -135,7 +135,8 @@
if (ruleMatch.matchedCompletely()) {
rule.getEnvironment().acceptTempVariableValues(localVariables);
rule.getRoot().applyRuleElements(ruleMatch, stream, crowd);
- } else {
+ } else if (entryPoint == null) {
+ // there was no dynamic lookahead, remove temp vars
rule.getEnvironment().clearTempVariables(localVariables);
}
ruleMatch.setApplied(true);
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java b/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
index e25038b..a38318c 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
@@ -534,7 +534,7 @@
// take care that failed matches wont be applied
ruleMatch.setMatched(ruleMatch.matched && !failed);
- doneMatching(ruleMatch, ruleApply, stream, crowd);
+ doneMatching(ruleMatch, ruleApply, entryPoint, stream, crowd);
return asList(ruleMatch);
}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRuleElement.java b/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRuleElement.java
index f616ab7..d4abcc6 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRuleElement.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRuleElement.java
@@ -110,7 +110,7 @@
result.addAll(fallbackContinue);
} else if (getContainer() instanceof RuleElementIsolator) {
// TODO move and refactor this:
- doneMatching(extendedMatch, ruleApply, stream, crowd);
+ doneMatching(extendedMatch, ruleApply, entryPoint, stream, crowd);
}
}
}
@@ -322,7 +322,7 @@
result.addAll(fallbackContinue);
} else {
// should never happen!
- doneMatching(ruleMatch, ruleApply, stream, crowd);
+ doneMatching(ruleMatch, ruleApply, entryPoint, stream, crowd);
}
}
}
@@ -335,8 +335,7 @@
InferenceCrowd crowd) {
RuleElementMatch result = new RuleElementMatch(this, containerMatch);
result.setRuleAnchor(ruleAnchor);
- List<EvaluatedCondition> evaluatedConditions = new ArrayList<>(
- conditions.size());
+ List<EvaluatedCondition> evaluatedConditions = new ArrayList<>(conditions.size());
// boolean base = matcher.match(annotation, stream, getParent());
boolean base = true;
MatchContext context = new MatchContext(annotation, this, ruleMatch, after);
diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/action/UnmarkTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/action/UnmarkTest.java
index 64b7152..3eb4289 100644
--- a/ruta-core/src/test/java/org/apache/uima/ruta/action/UnmarkTest.java
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/action/UnmarkTest.java
@@ -20,6 +20,7 @@
package org.apache.uima.ruta.action;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -43,45 +44,70 @@
cas.release();
}
-
-
+
@Test
public void testAnnotationExpression() throws Exception {
- Map<String, String> typeMap = new TreeMap<String, String>();
+ Map<String, String> typeMap = new LinkedHashMap<String, String>();
typeMap.put("Complex", "uima.tcas.Annotation");
Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
- List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+ List<TestFeature> list = new ArrayList<>();
featureMap.put("Complex", list);
list.add(new TestFeature("inner", "", "uima.tcas.Annotation"));
-
+
CAS cas = RutaTestUtils.getCAS("This is a test.", typeMap, featureMap);
String script = "";
script += "CW{->T1};t:T1 SW SW{-> UNMARK(t)};";
script += "CW{->T2};\n t:T2 # PERIOD{-> Complex, Complex.inner=t};\n Complex{-> UNMARK(Complex.inner)};\n";
Ruta.apply(cas, script);
-
+
RutaTestUtils.assertAnnotationsEquals(cas, 1, 0);
RutaTestUtils.assertAnnotationsEquals(cas, 2, 0);
-
+
}
-
+
@Test
- public void testAnnotationListExpression() throws Exception {
- Map<String, String> typeMap = new TreeMap<String, String>();
+ public void testAnnotationListExpression() throws Exception {
+ Map<String, String> typeMap = new LinkedHashMap<String, String>();
typeMap.put("Complex", "uima.tcas.Annotation");
Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
- List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+ List<TestFeature> list = new ArrayList<>();
featureMap.put("Complex", list);
list.add(new TestFeature("inner", "", "uima.cas.FSArray"));
-
+
CAS cas = RutaTestUtils.getCAS("This is a test.", typeMap, featureMap);
String script = "";
script += "W{->T1}; Document{-> Complex, Complex.inner = T1};";
script += "Complex{-> UNMARK(Complex.inner)};\n";
Ruta.apply(cas, script);
-
+
RutaTestUtils.assertAnnotationsEquals(cas, 1, 0);
RutaTestUtils.assertAnnotationsEquals(cas, 2, 0);
}
-
+
+ @Test
+ public void testUnmarkWithFeatureMatchInBlock() throws Exception {
+
+ Map<String, String> typeMap = new LinkedHashMap<String, String>();
+ typeMap.put("Struct", "uima.tcas.Annotation");
+ Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+ List<TestFeature> list = new ArrayList<>();
+ featureMap.put("Struct", list);
+ list.add(new TestFeature("s", "", CAS.TYPE_NAME_STRING));
+
+ CAS cas = RutaTestUtils.getCAS("This is a test.", typeMap, featureMap);
+ String script = "\"a\"{->s:Struct,Struct.s=\"foo\"};";
+ script += "BLOCK(SoftRemove) Struct.s==\"foo\"{} {\r\n"
+ + " t:Struct.s==\"foo\"{-> UNMARK(t)};\r\n" //
+ + " t:Struct.s==\"foo\"{-> T1}; \r\n" + "}";
+
+ Ruta.apply(cas, script, RutaTestUtils.getDebugParams());
+
+ if (RutaTestUtils.DEBUG_MODE) {
+ RutaTestUtils.storeTypeSystem(typeMap, featureMap);
+ RutaTestUtils.storeCas(cas, "testUnmarkWithFeatureMatchInBlock");
+ }
+
+ RutaTestUtils.assertAnnotationsEquals(cas, 1, 0);
+ }
+
}
diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/rule/WildCard2Test.java b/ruta-core/src/test/java/org/apache/uima/ruta/rule/WildCard2Test.java
index 38dabdf..03bd641 100644
--- a/ruta-core/src/test/java/org/apache/uima/ruta/rule/WildCard2Test.java
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/rule/WildCard2Test.java
@@ -275,13 +275,12 @@
public void testLabelForFailedLookahead() throws Exception {
String document = "A x B x C x D";
String script = "(w1:CW{REGEXP(\"A\")} # w2:CW{REGEXP(\"C\")})->{w1{->T1};};";
-
- CAS cas = RutaTestUtils.getCAS(document, null, null, false);
- Ruta.apply(cas, script);
-
- RutaTestUtils.assertAnnotationsEquals(cas, 1, 1, "A");
- }
+ CAS cas = RutaTestUtils.getCAS(document, null, null, false);
+ Ruta.apply(cas, script);
+
+ RutaTestUtils.assertAnnotationsEquals(cas, 1, 1, "A");
+ }
@Test
public void testLastElementAlsoAnnotatedWithLookahead() throws Exception {
@@ -297,4 +296,33 @@
RutaTestUtils.assertAnnotationsEquals(cas, 4, 2, "c", "c");
}
+ @Test
+ public void testLookaheadWithFeatureMatch() throws Exception {
+ String document = "a 2 b 3 c 4 d";
+ String script = "";
+ script += "\"2\"{->s:Struct,s.s=\"x\"};\n";
+ script += "\"3\"{->s:Struct};\n";
+ script += "\"4\"{->s:Struct,s.s=\"y\"};\n";
+ script += "s1:Struct.s==\"x\" # s2:Struct.s==\"y\"{->s2.s=s1.s, T1};\n";
+ script += "s:Struct.s==\"x\"{->T2};\n";
+
+ Map<String, String> complexType = new HashMap<>();
+ complexType.put("Struct", CAS.TYPE_NAME_ANNOTATION);
+ Map<String, List<TestFeature>> featureMap = new HashMap<>();
+ List<TestFeature> list = new ArrayList<>();
+ list.add(new TestFeature("s", "", CAS.TYPE_NAME_STRING));
+ featureMap.put("Struct", list);
+
+ CAS cas = RutaTestUtils.getCAS(document, complexType, featureMap);
+ Ruta.apply(cas, script);
+
+ if (RutaTestUtils.DEBUG_MODE) {
+ RutaTestUtils.storeTypeSystem(complexType, featureMap);
+ RutaTestUtils.storeCas(cas, "testLookaheadWithFeatureMatch");
+ }
+
+ RutaTestUtils.assertAnnotationsEquals(cas, 1, 1, "4");
+ RutaTestUtils.assertAnnotationsEquals(cas, 2, 2, "2", "4");
+ }
+
}