From fed987e778e0e2488888ffe2ac3a916b68255aac Mon Sep 17 00:00:00 2001 From: Mark Payne Date: Tue, 30 Dec 2014 09:16:14 -0500 Subject: [PATCH] NIFI-206: Build appropriate AnyAttribute, AllAttributes, AnyMatchingAttribute, etc. evaluators in the buildExpressionEvaluator method rather than building at evaluation time. This way, embedded expressions are also wrapped appropriately. --- .../attribute/expression/language/Query.java | 60 ++++++++++--------- .../expression/language/TestQuery.java | 10 ++++ 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java index f4c1c0dfb5..93ab7ada64 100644 --- a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java +++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java @@ -636,32 +636,7 @@ public class Query { throw new IllegalStateException("A Query cannot be evaluated more than once"); } - Evaluator chosenEvaluator = evaluator; - final Evaluator rootEvaluator = getRootSubjectEvaluator(evaluator); - if (rootEvaluator != null) { - if (rootEvaluator instanceof MultiAttributeEvaluator) { - if (evaluator.getResultType() != ResultType.BOOLEAN) { - throw new AttributeExpressionLanguageParsingException("Found Multi-Attribute function but return type is " + evaluator.getResultType() + ", not " + ResultType.BOOLEAN + ", for query: " + query); - } - - final MultiAttributeEvaluator multiAttrEval = (MultiAttributeEvaluator) rootEvaluator; - - switch (multiAttrEval.getEvaluationType()) { - case ANY_ATTRIBUTE: - case ANY_MATCHING_ATTRIBUTE: - case ANY_DELINEATED_VALUE: - chosenEvaluator = new AnyAttributeEvaluator((BooleanEvaluator) evaluator, multiAttrEval); - break; - case ALL_ATTRIBUTES: - case ALL_MATCHING_ATTRIBUTES: - case ALL_DELINEATED_VALUES: - chosenEvaluator = new AllAttributesEvaluator((BooleanEvaluator) evaluator, multiAttrEval); - break; - } - } - } - - return chosenEvaluator.evaluate(attributes); + return evaluator.evaluate(attributes); } Tree getTree() { @@ -843,8 +818,10 @@ public class Query { if (tree.getChildCount() == 0) { throw new AttributeExpressionLanguageParsingException("EXPRESSION tree node has no children"); } + + final Evaluator evaluator; if (tree.getChildCount() == 1) { - return buildEvaluator(tree.getChild(0)); + evaluator = buildEvaluator(tree.getChild(0)); } else { // we can chain together functions in the form of: // ${x:trim():substring(1,2):trim()} @@ -852,8 +829,35 @@ public class Query { // subject is the function to its left (the first trim()), and its subject is the value of // the 'x' attribute. We accomplish this logic by iterating over all of the children of the // tree from the right-most child going left-ward. - return buildFunctionExpressionEvaluator(tree, 0); + evaluator = buildFunctionExpressionEvaluator(tree, 0); } + + Evaluator chosenEvaluator = evaluator; + final Evaluator rootEvaluator = getRootSubjectEvaluator(evaluator); + if (rootEvaluator != null) { + if (rootEvaluator instanceof MultiAttributeEvaluator) { + if (evaluator.getResultType() != ResultType.BOOLEAN) { + throw new AttributeExpressionLanguageParsingException("Found Multi-Attribute function but return type is " + evaluator.getResultType() + ", not " + ResultType.BOOLEAN + ", for query: " + tree.getText()); + } + + final MultiAttributeEvaluator multiAttrEval = (MultiAttributeEvaluator) rootEvaluator; + + switch (multiAttrEval.getEvaluationType()) { + case ANY_ATTRIBUTE: + case ANY_MATCHING_ATTRIBUTE: + case ANY_DELINEATED_VALUE: + chosenEvaluator = new AnyAttributeEvaluator((BooleanEvaluator) evaluator, multiAttrEval); + break; + case ALL_ATTRIBUTES: + case ALL_MATCHING_ATTRIBUTES: + case ALL_DELINEATED_VALUES: + chosenEvaluator = new AllAttributesEvaluator((BooleanEvaluator) evaluator, multiAttrEval); + break; + } + } + } + + return chosenEvaluator; } private static Evaluator buildFunctionExpressionEvaluator(final Tree tree, final int offset) { diff --git a/commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java b/commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java index a2b72141bb..dd7a7fe36c 100644 --- a/commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java +++ b/commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java @@ -1047,6 +1047,16 @@ public class TestQuery { assertEquals(ResultType.NUMBER, Query.getResultType("${header.size:toNumber()}")); } + @Test + public void testAnyAttributeEmbedded() { + final Map attributes = new HashMap<>(); + attributes.put("a1", "test1"); + attributes.put("b2", "2test"); + attributes.put("c3", "3test3"); + + final String query = "${a1:equals('test1'):and( ${anyAttribute('a1','b2','c3'):contains('2')})}"; + verifyEquals(query, attributes, true); + } private void verifyEquals(final String expression, final Map attributes, final Object expectedResult) { Query.validateExpression(expression, false);