You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2015/01/05 21:40:55 UTC
[2/2] incubator-nifi git commit: NIFI-22: Added 'count', 'join',
'isEmpty', and 'replaceEmpty' functions
NIFI-22: Added 'count', 'join', 'isEmpty', and 'replaceEmpty' functions
Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/49256d9d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/49256d9d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/49256d9d
Branch: refs/heads/NIFI-22
Commit: 49256d9d83572bf7a0d7b16aa02ad43049bf2585
Parents: a2ecfe3
Author: Mark Payne <ma...@hotmail.com>
Authored: Mon Jan 5 15:40:32 2015 -0500
Committer: Mark Payne <ma...@hotmail.com>
Committed: Mon Jan 5 15:40:32 2015 -0500
----------------------------------------------------------------------
.../language/antlr/AttributeExpressionLexer.g | 5 +-
.../language/antlr/AttributeExpressionParser.g | 8 +-
.../attribute/expression/language/Query.java | 127 +++++++++----------
.../evaluation/functions/IsEmptyEvaluator.java | 43 +++++++
.../functions/ReplaceEmptyEvaluator.java | 50 ++++++++
.../evaluation/reduce/CountEvaluator.java | 56 ++++++++
.../evaluation/reduce/JoinEvaluator.java | 59 +++++++++
.../evaluation/reduce/ReduceEvaluator.java | 23 ++++
.../evaluation/selection/MappingEvaluator.java | 61 +++++++++
.../expression/language/TestQuery.java | 66 +++++++++-
10 files changed, 422 insertions(+), 76 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g b/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
index 8cb6847..10394b9 100644
--- a/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
+++ b/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
@@ -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';
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g b/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
index cf10fc0..f6a87dd 100644
--- a/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
+++ b/commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
@@ -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!);
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java
----------------------------------------------------------------------
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 93ab7ad..9a5fe0a 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
@@ -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,7 +112,6 @@ 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;
@@ -549,7 +491,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;
@@ -605,7 +548,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 +559,33 @@ 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);
@@ -836,10 +809,6 @@ public class Query {
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()) {
@@ -926,6 +895,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 +966,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 +1005,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));
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/IsEmptyEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/IsEmptyEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/IsEmptyEvaluator.java
new file mode 100644
index 0000000..c5e3c21
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/IsEmptyEvaluator.java
@@ -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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/ReplaceEmptyEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/ReplaceEmptyEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/ReplaceEmptyEvaluator.java
new file mode 100644
index 0000000..e5c40d2
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/ReplaceEmptyEvaluator.java
@@ -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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/CountEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/CountEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/CountEvaluator.java
new file mode 100644
index 0000000..f2af268
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/CountEvaluator.java
@@ -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;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/JoinEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/JoinEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/JoinEvaluator.java
new file mode 100644
index 0000000..6fab871
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/JoinEvaluator.java
@@ -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) {
+ final String subject = subjectEvaluator.evaluate(attributes).getValue();
+ if ( subject == null ) {
+ return new StringQueryResult("");
+ }
+
+ 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/ReduceEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/ReduceEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/ReduceEvaluator.java
new file mode 100644
index 0000000..12197c0
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/reduce/ReduceEvaluator.java
@@ -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> {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/selection/MappingEvaluator.java
----------------------------------------------------------------------
diff --git a/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/selection/MappingEvaluator.java b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/selection/MappingEvaluator.java
new file mode 100644
index 0000000..61ff2af
--- /dev/null
+++ b/commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/selection/MappingEvaluator.java
@@ -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 mappingEvaluator;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/49256d9d/commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
----------------------------------------------------------------------
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 dd7a7fe..824249b 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
@@ -29,10 +29,10 @@ 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;
-
import org.antlr.runtime.tree.Tree;
import org.junit.Assert;
import org.junit.Ignore;
@@ -192,9 +192,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 +231,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("b.b", "b");
+ attributes.put("c.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", "");
+ 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() {