mirror of https://github.com/apache/nifi.git
NIFI-5026: Refactored StandardPreparedQuery so that instead of a List of Strings that may or may not correspond to compiled expressions and a Map of String to Compiled Expression, the StandardPreparedQuery now just takes a List of Expression objects, and those Expressions can be evaluated to return the proper result
Signed-off-by: Pierre Villard <pierre.villard.fr@gmail.com> This closes #2592.
This commit is contained in:
parent
bbbe428e7b
commit
fd31c161a2
|
@ -15,14 +15,16 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.nifi.attribute.expression.language.compile;
|
package org.apache.nifi.attribute.expression.language;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.antlr.runtime.tree.Tree;
|
import org.antlr.runtime.tree.Tree;
|
||||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||||
|
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||||
|
|
||||||
public class CompiledExpression {
|
public class CompiledExpression implements Expression {
|
||||||
private final Evaluator<?> rootEvaluator;
|
private final Evaluator<?> rootEvaluator;
|
||||||
private final Tree tree;
|
private final Tree tree;
|
||||||
private final String expression;
|
private final String expression;
|
||||||
|
@ -50,4 +52,9 @@ public class CompiledExpression {
|
||||||
public Set<Evaluator<?>> getAllEvaluators() {
|
public Set<Evaluator<?>> getAllEvaluators() {
|
||||||
return allEvaluators;
|
return allEvaluators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String evaluate(final Map<String, String> variables, final AttributeValueDecorator decorator, final Map<String, String> stateVariables) {
|
||||||
|
return Query.evaluateExpression(getTree(), expression, variables, decorator, stateVariables);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||||
|
|
||||||
|
public interface Expression {
|
||||||
|
/**
|
||||||
|
* Evaluates this Expression against the given variables, attribute decorator, and state variables
|
||||||
|
*
|
||||||
|
* @param variables variables to be evaluated
|
||||||
|
* @param decorator decorator to decorate variable values
|
||||||
|
* @param stateVariables state variables to include in evaluation
|
||||||
|
* @return the evaluated value
|
||||||
|
*/
|
||||||
|
String evaluate(Map<String, String> variables, AttributeValueDecorator decorator, Map<String, String> stateVariables);
|
||||||
|
}
|
|
@ -17,13 +17,11 @@
|
||||||
package org.apache.nifi.attribute.expression.language;
|
package org.apache.nifi.attribute.expression.language;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.antlr.runtime.tree.Tree;
|
import org.antlr.runtime.tree.Tree;
|
||||||
import org.apache.nifi.attribute.expression.language.compile.CompiledExpression;
|
|
||||||
import org.apache.nifi.attribute.expression.language.compile.ExpressionCompiler;
|
import org.apache.nifi.attribute.expression.language.compile.ExpressionCompiler;
|
||||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
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.QueryResult;
|
||||||
|
@ -256,32 +254,30 @@ public class Query {
|
||||||
final ExpressionCompiler compiler = new ExpressionCompiler();
|
final ExpressionCompiler compiler = new ExpressionCompiler();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final List<String> substrings = new ArrayList<>();
|
final List<Expression> expressions = new ArrayList<>();
|
||||||
final Map<String, CompiledExpression> compiledExpressions = new HashMap<>();
|
|
||||||
|
|
||||||
int lastIndex = 0;
|
int lastIndex = 0;
|
||||||
for (final Range range : ranges) {
|
for (final Range range : ranges) {
|
||||||
if (range.getStart() > lastIndex) {
|
if (range.getStart() > lastIndex) {
|
||||||
substrings.add(query.substring(lastIndex, range.getStart()).replace("$$", "$"));
|
final String substring = query.substring(lastIndex, range.getStart()).replace("$$", "$");
|
||||||
|
expressions.add(new StringLiteralExpression(substring));
|
||||||
lastIndex = range.getEnd() + 1;
|
lastIndex = range.getEnd() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String treeText = query.substring(range.getStart(), range.getEnd() + 1).replace("$$", "$");
|
final String treeText = query.substring(range.getStart(), range.getEnd() + 1).replace("$$", "$");
|
||||||
substrings.add(treeText);
|
|
||||||
|
|
||||||
final CompiledExpression compiledExpression = compiler.compile(treeText);
|
final CompiledExpression compiledExpression = compiler.compile(treeText);
|
||||||
|
expressions.add(compiledExpression);
|
||||||
|
|
||||||
compiledExpressions.put(treeText, compiledExpression);
|
|
||||||
lastIndex = range.getEnd() + 1;
|
lastIndex = range.getEnd() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Range lastRange = ranges.get(ranges.size() - 1);
|
final Range lastRange = ranges.get(ranges.size() - 1);
|
||||||
if (lastRange.getEnd() + 1 < query.length()) {
|
if (lastRange.getEnd() + 1 < query.length()) {
|
||||||
final String treeText = query.substring(lastRange.getEnd() + 1).replace("$$", "$");
|
final String treeText = query.substring(lastRange.getEnd() + 1).replace("$$", "$");
|
||||||
substrings.add(treeText);
|
expressions.add(new StringLiteralExpression(treeText));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StandardPreparedQuery(substrings, compiledExpressions);
|
return new StandardPreparedQuery(expressions);
|
||||||
} catch (final AttributeExpressionLanguageParsingException e) {
|
} catch (final AttributeExpressionLanguageParsingException e) {
|
||||||
return new InvalidPreparedQuery(query, e.getMessage());
|
return new InvalidPreparedQuery(query, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.nifi.attribute.expression.language.compile.CompiledExpression;
|
|
||||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||||
import org.apache.nifi.attribute.expression.language.evaluation.literals.StringLiteralEvaluator;
|
import org.apache.nifi.attribute.expression.language.evaluation.literals.StringLiteralEvaluator;
|
||||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.AllAttributesEvaluator;
|
import org.apache.nifi.attribute.expression.language.evaluation.selection.AllAttributesEvaluator;
|
||||||
|
@ -37,29 +36,25 @@ import org.apache.nifi.processor.exception.ProcessException;
|
||||||
|
|
||||||
public class StandardPreparedQuery implements PreparedQuery {
|
public class StandardPreparedQuery implements PreparedQuery {
|
||||||
|
|
||||||
private final List<String> queryStrings;
|
private final List<Expression> expressions;
|
||||||
private final Map<String, CompiledExpression> expressions;
|
|
||||||
private volatile VariableImpact variableImpact;
|
private volatile VariableImpact variableImpact;
|
||||||
|
|
||||||
public StandardPreparedQuery(final List<String> queryStrings, final Map<String, CompiledExpression> expressions) {
|
public StandardPreparedQuery(final List<Expression> expressions) {
|
||||||
this.queryStrings = queryStrings;
|
|
||||||
this.expressions = expressions;
|
this.expressions = expressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String evaluateExpressions(final Map<String, String> valMap, final AttributeValueDecorator decorator, final Map<String, String> stateVariables) throws ProcessException {
|
public String evaluateExpressions(final Map<String, String> valMap, final AttributeValueDecorator decorator, final Map<String, String> stateVariables) throws ProcessException {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
for (final String val : queryStrings) {
|
|
||||||
final CompiledExpression expression = expressions.get(val);
|
for (final Expression expression : expressions) {
|
||||||
if (expression == null) {
|
final String evaluated = expression.evaluate(valMap, decorator, stateVariables);
|
||||||
sb.append(val);
|
|
||||||
} else {
|
if (evaluated != null) {
|
||||||
final String evaluated = Query.evaluateExpression(expression.getTree(), val, valMap, decorator, stateVariables);
|
sb.append(evaluated);
|
||||||
if (evaluated != null) {
|
|
||||||
sb.append(evaluated);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +78,13 @@ public class StandardPreparedQuery implements PreparedQuery {
|
||||||
|
|
||||||
final Set<String> variables = new HashSet<>();
|
final Set<String> variables = new HashSet<>();
|
||||||
|
|
||||||
for (final CompiledExpression expression : expressions.values()) {
|
for (final Expression expression : expressions) {
|
||||||
for (final Evaluator<?> evaluator : expression.getAllEvaluators()) {
|
if (!(expression instanceof CompiledExpression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompiledExpression compiled = (CompiledExpression) expression;
|
||||||
|
for (final Evaluator<?> evaluator : compiled.getAllEvaluators()) {
|
||||||
if (evaluator instanceof AttributeEvaluator) {
|
if (evaluator instanceof AttributeEvaluator) {
|
||||||
final AttributeEvaluator attributeEval = (AttributeEvaluator) evaluator;
|
final AttributeEvaluator attributeEval = (AttributeEvaluator) evaluator;
|
||||||
final Evaluator<String> nameEval = attributeEval.getNameEvaluator();
|
final Evaluator<String> nameEval = attributeEval.getNameEvaluator();
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||||
|
|
||||||
|
public class StringLiteralExpression implements Expression {
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public StringLiteralExpression(final String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String evaluate(Map<String, String> variables, AttributeValueDecorator decorator, Map<String, String> stateVariables) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,6 +119,7 @@ import org.antlr.runtime.ANTLRStringStream;
|
||||||
import org.antlr.runtime.CharStream;
|
import org.antlr.runtime.CharStream;
|
||||||
import org.antlr.runtime.CommonTokenStream;
|
import org.antlr.runtime.CommonTokenStream;
|
||||||
import org.antlr.runtime.tree.Tree;
|
import org.antlr.runtime.tree.Tree;
|
||||||
|
import org.apache.nifi.attribute.expression.language.CompiledExpression;
|
||||||
import org.apache.nifi.attribute.expression.language.Query;
|
import org.apache.nifi.attribute.expression.language.Query;
|
||||||
import org.apache.nifi.attribute.expression.language.Query.Range;
|
import org.apache.nifi.attribute.expression.language.Query.Range;
|
||||||
import org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionLexer;
|
import org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionLexer;
|
||||||
|
|
|
@ -74,6 +74,21 @@ public class TestQuery {
|
||||||
//System.out.println(Query.compile("").evaluate(null));
|
//System.out.println(Query.compile("").evaluate(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrepareWithEscapeChar() {
|
||||||
|
final Map<String, String> variables = Collections.singletonMap("foo", "bar");
|
||||||
|
|
||||||
|
final PreparedQuery onlyEscapedQuery = Query.prepare("$${foo}");
|
||||||
|
final String onlyEscapedEvaluated = onlyEscapedQuery.evaluateExpressions(variables, null);
|
||||||
|
assertEquals("${foo}", onlyEscapedEvaluated);
|
||||||
|
|
||||||
|
final PreparedQuery mixedQuery = Query.prepare("${foo}$${foo}");
|
||||||
|
final String mixedEvaluated = mixedQuery.evaluateExpressions(variables, null);
|
||||||
|
assertEquals("bar${foo}", mixedEvaluated);
|
||||||
|
|
||||||
|
assertEquals("bar${foo}$bar", Query.prepare("${foo}$${foo}$$${foo}").evaluateExpressions(variables, null));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertValid(final String query) {
|
private void assertValid(final String query) {
|
||||||
try {
|
try {
|
||||||
Query.compile(query);
|
Query.compile(query);
|
||||||
|
|
Loading…
Reference in New Issue