mirror of https://github.com/apache/nifi.git
Merge branch 'NIFI-22' into develop
This commit is contained in:
commit
b29333b9b6
|
@ -109,11 +109,13 @@ TO_STRING : 'toString';
|
|||
LENGTH : 'length';
|
||||
TRIM : 'trim';
|
||||
IS_NULL : 'isNull';
|
||||
IS_EMPTY : 'isEmpty';
|
||||
NOT_NULL : 'notNull';
|
||||
TO_NUMBER : 'toNumber';
|
||||
URL_ENCODE : 'urlEncode';
|
||||
URL_DECODE : 'urlDecode';
|
||||
NOT : 'not';
|
||||
COUNT : 'count';
|
||||
|
||||
// 1 arg functions
|
||||
SUBSTRING_AFTER : 'substringAfter';
|
||||
|
@ -128,6 +130,7 @@ APPEND : 'append';
|
|||
INDEX_OF : 'indexOf';
|
||||
LAST_INDEX_OF : 'lastIndexOf';
|
||||
REPLACE_NULL : 'replaceNull';
|
||||
REPLACE_EMPTY : 'replaceEmpty';
|
||||
FIND : 'find'; // regex
|
||||
MATCHES : 'matches'; // regex
|
||||
EQUALS : 'equals';
|
||||
|
@ -146,7 +149,7 @@ DIVIDE : 'divide';
|
|||
TO_RADIX : 'toRadix';
|
||||
OR : 'or';
|
||||
AND : 'and';
|
||||
|
||||
JOIN : 'join';
|
||||
|
||||
// 2 arg functions
|
||||
SUBSTRING : 'substring';
|
||||
|
|
|
@ -74,15 +74,15 @@ tokens {
|
|||
|
||||
// functions that return Strings
|
||||
zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECODE) LPAREN! RPAREN!;
|
||||
oneArgString : ((SUBSTRING_BEFORE | SUBSTRING_BEFORE_LAST | SUBSTRING_AFTER | SUBSTRING_AFTER_LAST | REPLACE_NULL |
|
||||
PREPEND | APPEND | FORMAT | STARTS_WITH | ENDS_WITH | CONTAINS) LPAREN! anyArg RPAREN!) |
|
||||
oneArgString : ((SUBSTRING_BEFORE | SUBSTRING_BEFORE_LAST | SUBSTRING_AFTER | SUBSTRING_AFTER_LAST | REPLACE_NULL | REPLACE_EMPTY |
|
||||
PREPEND | APPEND | FORMAT | STARTS_WITH | ENDS_WITH | CONTAINS | JOIN) LPAREN! anyArg RPAREN!) |
|
||||
(TO_RADIX LPAREN! anyArg (COMMA! anyArg)? RPAREN!);
|
||||
twoArgString : ((REPLACE | REPLACE_ALL) LPAREN! anyArg COMMA! anyArg RPAREN!) |
|
||||
(SUBSTRING LPAREN! anyArg (COMMA! anyArg)? RPAREN!);
|
||||
|
||||
|
||||
// functions that return Booleans
|
||||
zeroArgBool : (IS_NULL | NOT_NULL | NOT) LPAREN! RPAREN!;
|
||||
zeroArgBool : (IS_NULL | NOT_NULL | IS_EMPTY | NOT) LPAREN! RPAREN!;
|
||||
oneArgBool : ((FIND | MATCHES | EQUALS_IGNORE_CASE) LPAREN! anyArg RPAREN!) |
|
||||
(GREATER_THAN | LESS_THAN | GREATER_THAN_OR_EQUAL | LESS_THAN_OR_EQUAL) LPAREN! anyArg RPAREN! |
|
||||
(EQUALS) LPAREN! anyArg RPAREN! |
|
||||
|
@ -90,7 +90,7 @@ oneArgBool : ((FIND | MATCHES | EQUALS_IGNORE_CASE) LPAREN! anyArg RPAREN!) |
|
|||
|
||||
|
||||
// functions that return Numbers
|
||||
zeroArgNum : (LENGTH | TO_NUMBER) LPAREN! RPAREN!;
|
||||
zeroArgNum : (LENGTH | TO_NUMBER | COUNT) LPAREN! RPAREN!;
|
||||
oneArgNum : ((INDEX_OF | LAST_INDEX_OF) LPAREN! anyArg RPAREN!) |
|
||||
(TO_DATE LPAREN! anyArg? RPAREN!) |
|
||||
((MOD | PLUS | MINUS | MULTIPLY | DIVIDE) LPAREN! anyArg RPAREN!);
|
||||
|
|
|
@ -16,69 +16,7 @@
|
|||
*/
|
||||
package org.apache.nifi.attribute.expression.language;
|
||||
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ALL_ATTRIBUTES;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ALL_DELINEATED_VALUES;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ALL_MATCHING_ATTRIBUTES;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.AND;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ANY_ATTRIBUTE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ANY_DELINEATED_VALUE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ANY_MATCHING_ATTRIBUTE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.APPEND;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ATTRIBUTE_REFERENCE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ATTR_NAME;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.CONTAINS;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.DIVIDE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ENDS_WITH;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.EQUALS;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.EQUALS_IGNORE_CASE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.EXPRESSION;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.FALSE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.FIND;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.FORMAT;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.GREATER_THAN;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.GREATER_THAN_OR_EQUAL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.HOSTNAME;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.INDEX_OF;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.IP;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.IS_NULL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.LAST_INDEX_OF;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.LENGTH;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.LESS_THAN;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.LESS_THAN_OR_EQUAL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.MATCHES;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.MINUS;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.MOD;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.MULTIPLY;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.MULTI_ATTRIBUTE_REFERENCE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.NEXT_INT;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.NOT;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.NOT_NULL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.NOW;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.NUMBER;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.OR;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.PLUS;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.PREPEND;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.REPLACE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.REPLACE_ALL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.REPLACE_NULL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.STARTS_WITH;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.STRING_LITERAL;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.SUBSTRING;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.SUBSTRING_AFTER;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.SUBSTRING_AFTER_LAST;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.SUBSTRING_BEFORE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.SUBSTRING_BEFORE_LAST;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_DATE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_LOWER;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_NUMBER;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_RADIX;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_STRING;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TO_UPPER;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TRIM;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TRUE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_DECODE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_ENCODE;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.UUID;
|
||||
import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.*;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -118,6 +56,7 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.Greate
|
|||
import org.apache.nifi.attribute.expression.language.evaluation.functions.HostnameEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.IPEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.IndexOfEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.IsEmptyEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.IsNullEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.LastIndexOfEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.LengthEvaluator;
|
||||
|
@ -136,6 +75,7 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.OrEval
|
|||
import org.apache.nifi.attribute.expression.language.evaluation.functions.PlusEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.PrependEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.ReplaceAllEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.ReplaceEmptyEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.ReplaceEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.ReplaceNullEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.functions.StartsWithEvaluator;
|
||||
|
@ -157,6 +97,9 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.UuidEv
|
|||
import org.apache.nifi.attribute.expression.language.evaluation.literals.BooleanLiteralEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.literals.NumberLiteralEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.literals.StringLiteralEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.reduce.CountEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.reduce.JoinEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.reduce.ReduceEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.AllAttributesEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.AnyAttributeEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.DelineatedAttributeEvaluator;
|
||||
|
@ -169,11 +112,11 @@ import org.apache.nifi.expression.AttributeExpression.ResultType;
|
|||
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
import org.antlr.runtime.ANTLRStringStream;
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.CommonTokenStream;
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.MappingEvaluator;
|
||||
|
||||
/**
|
||||
* Class used for creating and evaluating NiFi Expression Language. Once a Query
|
||||
|
@ -549,7 +492,8 @@ public class Query {
|
|||
final Tree tree = ast.getChild(0);
|
||||
|
||||
// ensure that we are able to build the evaluators, so that we validate syntax
|
||||
buildEvaluator(tree);
|
||||
final Evaluator<?> evaluator = buildEvaluator(tree);
|
||||
verifyMappingEvaluatorReduced(evaluator);
|
||||
return tree;
|
||||
} catch (final AttributeExpressionLanguageParsingException e) {
|
||||
throw e;
|
||||
|
@ -572,26 +516,26 @@ public class Query {
|
|||
try {
|
||||
final List<String> substrings = new ArrayList<>();
|
||||
final Map<String, Tree> trees = new HashMap<>();
|
||||
|
||||
|
||||
int lastIndex = 0;
|
||||
for (final Range range : ranges) {
|
||||
if (range.getStart() > lastIndex) {
|
||||
substrings.add(query.substring(lastIndex, range.getStart()).replace("$$", "$"));
|
||||
lastIndex = range.getEnd() + 1;
|
||||
}
|
||||
|
||||
|
||||
final String treeText = query.substring(range.getStart(), range.getEnd() + 1).replace("$$", "$");
|
||||
substrings.add(treeText);
|
||||
trees.put(treeText, Query.compileTree(treeText));
|
||||
lastIndex = range.getEnd() + 1;
|
||||
}
|
||||
|
||||
|
||||
final Range lastRange = ranges.get(ranges.size() - 1);
|
||||
if (lastRange.getEnd() + 1 < query.length()) {
|
||||
final String treeText = query.substring(lastRange.getEnd() + 1).replace("$$", "$");
|
||||
substrings.add(treeText);
|
||||
}
|
||||
|
||||
|
||||
return new StandardPreparedQuery(substrings, trees);
|
||||
} catch (final AttributeExpressionLanguageParsingException e) {
|
||||
return new InvalidPreparedQuery(query, e.getMessage());
|
||||
|
@ -605,7 +549,10 @@ public class Query {
|
|||
final Tree ast = (Tree) parser.query().getTree();
|
||||
final Tree tree = ast.getChild(0);
|
||||
|
||||
return new Query(query, tree, buildEvaluator(tree));
|
||||
final Evaluator<?> evaluator = buildEvaluator(tree);
|
||||
verifyMappingEvaluatorReduced(evaluator);
|
||||
|
||||
return new Query(query, tree, evaluator);
|
||||
} catch (final AttributeExpressionLanguageParsingException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
|
@ -613,6 +560,32 @@ public class Query {
|
|||
}
|
||||
}
|
||||
|
||||
private static void verifyMappingEvaluatorReduced(final Evaluator<?> evaluator) {
|
||||
// if the result type of the evaluator is BOOLEAN, then it will always
|
||||
// be reduced when evaluator.
|
||||
final ResultType resultType = evaluator.getResultType();
|
||||
if (resultType == ResultType.BOOLEAN) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Evaluator<?> rootEvaluator = getRootSubjectEvaluator(evaluator);
|
||||
if (rootEvaluator != null && rootEvaluator instanceof MultiAttributeEvaluator) {
|
||||
final MultiAttributeEvaluator multiAttrEval = (MultiAttributeEvaluator) rootEvaluator;
|
||||
switch (multiAttrEval.getEvaluationType()) {
|
||||
case ALL_ATTRIBUTES:
|
||||
case ALL_MATCHING_ATTRIBUTES:
|
||||
case ALL_DELINEATED_VALUES: {
|
||||
if (!(evaluator instanceof ReduceEvaluator)) {
|
||||
throw new AttributeExpressionLanguageParsingException("Cannot evaluate expression because it attempts to reference multiple attributes but does not use a reducing function");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AttributeExpressionLanguageParsingException("Cannot evaluate expression because it attempts to reference multiple attributes but does not use a reducing function");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CommonTokenStream createTokenStream(final String expression) throws AttributeExpressionLanguageParsingException {
|
||||
final CharStream input = new ANTLRStringStream(expression);
|
||||
final AttributeExpressionLexer lexer = new AttributeExpressionLexer(input);
|
||||
|
@ -818,7 +791,7 @@ public class Query {
|
|||
if (tree.getChildCount() == 0) {
|
||||
throw new AttributeExpressionLanguageParsingException("EXPRESSION tree node has no children");
|
||||
}
|
||||
|
||||
|
||||
final Evaluator<?> evaluator;
|
||||
if (tree.getChildCount() == 1) {
|
||||
evaluator = buildEvaluator(tree.getChild(0));
|
||||
|
@ -831,15 +804,11 @@ public class Query {
|
|||
// tree from the right-most child going left-ward.
|
||||
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()) {
|
||||
|
@ -850,13 +819,21 @@ public class Query {
|
|||
break;
|
||||
case ALL_ATTRIBUTES:
|
||||
case ALL_MATCHING_ATTRIBUTES:
|
||||
case ALL_DELINEATED_VALUES:
|
||||
chosenEvaluator = new AllAttributesEvaluator((BooleanEvaluator) evaluator, multiAttrEval);
|
||||
case ALL_DELINEATED_VALUES: {
|
||||
final ResultType resultType = evaluator.getResultType();
|
||||
if (resultType == ResultType.BOOLEAN) {
|
||||
chosenEvaluator = new AllAttributesEvaluator((BooleanEvaluator) evaluator, multiAttrEval);
|
||||
} else if (evaluator instanceof ReduceEvaluator) {
|
||||
chosenEvaluator = new MappingEvaluator((ReduceEvaluator) evaluator, multiAttrEval);
|
||||
} else {
|
||||
throw new AttributeExpressionLanguageException("Cannot evaluate Expression because it attempts to reference multiple attributes but does not use a reducing function");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return chosenEvaluator;
|
||||
}
|
||||
|
||||
|
@ -926,6 +903,8 @@ public class Query {
|
|||
return (NumberEvaluator) evaluator;
|
||||
case STRING:
|
||||
return new NumberCastEvaluator((StringEvaluator) evaluator);
|
||||
case DATE:
|
||||
return new DateToNumberEvaluator((DateEvaluator) evaluator);
|
||||
default:
|
||||
throw new AttributeExpressionLanguageParsingException("Cannot implicitly convert Data Type " + evaluator.getResultType() + " to " + ResultType.NUMBER
|
||||
+ (location == null ? "" : " at location [" + location + "]"));
|
||||
|
@ -995,6 +974,10 @@ public class Query {
|
|||
return new ReplaceNullEvaluator(toStringEvaluator(subjectEvaluator),
|
||||
toStringEvaluator(argEvaluators.get(0), "first argument to replaceNull"));
|
||||
}
|
||||
case REPLACE_EMPTY: {
|
||||
verifyArgCount(argEvaluators, 1, "replaceEmtpy");
|
||||
return new ReplaceEmptyEvaluator(toStringEvaluator(subjectEvaluator), toStringEvaluator(argEvaluators.get(0), "first argumen to replaceEmpty"));
|
||||
}
|
||||
case REPLACE: {
|
||||
verifyArgCount(argEvaluators, 2, "replace");
|
||||
return new ReplaceEvaluator(toStringEvaluator(subjectEvaluator),
|
||||
|
@ -1030,10 +1013,22 @@ public class Query {
|
|||
throw new AttributeExpressionLanguageParsingException("substring() function can take either 1 or 2 arguments but cannot take " + numArgs + " arguments");
|
||||
}
|
||||
}
|
||||
case JOIN: {
|
||||
verifyArgCount(argEvaluators, 1, "join");
|
||||
return new JoinEvaluator(toStringEvaluator(subjectEvaluator), toStringEvaluator(argEvaluators.get(0)));
|
||||
}
|
||||
case COUNT: {
|
||||
verifyArgCount(argEvaluators, 0, "count");
|
||||
return new CountEvaluator(subjectEvaluator);
|
||||
}
|
||||
case IS_NULL: {
|
||||
verifyArgCount(argEvaluators, 0, "isNull");
|
||||
return new IsNullEvaluator(toStringEvaluator(subjectEvaluator));
|
||||
}
|
||||
case IS_EMPTY: {
|
||||
verifyArgCount(argEvaluators, 0, "isNull");
|
||||
return new IsEmptyEvaluator(toStringEvaluator(subjectEvaluator));
|
||||
}
|
||||
case NOT_NULL: {
|
||||
verifyArgCount(argEvaluators, 0, "notNull");
|
||||
return new NotNullEvaluator(toStringEvaluator(subjectEvaluator));
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.functions;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.BooleanEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.BooleanQueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
|
||||
public class IsEmptyEvaluator extends BooleanEvaluator {
|
||||
private final Evaluator<?> subjectEvaluator;
|
||||
|
||||
public IsEmptyEvaluator(final Evaluator<?> subjectEvaluator) {
|
||||
this.subjectEvaluator = subjectEvaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Boolean> evaluate(final Map<String, String> attributes) {
|
||||
final Object subjectValue = subjectEvaluator.evaluate(attributes).getValue();
|
||||
return new BooleanQueryResult(subjectValue == null || subjectValue.toString().trim().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return subjectEvaluator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.functions;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.StringEvaluator;
|
||||
|
||||
public class ReplaceEmptyEvaluator extends StringEvaluator {
|
||||
private final StringEvaluator subjectEvaluator;
|
||||
private final StringEvaluator replacementEvaluator;
|
||||
|
||||
public ReplaceEmptyEvaluator(final StringEvaluator subjectEvaluator, final StringEvaluator replacementEvaluator) {
|
||||
this.subjectEvaluator = subjectEvaluator;
|
||||
this.replacementEvaluator = replacementEvaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<String> evaluate(final Map<String, String> attributes) {
|
||||
final QueryResult<String> subjectResult = subjectEvaluator.evaluate(attributes);
|
||||
final String subjectValue = subjectResult.getValue();
|
||||
final boolean isEmpty = subjectValue == null || subjectValue.toString().trim().isEmpty();
|
||||
if ( isEmpty ) {
|
||||
return replacementEvaluator.evaluate(attributes);
|
||||
} else {
|
||||
return subjectResult;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return subjectEvaluator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.reduce;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.NumberEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.NumberQueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
import org.apache.nifi.expression.AttributeExpression.ResultType;
|
||||
|
||||
public class CountEvaluator extends NumberEvaluator implements ReduceEvaluator<Long> {
|
||||
|
||||
private final Evaluator<?> subjectEvaluator;
|
||||
private long count = 0L;
|
||||
|
||||
public CountEvaluator(final Evaluator<?> subjectEvaluator) {
|
||||
this.subjectEvaluator = subjectEvaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<Long> evaluate(final Map<String, String> attributes) {
|
||||
final QueryResult<?> result = subjectEvaluator.evaluate(attributes);
|
||||
if ( result.getValue() == null ) {
|
||||
return new NumberQueryResult(count);
|
||||
}
|
||||
|
||||
if ( result.getResultType() == ResultType.BOOLEAN && ((Boolean) result.getValue()).equals(Boolean.FALSE) ) {
|
||||
return new NumberQueryResult(count);
|
||||
}
|
||||
|
||||
count++;
|
||||
return new NumberQueryResult(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return subjectEvaluator;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.reduce;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.StringEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult;
|
||||
|
||||
public class JoinEvaluator extends StringEvaluator implements ReduceEvaluator<String> {
|
||||
private final StringEvaluator subjectEvaluator;
|
||||
private final StringEvaluator delimiterEvaluator;
|
||||
|
||||
private final StringBuilder sb = new StringBuilder();
|
||||
private int evalCount = 0;
|
||||
|
||||
public JoinEvaluator(final StringEvaluator subject, final StringEvaluator delimiter) {
|
||||
this.subjectEvaluator = subject;
|
||||
this.delimiterEvaluator = delimiter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<String> evaluate(final Map<String, String> attributes) {
|
||||
String subject = subjectEvaluator.evaluate(attributes).getValue();
|
||||
if ( subject == null ) {
|
||||
subject = "";
|
||||
}
|
||||
|
||||
final String delimiter = delimiterEvaluator.evaluate(attributes).getValue();
|
||||
if ( evalCount > 0 ) {
|
||||
sb.append(delimiter);
|
||||
}
|
||||
sb.append(subject);
|
||||
|
||||
evalCount++;
|
||||
return new StringQueryResult( sb.toString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return subjectEvaluator;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.reduce;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
|
||||
public interface ReduceEvaluator<T> extends Evaluator<T> {
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.selection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.reduce.ReduceEvaluator;
|
||||
import org.apache.nifi.expression.AttributeExpression.ResultType;
|
||||
|
||||
public class MappingEvaluator<T> implements Evaluator<T> {
|
||||
private final ReduceEvaluator<T> mappingEvaluator;
|
||||
private final MultiAttributeEvaluator multiAttributeEvaluator;
|
||||
|
||||
public MappingEvaluator(final ReduceEvaluator<T> mappingEvaluator, final MultiAttributeEvaluator multiAttributeEval) {
|
||||
this.mappingEvaluator = mappingEvaluator;
|
||||
this.multiAttributeEvaluator = multiAttributeEval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResult<T> evaluate(final Map<String, String> attributes) {
|
||||
QueryResult<T> result = mappingEvaluator.evaluate(attributes);
|
||||
|
||||
while ( multiAttributeEvaluator.getEvaluationsRemaining() > 0 ) {
|
||||
result = mappingEvaluator.evaluate(attributes);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultType getResultType() {
|
||||
return mappingEvaluator.getResultType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEvaluationsRemaining() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,7 @@ import java.util.Map;
|
|||
|
||||
import org.apache.nifi.attribute.expression.language.Query.Range;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException;
|
||||
import org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageParsingException;
|
||||
import org.apache.nifi.expression.AttributeExpression.ResultType;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
|
@ -192,9 +193,11 @@ public class TestQuery {
|
|||
attributes.put("dateTime", "2013/11/18 10:22:27.678");
|
||||
|
||||
verifyEquals("${dateTime:toDate('yyyy/MM/dd HH:mm:ss.SSS'):toNumber():plus(86400000):toDate():format('yyyy/MM/dd HH:mm:ss.SSS')}", attributes, "2013/11/19 10:22:27.678");
|
||||
verifyEquals("${dateTime:toDate('yyyy/MM/dd HH:mm:ss.SSS'):plus(86400000):format('yyyy/MM/dd HH:mm:ss.SSS')}", attributes, "2013/11/19 10:22:27.678");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Requires specific locale")
|
||||
public void implicitDateConversion() {
|
||||
final Date date = new Date();
|
||||
final Query query = Query.compile("${dateTime:format('yyyy/MM/dd HH:mm:ss.SSS')}");
|
||||
|
@ -229,6 +232,68 @@ public class TestQuery {
|
|||
assertEquals("true", Query.evaluateExpressions("${x:equals(\"${a}\")}", attributes, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoin() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("a.a", "a");
|
||||
attributes.put("a.b", "b");
|
||||
attributes.put("a.c", "c");
|
||||
verifyEquals("${allAttributes( 'a.a', 'a.b', 'a.c' ):join(', ')}", attributes, "a, b, c");
|
||||
verifyEquals("${x:join(', ')}", attributes, "");
|
||||
verifyEquals("${a.a:join(', ')}", attributes, "a");
|
||||
verifyEquals("${allAttributes( 'x', 'y' ):join(',')}", attributes, ",");
|
||||
}
|
||||
|
||||
@Test(expected=AttributeExpressionLanguageException.class)
|
||||
public void testCannotCombineWithNonReducingFunction() {
|
||||
Query.compileTree("${allAttributes( 'a.1' ):plus(1)}");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsEmpty() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("a", "a");
|
||||
attributes.put("b", "");
|
||||
attributes.put("c", " \n");
|
||||
|
||||
verifyEquals("${a:isEmpty()}", attributes, false);
|
||||
verifyEquals("${b:isEmpty()}", attributes, true);
|
||||
verifyEquals("${c:isEmpty()}", attributes, true);
|
||||
verifyEquals("${d:isEmpty()}", attributes, true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReplaceEmpty() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("a", "a");
|
||||
attributes.put("b", "");
|
||||
attributes.put("c", " \n");
|
||||
|
||||
verifyEquals("${a:replaceEmpty('c')}", attributes, "a");
|
||||
verifyEquals("${b:replaceEmpty('c')}", attributes, "c");
|
||||
verifyEquals("${c:replaceEmpty('c')}", attributes, "c");
|
||||
verifyEquals("${d:replaceEmpty('c')}", attributes, "c");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCount() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
attributes.put("a", "a");
|
||||
attributes.put("b", "abc");
|
||||
attributes.put("c", " \n");
|
||||
attributes.put("n1", "111");
|
||||
attributes.put("n2", "222");
|
||||
attributes.put("n3", "333333");
|
||||
|
||||
verifyEquals("${allMatchingAttributes( '.*' ):count()}", attributes, 6L);
|
||||
verifyEquals("${allMatchingAttributes( '.*' ):length():gt(2):count()}", attributes, 5L);
|
||||
verifyEquals("${allMatchingAttributes( 'n.*' ):plus(1):count()}", attributes, 3L );
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCurlyBracesInQuotes() {
|
||||
|
|
Loading…
Reference in New Issue