This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 3a60013876 NIFI-10754 Added getUri NIFI Expression Language function
3a60013876 is described below
commit 3a6001387681f79615ac5ce776e74548dd825005
Author: dan-s1 <[email protected]>
AuthorDate: Fri Nov 18 20:19:44 2022 +0000
NIFI-10754 Added getUri NIFI Expression Language function
This closes #6689
Signed-off-by: David Handermann <[email protected]>
---
.../language/antlr/AttributeExpressionLexer.g | 2 +
.../language/antlr/AttributeExpressionParser.g | 5 +-
.../language/compile/ExpressionCompiler.java | 14 ++++
.../evaluation/functions/GetUriEvaluator.java | 75 ++++++++++++++++++++++
.../literals/StringLiteralEvaluator.java | 64 +++++++++---------
.../attribute/expression/language/TestQuery.java | 22 +++++++
.../main/asciidoc/expression-language-guide.adoc | 41 ++++++++++++
7 files changed, 191 insertions(+), 32 deletions(-)
diff --git
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
index 734794f3be..02901c4b4e 100644
---
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
+++
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
@@ -91,6 +91,7 @@ fragment EXP : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
TRUE : 'true';
FALSE : 'false';
+NULL : 'null';
//
// FUNCTION NAMES
@@ -111,6 +112,7 @@ UUID : 'UUID';
HOSTNAME : 'hostname'; // requires boolean arg: prefer FQDN
NOW : 'now';
THREAD : 'thread';
+GET_URI : 'getUri';
// 0 arg functions
diff --git
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
index c71719b92c..56d900a69f 100644
---
a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
+++
b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
@@ -106,7 +106,7 @@ booleanFunctionRef : zeroArgBool | oneArgBool |
multiArgBool;
numberFunctionRef : zeroArgNum | oneArgNum | zeroOrTwoArgNum | oneOrTwoArgNum
| zeroOrOneOrTwoArgNum;
anyArg : WHOLE_NUMBER | DECIMAL | numberFunctionRef | STRING_LITERAL |
zeroArgString | oneArgString | twoArgString | fiveArgString | booleanLiteral |
zeroArgBool | oneArgBool | multiArgBool
- | expression | parameterReference;
+ | expression | parameterReference | NULL;
stringArg : STRING_LITERAL | zeroArgString | oneArgString | twoArgString |
expression;
functionRef : stringFunctionRef | booleanFunctionRef | numberFunctionRef;
@@ -137,7 +137,8 @@ booleanLiteral : TRUE | FALSE;
zeroArgStandaloneFunction : (IP | UUID | NOW | NEXT_INT | HOSTNAME | THREAD |
RANDOM) LPAREN! RPAREN!;
oneArgStandaloneFunction : ((TO_LITERAL | MATH | GET_STATE_VALUE)^ LPAREN!
anyArg RPAREN!) |
(HOSTNAME^ LPAREN! booleanLiteral RPAREN!);
-standaloneFunction : zeroArgStandaloneFunction | oneArgStandaloneFunction;
+sevenArgStandaloneFunction : GET_URI^ LPAREN! anyArg COMMA! anyArg COMMA!
anyArg COMMA! anyArg COMMA! anyArg COMMA! anyArg COMMA! anyArg RPAREN!;
+standaloneFunction : zeroArgStandaloneFunction | oneArgStandaloneFunction |
sevenArgStandaloneFunction;
attributeRefOrFunctionCall : (attributeRef | standaloneFunction |
parameterReference);
diff --git
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
index 05bc23a2ac..f5e1e74195 100644
---
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
+++
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
@@ -117,6 +117,7 @@ import
org.apache.nifi.attribute.expression.language.evaluation.functions.ToStri
import
org.apache.nifi.attribute.expression.language.evaluation.functions.ToUpperEvaluator;
import
org.apache.nifi.attribute.expression.language.evaluation.functions.EvaluateELStringEvaluator;
import
org.apache.nifi.attribute.expression.language.evaluation.functions.TrimEvaluator;
+import
org.apache.nifi.attribute.expression.language.evaluation.functions.GetUriEvaluator;
import
org.apache.nifi.attribute.expression.language.evaluation.functions.UrlDecodeEvaluator;
import
org.apache.nifi.attribute.expression.language.evaluation.functions.UrlEncodeEvaluator;
import
org.apache.nifi.attribute.expression.language.evaluation.functions.UuidEvaluator;
@@ -152,6 +153,8 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionLexer.TO_MICROS;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionLexer.TO_NANOS;
@@ -187,6 +190,7 @@ import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpre
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.FROM_RADIX;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.GET_DELIMITED_FIELD;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.GET_STATE_VALUE;
+import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.GET_URI;
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.HASH;
@@ -217,6 +221,7 @@ import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpre
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.NULL;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.OR;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.PAD_LEFT;
import static
org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.PAD_RIGHT;
@@ -1202,6 +1207,8 @@ public class ExpressionCompiler {
case TRUE:
case FALSE:
return buildBooleanEvaluator(tree);
+ case NULL:
+ return newStringLiteralEvaluator(null);
case UUID: {
return addToken(new UuidEvaluator(), "uuid");
}
@@ -1267,6 +1274,13 @@ public class ExpressionCompiler {
evaluators.add(eval);
return eval;
}
+ case GET_URI: {
+ List<Evaluator<String>> uriArgs = Stream.iterate(0, i -> i + 1)
+ .limit(tree.getChildCount())
+ .map(num ->
toStringEvaluator(buildEvaluator(tree.getChild(num))))
+ .collect(Collectors.toList());
+ return addToken(new GetUriEvaluator(uriArgs), "getUri");
+ }
default:
throw new
AttributeExpressionLanguageParsingException("Unexpected token: " +
tree.toString());
}
diff --git
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/GetUriEvaluator.java
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/GetUriEvaluator.java
new file mode 100644
index 0000000000..011b498910
--- /dev/null
+++
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/GetUriEvaluator.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.apache.nifi.attribute.expression.language.EvaluationContext;
+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;
+import
org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class GetUriEvaluator extends StringEvaluator {
+
+ private final List<Evaluator<String>> uriArgs;
+
+ public GetUriEvaluator(List<Evaluator<String>> uriArgs) {
+ this.uriArgs = uriArgs;
+ }
+
+ @Override
+ public QueryResult<String> evaluate(EvaluationContext evaluationContext) {
+ List<String> args = uriArgs.stream()
+ .map(uriArg -> uriArg.evaluate(evaluationContext).getValue())
+ .collect(Collectors.toList());
+
+ try {
+ if (args.size() == 7) {
+ final String scheme = args.get(0);
+ final String userInfo = args.get(1);
+ final String host = args.get(2);
+ final int port = getPort(args.get(3));
+ final String path = args.get(4);
+ final String query = args.get(5);
+ final String fragment = args.get(6);
+ final URI uri = new URI(scheme, userInfo, host, port, path,
query, fragment);
+ return new StringQueryResult(uri.toString());
+ }
+ throw new AttributeExpressionLanguageException("Could not evaluate
'getUri' function with " + args.size() + " argument(s)");
+ } catch (URISyntaxException use) {
+ throw new AttributeExpressionLanguageException("Could not evaluate
'getUri' function with argument(s) " + args, use);
+ }
+ }
+
+ private int getPort(String portArg) {
+ try {
+ return Integer.parseInt(portArg);
+ } catch (NumberFormatException nfe) {
+ throw new AttributeExpressionLanguageException("Could not evaluate
'getUri' function with argument '"
+ + portArg + "' which is not a number", nfe);
+ }
+ }
+ @Override
+ public Evaluator<?> getSubjectEvaluator() {
+ return null;
+ }
+}
diff --git
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/literals/StringLiteralEvaluator.java
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/literals/StringLiteralEvaluator.java
index 410449b59a..c3fffde0fb 100644
---
a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/literals/StringLiteralEvaluator.java
+++
b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/literals/StringLiteralEvaluator.java
@@ -27,40 +27,44 @@ public class StringLiteralEvaluator extends StringEvaluator
{
private final String value;
public StringLiteralEvaluator(final String value) {
- // need to escape characters after backslashes
- final StringBuilder sb = new StringBuilder();
- boolean lastCharIsBackslash = false;
- for (int i = 0; i < value.length(); i++) {
- final char c = value.charAt(i);
+ if(value == null) {
+ this.value = null;
+ } else {
+ // need to escape characters after backslashes
+ final StringBuilder sb = new StringBuilder();
+ boolean lastCharIsBackslash = false;
+ for (int i = 0; i < value.length(); i++) {
+ final char c = value.charAt(i);
- if (lastCharIsBackslash) {
- switch (c) {
- case 'n':
- sb.append("\n");
- break;
- case 'r':
- sb.append("\r");
- break;
- case '\\':
- sb.append("\\");
- break;
- case 't':
- sb.append("\\t");
- break;
- default:
- sb.append("\\").append(c);
- break;
- }
+ if (lastCharIsBackslash) {
+ switch (c) {
+ case 'n':
+ sb.append("\n");
+ break;
+ case 'r':
+ sb.append("\r");
+ break;
+ case '\\':
+ sb.append("\\");
+ break;
+ case 't':
+ sb.append("\\t");
+ break;
+ default:
+ sb.append("\\").append(c);
+ break;
+ }
- lastCharIsBackslash = false;
- } else if (c == '\\') {
- lastCharIsBackslash = true;
- } else {
- sb.append(c);
+ lastCharIsBackslash = false;
+ } else if (c == '\\') {
+ lastCharIsBackslash = true;
+ } else {
+ sb.append(c);
+ }
}
- }
- this.value = sb.toString();
+ this.value = sb.toString();
+ }
}
@Override
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 4db4f0a943..55d252f7a8 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
@@ -28,6 +28,7 @@ import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterDescriptor;
import org.apache.nifi.parameter.ParameterLookup;
import org.apache.nifi.registry.VariableRegistry;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -2398,6 +2399,27 @@ public class TestQuery {
verifyEquals("${nullAttr:isJson()}", attributes, false);
}
+ @Test
+ void testGetUri() {
+ verifyEquals("${getUri('https', 'admin:admin', 'nifi.apache.org',
'1234', '/path/data ', 'key=value &key2=value2', 'frag1')}",
+ null,
"https://admin:[email protected]:1234/path/data%20?key=value%20&key2=value2#frag1");
+ verifyEquals("${getUri('https', null, 'nifi.apache.org', 8443,
'/docs.html', null, null)}",
+ null, "https://nifi.apache.org:8443/docs.html");
+ verifyEquals("${getUri('http', null, 'nifi.apache.org', -1,
'/docs.html', null, null)}",
+ null, "http://nifi.apache.org/docs.html");
+
+ assertInvalid("${getUri()}");
+
assertInvalid("${getUri('http://nifi.apache.org:1234/path/data?key=value&key2=value2#frag1')}");
+ assertInvalid("${getUri('https', 'admin:admin')}");
+ assertInvalid("${getUri('mailto', '[email protected]', '')}");
+ assertInvalid("${getUri('http', 'nifi.apache.org', '/path/data',
'frag1')}");
+ assertInvalid("${getUri('https', 'admin:[email protected]:1234',
'/path/data ', 'key=value&key2=value2', 'frag1')}");
+
+ AttributeExpressionLanguageException thrown =
assertThrows(AttributeExpressionLanguageException.class,
+ () -> verifyEquals("${getUri('https', 'admin:admin',
'nifi.apache.org', 'notANumber', '/path/data ', 'key=value&key2=value2',
'frag1')}", null, ""));
+ Assertions.assertEquals("Could not evaluate 'getUri' function with
argument 'notANumber' which is not a number", thrown.getMessage());
+ }
+
private void verifyEquals(final String expression, final Map<String,
String> attributes, final Object expectedResult) {
verifyEquals(expression,attributes, null, ParameterLookup.EMPTY,
expectedResult);
}
diff --git a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
index 8fab2761b1..fd3dd94ef5 100644
--- a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
@@ -2616,6 +2616,47 @@ names begin with the letter `a`.
+
+[.function]
+=== getUri
+
+*Description*: [.description]#Returns a URI compliant with RFC 2396. This
includes encoding non-US-ASCII characters and
+quoting illegal characters with octets. This expression utilizes the
+link:https://docs.oracle.com/javase/8/docs/api/java/net/URI.html[java.net.URI^]
class to build a URI.
+As described in the API, a hierarchical URI consists of seven components
represented with the following types:#
+|============================================================================
+| Component | Type
+| `scheme` | `String`
+| `user-info` | `String`
+| `host` | `String`
+| `port` | `int`
+| `path` | `String`
+| `query` | `String`
+| `fragment` | `String`
+|============================================================================
+
+See the API for more details on character categories, encoding and quoting.
+
+*Subject Type*: [.subjectless]#No Subject#
+
+*Arguments*: This expression takes seven arguments.
+
+- [.argName]#_scheme_#, [.argName]#_userinfo_#, [.argName]#_host_#,
[.argName]#_port_#, [.argName]#_path_#, [.argName]#_query_#,
[.argName]#_fragment_#
+
+*NOTE:* Any component of the new URI may be left undefined by passing
[.argName]#_null_# for the corresponding parameter or, in the case of the port
parameter, by passing [.argName]#_-1_#.
+
+*Return Type*: [.returnType]#String#
+
+*Examples*
+The following examples detail how this expression can be invoked:
+
+|============================================================================
+| Expression | Value
+|`${getUri('https', 'admin:admin', 'nifi.apache.org', '1234', '/path/data ',
'key=value &key2=value2', 'frag1')}` |
`https://admin:[email protected]:1234/path/data%20?key=value%20&key2=value2#frag1`
+|`${getUri('https', null, 'nifi.apache.org', 8443, '/docs.html', null, null)}`
| `https://nifi.apache.org:8443/docs.html`
+|`${getUri('http', null, 'nifi.apache.org', -1, '/docs.html', null, null)}`
| `http://nifi.apache.org/docs.html`
+|============================================================================
+
[[multi]]
== Evaluating Multiple Attributes