nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pvill...@apache.org
Subject nifi git commit: NIFI-5885 ArrayOutOfBoundsException at EL 'or' and 'and' functions
Date Mon, 10 Dec 2018 10:48:09 GMT
Repository: nifi
Updated Branches:
  refs/heads/master a6f91a197 -> 4e7a856f7


NIFI-5885 ArrayOutOfBoundsException at EL 'or' and 'and' functions

EL 'or' and 'and' functions can be called multiple times within the same context using the
same evaluator instance.
That happens if their subject is derived from an IteratingEvaluator such as 'anyDelineatedValues'.

And if the right hand side expression for such 'or' and 'and' contains another IteratingEvaluator,
then it can be evaluated more than the number of its candidates, ultimately an ArrayOutOfBoundsException
is thrown.

This commit makes Or/AndEvaluator caching its right hand side result to prevent that happens.
For 'or' and 'and' functions, the right hand side expression is independant from their subject
boolean value.
It's enough evaluating right hand side once, because it returns the same result even with
different subjects.

Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com>

This closes #3212.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/4e7a856f
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/4e7a856f
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/4e7a856f

Branch: refs/heads/master
Commit: 4e7a856f77fb8b7fbe1067ce667d8dff93dbd271
Parents: a6f91a1
Author: Koji Kawamura <ijokarumawak@apache.org>
Authored: Mon Dec 10 14:31:16 2018 +0900
Committer: Pierre Villard <pierre.villard.fr@gmail.com>
Committed: Mon Dec 10 11:47:58 2018 +0100

----------------------------------------------------------------------
 .../evaluation/functions/AndEvaluator.java      | 12 ++++++-
 .../evaluation/functions/OrEvaluator.java       | 14 ++++++--
 .../expression/language/TestQuery.java          | 36 ++++++++++++++++++++
 3 files changed, 59 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/4e7a856f/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AndEvaluator.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AndEvaluator.java
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AndEvaluator.java
index 232fc26..adc41da 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AndEvaluator.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/AndEvaluator.java
@@ -27,6 +27,7 @@ public class AndEvaluator extends BooleanEvaluator {
 
     private final Evaluator<Boolean> subjectEvaluator;
     private final Evaluator<Boolean> rhsEvaluator;
+    private BooleanQueryResult rhsResult;
 
     public AndEvaluator(final Evaluator<Boolean> subjectEvaluator, final Evaluator<Boolean>
rhsEvaluator) {
         this.subjectEvaluator = subjectEvaluator;
@@ -44,9 +45,18 @@ public class AndEvaluator extends BooleanEvaluator {
             return new BooleanQueryResult(false);
         }
 
+        // Returning previously evaluated result.
+        // The same AndEvaluator can be evaluated multiple times if subjectEvaluator is IteratingEvaluator.
+        // In that case, it's enough to evaluate the right hand side.
+        if (rhsResult != null) {
+            return rhsResult;
+        }
+
         final QueryResult<Boolean> rhsValue = rhsEvaluator.evaluate(attributes);
         if (rhsValue == null) {
-            return new BooleanQueryResult(false);
+            rhsResult = new BooleanQueryResult(false);
+        } else {
+            rhsResult = new BooleanQueryResult(rhsValue.getValue());
         }
 
         return new BooleanQueryResult(rhsValue.getValue());

http://git-wip-us.apache.org/repos/asf/nifi/blob/4e7a856f/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/OrEvaluator.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/OrEvaluator.java
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/OrEvaluator.java
index 719fa11..9c63c27 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/OrEvaluator.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/OrEvaluator.java
@@ -27,6 +27,7 @@ public class OrEvaluator extends BooleanEvaluator {
 
     private final Evaluator<Boolean> subjectEvaluator;
     private final Evaluator<Boolean> rhsEvaluator;
+    private BooleanQueryResult rhsResult;
 
     public OrEvaluator(final Evaluator<Boolean> subjectEvaluator, final Evaluator<Boolean>
rhsEvaluator) {
         this.subjectEvaluator = subjectEvaluator;
@@ -44,12 +45,21 @@ public class OrEvaluator extends BooleanEvaluator {
             return new BooleanQueryResult(true);
         }
 
+        // Returning previously evaluated result.
+        // The same OrEvaluator can be evaluated multiple times if subjectEvaluator is IteratingEvaluator.
+        // In that case, it's enough to evaluate the right hand side.
+        if (rhsResult != null) {
+            return rhsResult;
+        }
+
         final QueryResult<Boolean> rhsValue = rhsEvaluator.evaluate(attributes);
         if (rhsValue == null) {
-            return new BooleanQueryResult(false);
+            rhsResult = new BooleanQueryResult(false);
+        } else {
+            rhsResult = new BooleanQueryResult(rhsValue.getValue());
         }
 
-        return new BooleanQueryResult(rhsValue.getValue());
+        return rhsResult;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/4e7a856f/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
index 2a43bdc..5b36813 100644
--- a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
+++ b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
@@ -996,6 +996,42 @@ public class TestQuery {
     }
 
     @Test
+    public void testNestedAnyDelineatedValueOr() {
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "a,b,c");
+        attributes.put("xyz", "x");
+
+        // Assert each part separately.
+        assertEquals("true", Query.evaluateExpressions("${anyDelineatedValue('${abc}', ','):equals('c')}",
+                attributes, null));
+        assertEquals("false", Query.evaluateExpressions("${anyDelineatedValue('${xyz}', ','):equals('z')}",
+                attributes, null));
+
+        // Combine them with 'or'.
+        assertEquals("true", Query.evaluateExpressions(
+                "${anyDelineatedValue('${abc}', ','):equals('c'):or(${anyDelineatedValue('${xyz}',
','):equals('z')})}",
+                attributes, null));
+    }
+
+    @Test
+    public void testNestedAnyDelineatedValueAnd() {
+        final Map<String, String> attributes = new HashMap<>();
+        attributes.put("abc", "2,0,1,3");
+        attributes.put("xyz", "x,y,z");
+
+        // Assert each part separately.
+        assertEquals("true", Query.evaluateExpressions("${anyDelineatedValue('${abc}', ','):gt('2')}",
+                attributes, null));
+        assertEquals("true", Query.evaluateExpressions("${anyDelineatedValue('${xyz}', ','):equals('z')}",
+                attributes, null));
+
+        // Combine them with 'and'.
+        assertEquals("true", Query.evaluateExpressions(
+                "${anyDelineatedValue('${abc}', ','):gt('2'):and(${anyDelineatedValue('${xyz}',
','):equals('z')})}",
+                attributes, null));
+    }
+
+    @Test
     public void testAllDelineatedValues() {
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("abc", "a,b,c");


Mime
View raw message