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.

This commit is contained in:
Mark Payne 2014-12-30 09:16:14 -05:00
parent bfe39c0b82
commit fed987e778
2 changed files with 42 additions and 28 deletions

View File

@ -636,32 +636,7 @@ public class Query {
throw new IllegalStateException("A Query cannot be evaluated more than once"); throw new IllegalStateException("A Query cannot be evaluated more than once");
} }
Evaluator<?> chosenEvaluator = evaluator; return evaluator.evaluate(attributes);
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);
} }
Tree getTree() { Tree getTree() {
@ -843,8 +818,10 @@ public class Query {
if (tree.getChildCount() == 0) { if (tree.getChildCount() == 0) {
throw new AttributeExpressionLanguageParsingException("EXPRESSION tree node has no children"); throw new AttributeExpressionLanguageParsingException("EXPRESSION tree node has no children");
} }
final Evaluator<?> evaluator;
if (tree.getChildCount() == 1) { if (tree.getChildCount() == 1) {
return buildEvaluator(tree.getChild(0)); evaluator = buildEvaluator(tree.getChild(0));
} else { } else {
// we can chain together functions in the form of: // we can chain together functions in the form of:
// ${x:trim():substring(1,2):trim()} // ${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 // 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 // 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. // 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) { private static Evaluator<?> buildFunctionExpressionEvaluator(final Tree tree, final int offset) {

View File

@ -1047,6 +1047,16 @@ public class TestQuery {
assertEquals(ResultType.NUMBER, Query.getResultType("${header.size:toNumber()}")); assertEquals(ResultType.NUMBER, Query.getResultType("${header.size:toNumber()}"));
} }
@Test
public void testAnyAttributeEmbedded() {
final Map<String, String> 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<String, String> attributes, final Object expectedResult) { private void verifyEquals(final String expression, final Map<String, String> attributes, final Object expectedResult) {
Query.validateExpression(expression, false); Query.validateExpression(expression, false);