mirror of https://github.com/apache/nifi.git
NIFI-4224:
- Initial implementation of Process Group level Variable Registry - Updated to incorporate PR Feedback - Changed log message because slf4j-simple apparently has a memory leak; passing a String instead of passing in the Controller Service object as an argument addresses this. - This closes #2051
This commit is contained in:
parent
c1b99d584d
commit
5cd8e93beb
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.registry;
|
||||
|
||||
public interface ComponentVariableRegistry extends VariableRegistry {
|
||||
VariableRegistry getParent();
|
||||
|
||||
void setParent(VariableRegistry parentRegistry);
|
||||
}
|
|
@ -66,6 +66,44 @@ public final class VariableDescriptor implements Comparable<VariableDescriptor>
|
|||
return getName().compareTo(o.getName());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean isSensitive() {
|
||||
return sensitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!(other instanceof VariableDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final VariableDescriptor desc = (VariableDescriptor) other;
|
||||
return this.name.equals(desc.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 797 + this.name.hashCode() * 97;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[" + name + "]";
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
|
||||
private String name = null;
|
||||
|
@ -112,43 +150,4 @@ public final class VariableDescriptor implements Comparable<VariableDescriptor>
|
|||
return new VariableDescriptor(this);
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean isSensitive() {
|
||||
return sensitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(other instanceof VariableDescriptor)) {
|
||||
return false;
|
||||
}
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final VariableDescriptor desc = (VariableDescriptor) other;
|
||||
return this.name.equals(desc.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 797 + this.name.hashCode() * 97;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[" + name + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.attribute.expression.language;
|
|||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
|
@ -43,4 +44,9 @@ public class EmptyPreparedQuery implements PreparedQuery {
|
|||
public boolean isExpressionLanguagePresent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableImpact getVariableImpact() {
|
||||
return VariableImpact.NEVER_IMPACTED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.attribute.expression.language;
|
|||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException;
|
||||
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
@ -52,4 +53,9 @@ public class InvalidPreparedQuery implements PreparedQuery {
|
|||
public boolean isExpressionLanguagePresent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableImpact getVariableImpact() {
|
||||
return VariableImpact.NEVER_IMPACTED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.Set;
|
||||
|
||||
public class NamedVariableImpact implements VariableImpact {
|
||||
private final Set<String> impactedVariableNames;
|
||||
|
||||
public NamedVariableImpact(final Set<String> impactedVariableNames) {
|
||||
this.impactedVariableNames = impactedVariableNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImpacted(final String variableName) {
|
||||
return impactedVariableNames.contains(variableName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class NoVariablesImpacted implements VariableImpact {
|
||||
@Override
|
||||
public boolean isImpacted(final String variableName) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.attribute.expression.language;
|
|||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
|
@ -28,4 +29,13 @@ public interface PreparedQuery {
|
|||
String evaluateExpressions(final Map<String, String> valueLookup, final AttributeValueDecorator decorator, final Map<String, String> stateVariables) throws ProcessException;
|
||||
|
||||
boolean isExpressionLanguagePresent();
|
||||
|
||||
/**
|
||||
* Returns a {@link VariableImpact} that can be used to determine whether or not a given
|
||||
* variable impacts this Expression.
|
||||
*
|
||||
* @return a {@link VariableImpact} that can be used to determine whether or not a given
|
||||
* variable impacts this Expression.
|
||||
*/
|
||||
VariableImpact getVariableImpact();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,36 +16,45 @@
|
|||
*/
|
||||
package org.apache.nifi.attribute.expression.language;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.literals.StringLiteralEvaluator;
|
||||
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.AttributeEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.MappingEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.MultiAttributeEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.MultiMatchAttributeEvaluator;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.selection.MultiNamedAttributeEvaluator;
|
||||
import org.apache.nifi.expression.AttributeValueDecorator;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
|
||||
public class StandardPreparedQuery implements PreparedQuery {
|
||||
|
||||
private final List<String> queryStrings;
|
||||
private final Map<String, Tree> trees;
|
||||
private final Map<String, CompiledExpression> expressions;
|
||||
private volatile VariableImpact variableImpact;
|
||||
|
||||
public StandardPreparedQuery(final List<String> queryStrings, final Map<String, Tree> trees) {
|
||||
this.queryStrings = new ArrayList<>(queryStrings);
|
||||
this.trees = new HashMap<>(trees);
|
||||
public StandardPreparedQuery(final List<String> queryStrings, final Map<String, CompiledExpression> expressions) {
|
||||
this.queryStrings = queryStrings;
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String evaluateExpressions(final Map<String, String> valMap, final AttributeValueDecorator decorator, final Map<String, String> stateVariables) throws ProcessException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (final String val : queryStrings) {
|
||||
final Tree tree = trees.get(val);
|
||||
if (tree == null) {
|
||||
final CompiledExpression expression = expressions.get(val);
|
||||
if (expression == null) {
|
||||
sb.append(val);
|
||||
} else {
|
||||
final String evaluated = Query.evaluateExpression(tree, val, valMap, decorator, stateVariables);
|
||||
final String evaluated = Query.evaluateExpression(expression.getTree(), val, valMap, decorator, stateVariables);
|
||||
if (evaluated != null) {
|
||||
sb.append(evaluated);
|
||||
}
|
||||
|
@ -62,6 +71,56 @@ public class StandardPreparedQuery implements PreparedQuery {
|
|||
|
||||
@Override
|
||||
public boolean isExpressionLanguagePresent() {
|
||||
return !trees.isEmpty();
|
||||
return !expressions.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableImpact getVariableImpact() {
|
||||
final VariableImpact existing = this.variableImpact;
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
final Set<String> variables = new HashSet<>();
|
||||
|
||||
for (final CompiledExpression expression : expressions.values()) {
|
||||
for (final Evaluator<?> evaluator : expression.getAllEvaluators()) {
|
||||
if (evaluator instanceof AttributeEvaluator) {
|
||||
final AttributeEvaluator attributeEval = (AttributeEvaluator) evaluator;
|
||||
final Evaluator<String> nameEval = attributeEval.getNameEvaluator();
|
||||
|
||||
if (nameEval instanceof StringLiteralEvaluator) {
|
||||
final String referencedVar = nameEval.evaluate(Collections.emptyMap()).getValue();
|
||||
variables.add(referencedVar);
|
||||
}
|
||||
} else if (evaluator instanceof AllAttributesEvaluator) {
|
||||
final AllAttributesEvaluator allAttrsEval = (AllAttributesEvaluator) evaluator;
|
||||
final MultiAttributeEvaluator iteratingEval = allAttrsEval.getVariableIteratingEvaluator();
|
||||
if (iteratingEval instanceof MultiNamedAttributeEvaluator) {
|
||||
variables.addAll(((MultiNamedAttributeEvaluator) iteratingEval).getAttributeNames());
|
||||
} else if (iteratingEval instanceof MultiMatchAttributeEvaluator) {
|
||||
return VariableImpact.ALWAYS_IMPACTED;
|
||||
}
|
||||
} else if (evaluator instanceof AnyAttributeEvaluator) {
|
||||
final AnyAttributeEvaluator allAttrsEval = (AnyAttributeEvaluator) evaluator;
|
||||
final MultiAttributeEvaluator iteratingEval = allAttrsEval.getVariableIteratingEvaluator();
|
||||
if (iteratingEval instanceof MultiNamedAttributeEvaluator) {
|
||||
variables.addAll(((MultiNamedAttributeEvaluator) iteratingEval).getAttributeNames());
|
||||
} else if (iteratingEval instanceof MultiMatchAttributeEvaluator) {
|
||||
return VariableImpact.ALWAYS_IMPACTED;
|
||||
}
|
||||
} else if (evaluator instanceof MappingEvaluator) {
|
||||
final MappingEvaluator<?> allAttrsEval = (MappingEvaluator<?>) evaluator;
|
||||
final MultiAttributeEvaluator iteratingEval = allAttrsEval.getVariableIteratingEvaluator();
|
||||
if (iteratingEval instanceof MultiNamedAttributeEvaluator) {
|
||||
variables.addAll(((MultiNamedAttributeEvaluator) iteratingEval).getAttributeNames());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final VariableImpact impact = new NamedVariableImpact(variables);
|
||||
this.variableImpact = impact;
|
||||
return impact;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ final class ValueLookup implements Map<String, String> {
|
|||
* @param flowFile the flowFile to pull attributes from; may be null
|
||||
* @param additionalMaps the maps to pull values from; may be null or empty
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
ValueLookup(final VariableRegistry registry, final FlowFile flowFile, final Map<String, String>... additionalMaps) {
|
||||
for (final Map<String, String> map : additionalMaps) {
|
||||
if (map != null && !map.isEmpty()) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public interface VariableImpact {
|
||||
boolean isImpacted(String variableName);
|
||||
|
||||
public static final VariableImpact NEVER_IMPACTED = var -> false;
|
||||
|
||||
public static final VariableImpact ALWAYS_IMPACTED = var -> true;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.compile;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
|
||||
|
||||
public class CompiledExpression {
|
||||
private final Evaluator<?> rootEvaluator;
|
||||
private final Tree tree;
|
||||
private final String expression;
|
||||
private final Set<Evaluator<?>> allEvaluators;
|
||||
|
||||
public CompiledExpression(final String expression, final Evaluator<?> rootEvaluator, final Tree tree, final Set<Evaluator<?>> allEvaluators) {
|
||||
this.rootEvaluator = rootEvaluator;
|
||||
this.tree = tree;
|
||||
this.expression = expression;
|
||||
this.allEvaluators = allEvaluators;
|
||||
}
|
||||
|
||||
public Evaluator<?> getRootEvaluator() {
|
||||
return rootEvaluator;
|
||||
}
|
||||
|
||||
public Tree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public Set<Evaluator<?>> getAllEvaluators() {
|
||||
return allEvaluators;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -70,4 +70,8 @@ public class AllAttributesEvaluator extends BooleanEvaluator implements Iteratin
|
|||
public Evaluator<?> getLogicEvaluator() {
|
||||
return booleanEvaluator;
|
||||
}
|
||||
|
||||
public MultiAttributeEvaluator getVariableIteratingEvaluator() {
|
||||
return multiAttributeEvaluator;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,4 +70,8 @@ public class AnyAttributeEvaluator extends BooleanEvaluator implements Iterating
|
|||
public Evaluator<Boolean> getLogicEvaluator() {
|
||||
return booleanEvaluator;
|
||||
}
|
||||
|
||||
public MultiAttributeEvaluator getVariableIteratingEvaluator() {
|
||||
return multiAttributeEvaluator;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.functions;
|
||||
package org.apache.nifi.attribute.expression.language.evaluation.selection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -42,4 +42,8 @@ public class AttributeEvaluator extends StringEvaluator {
|
|||
public Evaluator<?> getSubjectEvaluator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Evaluator<String> getNameEvaluator() {
|
||||
return nameEvaluator;
|
||||
}
|
||||
}
|
|
@ -68,4 +68,8 @@ public class MappingEvaluator<T> implements Evaluator<T> {
|
|||
public void setToken(final String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public MultiAttributeEvaluator getVariableIteratingEvaluator() {
|
||||
return multiAttributeEvaluator;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,4 +66,8 @@ public class MultiNamedAttributeEvaluator extends MultiAttributeEvaluator {
|
|||
public Evaluator<?> getLogicEvaluator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getAttributeNames() {
|
||||
return attributeNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ package org.apache.nifi.attribute.expression.language;
|
|||
import static java.lang.Double.NEGATIVE_INFINITY;
|
||||
import static java.lang.Double.NaN;
|
||||
import static java.lang.Double.POSITIVE_INFINITY;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
|
@ -40,6 +40,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.runtime.tree.Tree;
|
||||
import org.apache.nifi.attribute.expression.language.Query.Range;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.NumberQueryResult;
|
||||
import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
|
||||
|
@ -47,14 +48,10 @@ import org.apache.nifi.attribute.expression.language.exception.AttributeExpressi
|
|||
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.apache.nifi.registry.VariableRegistry;
|
||||
import org.junit.Assert;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class TestQuery {
|
||||
|
@ -304,7 +301,7 @@ public class TestQuery {
|
|||
|
||||
@Test(expected = AttributeExpressionLanguageException.class)
|
||||
public void testCannotCombineWithNonReducingFunction() {
|
||||
Query.compileTree("${allAttributes( 'a.1' ):plus(1)}");
|
||||
Query.compile("${allAttributes( 'a.1' ):plus(1)}");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -357,6 +354,7 @@ public class TestQuery {
|
|||
assertEquals("Val", evaluateQueryForEscape("${attr:replaceAll(\"My (Val)ue{1,2}\", '$1')}", attributes));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String evaluateQueryForEscape(final String queryString, final Map<String, String> attributes) {
|
||||
final FlowFile mockFlowFile = Mockito.mock(FlowFile.class);
|
||||
Mockito.when(mockFlowFile.getAttributes()).thenReturn(attributes);
|
||||
|
@ -639,7 +637,7 @@ public class TestQuery {
|
|||
final String query = "${ abc:equals('abc'):or( \n\t${xx:isNull()}\n) }";
|
||||
assertEquals(ResultType.BOOLEAN, Query.getResultType(query));
|
||||
Query.validateExpression(query, false);
|
||||
assertEquals("true", Query.evaluateExpressions(query, Collections.EMPTY_MAP));
|
||||
assertEquals("true", Query.evaluateExpressions(query, Collections.emptyMap()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1675,25 +1673,25 @@ public class TestQuery {
|
|||
verifyEquals("${string:escapeHtml4()}", attributes, "special ♣");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnescapeFunctions() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
@Test
|
||||
public void testUnescapeFunctions() {
|
||||
final Map<String, String> attributes = new HashMap<>();
|
||||
|
||||
attributes.put("string", "making air \\\"QUOTES\\\".");
|
||||
verifyEquals("${string:unescapeJson()}", attributes, "making air \"QUOTES\".");
|
||||
attributes.put("string", "making air \\\"QUOTES\\\".");
|
||||
verifyEquals("${string:unescapeJson()}", attributes, "making air \"QUOTES\".");
|
||||
|
||||
attributes.put("string", "M & M");
|
||||
verifyEquals("${string:unescapeXml()}", attributes, "M & M");
|
||||
attributes.put("string", "M & M");
|
||||
verifyEquals("${string:unescapeXml()}", attributes, "M & M");
|
||||
|
||||
attributes.put("string", "\"making air \"\"QUOTES\"\".\"");
|
||||
verifyEquals("${string:unescapeCsv()}", attributes, "making air \"QUOTES\".");
|
||||
attributes.put("string", "\"making air \"\"QUOTES\"\".\"");
|
||||
verifyEquals("${string:unescapeCsv()}", attributes, "making air \"QUOTES\".");
|
||||
|
||||
attributes.put("string", "special ¡");
|
||||
verifyEquals("${string:unescapeHtml3()}", attributes, "special ¡");
|
||||
attributes.put("string", "special ¡");
|
||||
verifyEquals("${string:unescapeHtml3()}", attributes, "special ¡");
|
||||
|
||||
attributes.put("string", "special ♣");
|
||||
verifyEquals("${string:unescapeHtml4()}", attributes, "special ♣");
|
||||
}
|
||||
attributes.put("string", "special ♣");
|
||||
verifyEquals("${string:unescapeHtml4()}", attributes, "special ♣");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfElse() {
|
||||
|
@ -1709,9 +1707,9 @@ public class TestQuery {
|
|||
verifyEquals("${attr2:isNull():ifElse('a', 'b')}", attributes, "a");
|
||||
verifyEquals("${literal(true):ifElse('a', 'b')}", attributes, "a");
|
||||
verifyEquals("${literal(true):ifElse(false, 'b')}", attributes, "false");
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void verifyEquals(final String expression, final Map<String, String> attributes, final Object expectedResult) {
|
||||
verifyEquals(expression,attributes, null, expectedResult);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,13 @@
|
|||
package org.apache.nifi.attribute.expression.language;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
@ -46,6 +50,7 @@ public class TestStandardPreparedQuery {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Intended for manual performance testing; should not be run in an automated environment")
|
||||
public void test10MIterations() {
|
||||
final Map<String, String> attrs = new HashMap<>();
|
||||
attrs.put("xx", "world");
|
||||
|
@ -84,6 +89,42 @@ public class TestStandardPreparedQuery {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariableImpacted() {
|
||||
final Set<String> attr = new HashSet<>();
|
||||
attr.add("attr");
|
||||
|
||||
final Set<String> attr2 = new HashSet<>();
|
||||
attr2.add("attr");
|
||||
attr2.add("attr2");
|
||||
|
||||
final Set<String> abc = new HashSet<>();
|
||||
abc.add("a");
|
||||
abc.add("b");
|
||||
abc.add("c");
|
||||
|
||||
assertTrue(Query.prepare("${attr}").getVariableImpact().isImpacted("attr"));
|
||||
assertFalse(Query.prepare("${attr}").getVariableImpact().isImpacted("attr2"));
|
||||
assertTrue(Query.prepare("${attr:trim():toUpper():equals('abc')}").getVariableImpact().isImpacted("attr"));
|
||||
|
||||
assertFalse(Query.prepare("${anyAttribute('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("attr"));
|
||||
assertTrue(Query.prepare("${anyAttribute('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("a"));
|
||||
assertTrue(Query.prepare("${anyAttribute('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("b"));
|
||||
assertTrue(Query.prepare("${anyAttribute('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("c"));
|
||||
|
||||
assertFalse(Query.prepare("${allAttributes('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("attr"));
|
||||
assertTrue(Query.prepare("${allAttributes('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("a"));
|
||||
assertTrue(Query.prepare("${allAttributes('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("b"));
|
||||
assertTrue(Query.prepare("${allAttributes('a', 'b', 'c'):equals('hello')}").getVariableImpact().isImpacted("c"));
|
||||
|
||||
assertTrue(Query.prepare("${attr:equals('${attr2}')}").getVariableImpact().isImpacted("attr"));
|
||||
assertTrue(Query.prepare("${attr:equals('${attr2}')}").getVariableImpact().isImpacted("attr2"));
|
||||
assertFalse(Query.prepare("${attr:equals('${attr2}')}").getVariableImpact().isImpacted("attr3"));
|
||||
|
||||
assertTrue(Query.prepare("${allMatchingAttributes('a.*'):equals('hello')}").getVariableImpact().isImpacted("attr"));
|
||||
assertTrue(Query.prepare("${anyMatchingAttribute('a.*'):equals('hello')}").getVariableImpact().isImpacted("attr"));
|
||||
}
|
||||
|
||||
private String evaluate(final String query, final Map<String, String> attrs) {
|
||||
final String evaluated = ((StandardPreparedQuery) Query.prepare(query)).evaluateExpressions(attrs, null);
|
||||
return evaluated;
|
||||
|
|
|
@ -25,12 +25,10 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TestValueLookup {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testCreateCustomVariableRegistry() {
|
||||
|
||||
final VariableRegistry variableRegistry = VariableRegistry.ENVIRONMENT_SYSTEM_REGISTRY;
|
||||
|
|
|
@ -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.web.api.dto;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlType(name = "affectedComponent")
|
||||
public class AffectedComponentDTO {
|
||||
public static final String COMPONENT_TYPE_PROCESSOR = "PROCESSOR";
|
||||
public static final String COMPONENT_TYPE_CONTROLLER_SERVICE = "CONTROLLER_SERVICE";
|
||||
|
||||
private String parentGroupId;
|
||||
private String componentId;
|
||||
private String componentType;
|
||||
|
||||
@ApiModelProperty("The UUID of the Process Group that this component is in")
|
||||
public String getParentGroupId() {
|
||||
return parentGroupId;
|
||||
}
|
||||
|
||||
public void setParentGroupId(final String parentGroupId) {
|
||||
this.parentGroupId = parentGroupId;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The UUID of this component")
|
||||
public String getComponentId() {
|
||||
return componentId;
|
||||
}
|
||||
|
||||
public void setComponentId(final String componentId) {
|
||||
this.componentId = componentId;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The type of this component", allowableValues = COMPONENT_TYPE_PROCESSOR + "," + COMPONENT_TYPE_CONTROLLER_SERVICE)
|
||||
public String getComponentType() {
|
||||
return componentType;
|
||||
}
|
||||
|
||||
public void setComponentType(final String componentType) {
|
||||
this.componentType = componentType;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@
|
|||
package org.apache.nifi.web.api.dto;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +30,7 @@ public class ProcessGroupDTO extends ComponentDTO {
|
|||
|
||||
private String name;
|
||||
private String comments;
|
||||
private Map<String, String> variables;
|
||||
|
||||
private Integer runningCount;
|
||||
private Integer stoppedCount;
|
||||
|
@ -200,4 +204,16 @@ public class ProcessGroupDTO extends ComponentDTO {
|
|||
this.inactiveRemotePortCount = inactiveRemotePortCount;
|
||||
}
|
||||
|
||||
|
||||
@ApiModelProperty(value = "The variables that are configured for the Process Group. Note that this map contains only "
|
||||
+ "those variables that are defined on this Process Group and not any variables that are defined in the parent "
|
||||
+ "Process Group, etc. I.e., this Map will not contain all variables that are accessible by components in this "
|
||||
+ "Process Group by rather only the variables that are defined for this Process Group itself.", readOnly = true)
|
||||
public Map<String, String> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void setVariables(final Map<String, String> variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.web.api.dto;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlType(name = "variable")
|
||||
public class VariableDTO {
|
||||
private String name;
|
||||
private String value;
|
||||
private String processGroupId;
|
||||
private Set<AffectedComponentDTO> affectedComponents = new HashSet<>();
|
||||
|
||||
@ApiModelProperty("The name of the variable")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The value of the variable")
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The ID of the Process Group where this Variable is defined", readOnly = true)
|
||||
public String getProcessGroupId() {
|
||||
return processGroupId;
|
||||
}
|
||||
|
||||
public void setProcessGroupId(String groupId) {
|
||||
this.processGroupId = groupId;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "A set of all components that will be affected if the value of this variable is changed", readOnly = true)
|
||||
public Set<AffectedComponentDTO> getAffectedComponents() {
|
||||
return affectedComponents;
|
||||
}
|
||||
|
||||
public void setAffectedComponents(Set<AffectedComponentDTO> affectedComponents) {
|
||||
this.affectedComponents = affectedComponents;
|
||||
}
|
||||
}
|
|
@ -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.web.api.dto;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.apache.nifi.web.api.entity.VariableEntity;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlType(name = "variableRegistry")
|
||||
public class VariableRegistryDTO {
|
||||
private Set<VariableEntity> variables;
|
||||
private String groupId;
|
||||
|
||||
public void setVariables(final Set<VariableEntity> variables) {
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The variables that are available in this Variable Registry")
|
||||
public Set<VariableEntity> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public void setProcessGroupId(final String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The UUID of the Process Group that this Variable Registry belongs to")
|
||||
public String getProcessGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.web.api.dto;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.apache.nifi.web.api.dto.util.TimestampAdapter;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlType(name = "variableRegistryUpdateRequest")
|
||||
public class VariableRegistryUpdateRequestDTO {
|
||||
private String requestId;
|
||||
private String processGroupId;
|
||||
private String uri;
|
||||
private Date submissionTime = new Date();
|
||||
private Date lastUpdated = new Date();
|
||||
private boolean complete = false;
|
||||
private String failureReason;
|
||||
private List<VariableRegistryUpdateStepDTO> updateSteps;
|
||||
|
||||
|
||||
@ApiModelProperty("The unique ID of the Process Group that the variable registry belongs to")
|
||||
public String getProcessGroupId() {
|
||||
return processGroupId;
|
||||
}
|
||||
|
||||
public void setProcessGroupId(String processGroupId) {
|
||||
this.processGroupId = processGroupId;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The unique ID of this request.", readOnly = true)
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The URI for future requests to this drop request.", readOnly = true)
|
||||
public String getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
@XmlJavaTypeAdapter(TimestampAdapter.class)
|
||||
@ApiModelProperty(value = "The time at which this request was submitted.", dataType = "string", readOnly = true)
|
||||
public Date getSubmissionTime() {
|
||||
return submissionTime;
|
||||
}
|
||||
|
||||
public void setSubmissionTime(Date submissionTime) {
|
||||
this.submissionTime = submissionTime;
|
||||
}
|
||||
|
||||
@XmlJavaTypeAdapter(TimestampAdapter.class)
|
||||
@ApiModelProperty(value = "The last time this request was updated.", dataType = "string", readOnly = true)
|
||||
public Date getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The steps that are required in order to complete the request, along with the status of each", readOnly = true)
|
||||
public List<VariableRegistryUpdateStepDTO> getUpdateSteps() {
|
||||
return updateSteps;
|
||||
}
|
||||
|
||||
public void setUpdateSteps(List<VariableRegistryUpdateStepDTO> updateSteps) {
|
||||
this.updateSteps = updateSteps;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "Whether or not this request has completed", readOnly = true)
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "An explanation of why this request failed, or null if this request has not failed", readOnly = true)
|
||||
public String getFailureReason() {
|
||||
return failureReason;
|
||||
}
|
||||
|
||||
public void setFailureReason(String reason) {
|
||||
this.failureReason = reason;
|
||||
}
|
||||
}
|
|
@ -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.web.api.dto;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlType(name = "varaibleRegistryUpdateStep")
|
||||
public class VariableRegistryUpdateStepDTO {
|
||||
private String description;
|
||||
private boolean complete;
|
||||
private String failureReason;
|
||||
|
||||
public VariableRegistryUpdateStepDTO() {
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "Explanation of what happens in this step", readOnly = true)
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "Whether or not this step has completed", readOnly = true)
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "An explanation of why this step failed, or null if this step did not fail", readOnly = true)
|
||||
public String getFailureReason() {
|
||||
return failureReason;
|
||||
}
|
||||
|
||||
public void setFailureReason(String reason) {
|
||||
this.failureReason = reason;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.web.api.entity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlRootElement(name = "activateControllerServicesEntity")
|
||||
public class ActivateControllerServicesEntity extends Entity {
|
||||
public static final String STATE_ENABLED = "ENABLED";
|
||||
public static final String STATE_DISABLED = "DISABLED";
|
||||
|
||||
private String id;
|
||||
private String state;
|
||||
private Map<String, RevisionDTO> components;
|
||||
|
||||
@ApiModelProperty("The id of the ProcessGroup")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The desired state of the descendant components. Possible states are 'RUNNING' and 'STOPPED'
|
||||
*/
|
||||
@ApiModelProperty(value = "The desired state of the descendant components",
|
||||
allowableValues = STATE_ENABLED + ", " + STATE_DISABLED)
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@ApiModelProperty("Optional services to schedule. If not specified, all authorized descendant controller services will be used.")
|
||||
public Map<String, RevisionDTO> getComponents() {
|
||||
return components;
|
||||
}
|
||||
|
||||
public void setComponents(Map<String, RevisionDTO> components) {
|
||||
this.components = components;
|
||||
}
|
||||
}
|
|
@ -16,17 +16,21 @@
|
|||
*/
|
||||
package org.apache.nifi.web.api.entity;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
/**
|
||||
* A serialized representation of this class can be placed in the entity body of a request to the API.
|
||||
*/
|
||||
@XmlRootElement(name = "scheduleComponentEntity")
|
||||
public class ScheduleComponentsEntity extends Entity {
|
||||
public static final String STATE_RUNNING = "RUNNING";
|
||||
public static final String STATE_STOPPED = "STOPPED";
|
||||
|
||||
private String id;
|
||||
private String state;
|
||||
|
@ -51,7 +55,7 @@ public class ScheduleComponentsEntity extends Entity {
|
|||
*/
|
||||
@ApiModelProperty(
|
||||
value = "The desired state of the descendant components",
|
||||
allowableValues = "RUNNING, STOPPED"
|
||||
allowableValues = STATE_RUNNING + ", " + STATE_STOPPED
|
||||
)
|
||||
public String getState() {
|
||||
return state;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.web.api.entity;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.nifi.web.api.dto.VariableDTO;
|
||||
import org.apache.nifi.web.api.dto.WritablePermission;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlRootElement(name = "variableEntity")
|
||||
public class VariableEntity extends Entity implements WritablePermission {
|
||||
private VariableDTO variable;
|
||||
private Boolean canWrite;
|
||||
|
||||
@Override
|
||||
@ApiModelProperty(value = "Indicates whether the user can write a given resource.", readOnly = true)
|
||||
public Boolean getCanWrite() {
|
||||
return canWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCanWrite(Boolean canWrite) {
|
||||
this.canWrite = canWrite;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The variable information")
|
||||
public VariableDTO getVariable() {
|
||||
return variable;
|
||||
}
|
||||
|
||||
public void setVariable(VariableDTO variable) {
|
||||
this.variable = variable;
|
||||
}
|
||||
}
|
|
@ -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.web.api.entity;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlRootElement(name = "variableRegistryEntity")
|
||||
public class VariableRegistryEntity extends Entity {
|
||||
private RevisionDTO groupRevision;
|
||||
private VariableRegistryDTO variableRegistry;
|
||||
|
||||
|
||||
@ApiModelProperty("The Variable Registry.")
|
||||
public VariableRegistryDTO getVariableRegistry() {
|
||||
return variableRegistry;
|
||||
}
|
||||
|
||||
public void setVariableRegistry(VariableRegistryDTO variableRegistry) {
|
||||
this.variableRegistry = variableRegistry;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The revision of the Process Group that the Variable Registry belongs to")
|
||||
public RevisionDTO getProcessGroupRevision() {
|
||||
return groupRevision;
|
||||
}
|
||||
|
||||
public void setProcessGroupRevision(RevisionDTO revision) {
|
||||
this.groupRevision = revision;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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.web.api.entity;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.apache.nifi.web.api.dto.RevisionDTO;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryUpdateRequestDTO;
|
||||
|
||||
import com.wordnik.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@XmlRootElement(name = "variableRegistryUpdateRequestEntity")
|
||||
public class VariableRegistryUpdateRequestEntity extends Entity {
|
||||
private VariableRegistryUpdateRequestDTO requestDto;
|
||||
private RevisionDTO processGroupRevision;
|
||||
|
||||
@ApiModelProperty("The revision for the Process Group that owns this variable registry.")
|
||||
public RevisionDTO getProcessGroupRevision() {
|
||||
return processGroupRevision;
|
||||
}
|
||||
|
||||
public void setProcessGroupRevision(RevisionDTO revision) {
|
||||
this.processGroupRevision = revision;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The Variable Registry Update Request")
|
||||
public VariableRegistryUpdateRequestDTO getRequestDto() {
|
||||
return requestDto;
|
||||
}
|
||||
|
||||
public void setRequestDto(VariableRegistryUpdateRequestDTO requestDto) {
|
||||
this.requestDto = requestDto;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,16 @@
|
|||
*/
|
||||
package org.apache.nifi.cluster.coordination.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
|
||||
import org.apache.nifi.cluster.coordination.http.endpoints.AccessPolicyEndpointMerger;
|
||||
import org.apache.nifi.cluster.coordination.http.endpoints.BulletinBoardEndpointMerger;
|
||||
import org.apache.nifi.cluster.coordination.http.endpoints.ComponentStateEndpointMerger;
|
||||
|
@ -77,15 +87,6 @@ import org.apache.nifi.util.NiFiProperties;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StandardHttpResponseMapper implements HttpResponseMapper {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(StandardHttpResponseMapper.class);
|
||||
|
|
|
@ -16,24 +16,6 @@
|
|||
*/
|
||||
package org.apache.nifi.controller;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
|
||||
import org.apache.nifi.bundle.Bundle;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
import org.apache.nifi.nar.ExtensionManager;
|
||||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
@ -53,6 +35,24 @@ import java.util.concurrent.locks.Lock;
|
|||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
|
||||
import org.apache.nifi.bundle.Bundle;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationContext;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
import org.apache.nifi.nar.ExtensionManager;
|
||||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractConfiguredComponent implements ConfigurableComponent, ConfiguredComponent {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractConfiguredComponent.class);
|
||||
|
||||
|
@ -64,7 +64,7 @@ public abstract class AbstractConfiguredComponent implements ConfigurableCompone
|
|||
private final AtomicReference<ValidationContext> validationContext = new AtomicReference<>();
|
||||
private final String componentType;
|
||||
private final String componentCanonicalClass;
|
||||
private final VariableRegistry variableRegistry;
|
||||
private final ComponentVariableRegistry variableRegistry;
|
||||
private final ReloadComponent reloadComponent;
|
||||
|
||||
private final AtomicBoolean isExtensionMissing;
|
||||
|
@ -74,7 +74,7 @@ public abstract class AbstractConfiguredComponent implements ConfigurableCompone
|
|||
|
||||
public AbstractConfiguredComponent(final String id,
|
||||
final ValidationContextFactory validationContextFactory, final ControllerServiceProvider serviceProvider,
|
||||
final String componentType, final String componentCanonicalClass, final VariableRegistry variableRegistry,
|
||||
final String componentType, final String componentCanonicalClass, final ComponentVariableRegistry variableRegistry,
|
||||
final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
this.id = id;
|
||||
this.validationContextFactory = validationContextFactory;
|
||||
|
@ -541,7 +541,7 @@ public abstract class AbstractConfiguredComponent implements ConfigurableCompone
|
|||
}
|
||||
}
|
||||
|
||||
protected VariableRegistry getVariableRegistry() {
|
||||
public ComponentVariableRegistry getVariableRegistry() {
|
||||
return this.variableRegistry;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.apache.nifi.components.ConfigurableComponent;
|
|||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
@ -38,6 +39,7 @@ import java.util.Set;
|
|||
|
||||
public interface ConfiguredComponent extends ComponentAuthorizable {
|
||||
|
||||
@Override
|
||||
public String getIdentifier();
|
||||
|
||||
public String getName();
|
||||
|
@ -99,6 +101,11 @@ public interface ConfiguredComponent extends ComponentAuthorizable {
|
|||
*/
|
||||
boolean isDeprecated();
|
||||
|
||||
/**
|
||||
* @return the variable registry for this component
|
||||
*/
|
||||
ComponentVariableRegistry getVariableRegistry();
|
||||
|
||||
@Override
|
||||
default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user, Map<String, String> resourceContext) {
|
||||
// if this is a modification request and the reporting task is restricted ensure the user has elevated privileges. if this
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.controller;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.connectable.Funnel;
|
||||
|
@ -41,7 +42,7 @@ public interface ProcessScheduler {
|
|||
* @param procNode to start
|
||||
* @throws IllegalStateException if the Processor is disabled
|
||||
*/
|
||||
void startProcessor(ProcessorNode procNode);
|
||||
Future<Void> startProcessor(ProcessorNode procNode);
|
||||
|
||||
/**
|
||||
* Stops scheduling the given processor to run and invokes all methods on
|
||||
|
@ -52,7 +53,7 @@ public interface ProcessScheduler {
|
|||
*
|
||||
* @param procNode to stop
|
||||
*/
|
||||
void stopProcessor(ProcessorNode procNode);
|
||||
Future<Void> stopProcessor(ProcessorNode procNode);
|
||||
|
||||
/**
|
||||
* Starts scheduling the given Port to run. If the Port is already scheduled
|
||||
|
@ -169,12 +170,12 @@ public interface ProcessScheduler {
|
|||
* Disables all of the given Controller Services in the order provided by the List
|
||||
* @param services the controller services to disable
|
||||
*/
|
||||
void disableControllerServices(List<ControllerServiceNode> services);
|
||||
CompletableFuture<Void> disableControllerServices(List<ControllerServiceNode> services);
|
||||
|
||||
/**
|
||||
* Disables the Controller Service so that it can be updated
|
||||
*
|
||||
* @param service to disable
|
||||
*/
|
||||
void disableControllerService(ControllerServiceNode service);
|
||||
CompletableFuture<Void> disableControllerService(ControllerServiceNode service);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
*/
|
||||
package org.apache.nifi.controller;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.controller.scheduling.ScheduleState;
|
||||
|
@ -26,18 +33,12 @@ import org.apache.nifi.logging.LogLevel;
|
|||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.Processor;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.scheduling.ExecutionNode;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public abstract class ProcessorNode extends AbstractConfiguredComponent implements Connectable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProcessorNode.class);
|
||||
|
@ -46,7 +47,7 @@ public abstract class ProcessorNode extends AbstractConfiguredComponent implemen
|
|||
|
||||
public ProcessorNode(final String id,
|
||||
final ValidationContextFactory validationContextFactory, final ControllerServiceProvider serviceProvider,
|
||||
final String componentType, final String componentCanonicalClass, final VariableRegistry variableRegistry,
|
||||
final String componentType, final String componentCanonicalClass, final ComponentVariableRegistry variableRegistry,
|
||||
final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
super(id, validationContextFactory, serviceProvider, componentType, componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
|
||||
this.scheduledState = new AtomicReference<>(ScheduledState.STOPPED);
|
||||
|
@ -185,7 +186,7 @@ public abstract class ProcessorNode extends AbstractConfiguredComponent implemen
|
|||
* the ScheduleState that can be used to ensure that the running state (STOPPED, RUNNING, etc.)
|
||||
* as well as the active thread counts are kept in sync
|
||||
*/
|
||||
public abstract <T extends ProcessContext & ControllerServiceLookup> void stop(ScheduledExecutorService scheduler,
|
||||
public abstract <T extends ProcessContext & ControllerServiceLookup> CompletableFuture<Void> stop(ScheduledExecutorService scheduler,
|
||||
T processContext, SchedulingAgent schedulingAgent, ScheduleState scheduleState);
|
||||
|
||||
/**
|
||||
|
|
|
@ -108,7 +108,7 @@ public interface ControllerServiceNode extends ConfiguredComponent {
|
|||
* implementation of {@link ScheduledExecutorService} used to
|
||||
* initiate service disabling task
|
||||
*/
|
||||
void disable(ScheduledExecutorService scheduler);
|
||||
CompletableFuture<Void> disable(ScheduledExecutorService scheduler);
|
||||
|
||||
/**
|
||||
* @return the ControllerServiceReference that describes which components are referencing this Controller Service
|
||||
|
|
|
@ -19,7 +19,7 @@ package org.apache.nifi.controller.service;
|
|||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.apache.nifi.annotation.lifecycle.OnAdded;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
|
@ -72,7 +72,7 @@ public interface ControllerServiceProvider extends ControllerServiceLookup {
|
|||
* @param serviceNode the service node
|
||||
* @return a Future that can be used to wait for the service to finish being enabled.
|
||||
*/
|
||||
Future<Void> enableControllerService(ControllerServiceNode serviceNode);
|
||||
CompletableFuture<Void> enableControllerService(ControllerServiceNode serviceNode);
|
||||
|
||||
/**
|
||||
* Enables the collection of services. If a service in this collection
|
||||
|
@ -90,7 +90,7 @@ public interface ControllerServiceProvider extends ControllerServiceLookup {
|
|||
*
|
||||
* @param serviceNode the node
|
||||
*/
|
||||
void disableControllerService(ControllerServiceNode serviceNode);
|
||||
CompletableFuture<Void> disableControllerService(ControllerServiceNode serviceNode);
|
||||
|
||||
/**
|
||||
* @return a Set of all Controller Services that exist for this service
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
|
@ -43,4 +44,13 @@ public interface ControllerServiceReference {
|
|||
* Controller Services)
|
||||
*/
|
||||
Set<ConfiguredComponent> getActiveReferences();
|
||||
|
||||
/**
|
||||
* Returns a List of all components that reference this Controller Service (recursively) that
|
||||
* are of the given type
|
||||
*
|
||||
* @param componentType the type of component that is desirable
|
||||
* @return a List of all components that reference this Controller Service that are of the given type
|
||||
*/
|
||||
<T> List<T> findRecursiveReferences(Class<T> componentType);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,20 @@
|
|||
*/
|
||||
package org.apache.nifi.groups;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.nifi.authorization.resource.ComponentAuthorizable;
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.connectable.Connection;
|
||||
import org.apache.nifi.connectable.Funnel;
|
||||
import org.apache.nifi.connectable.Port;
|
||||
import org.apache.nifi.connectable.Positionable;
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
import org.apache.nifi.controller.ProcessorNode;
|
||||
import org.apache.nifi.controller.ScheduledState;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
|
@ -30,13 +38,9 @@ import org.apache.nifi.controller.label.Label;
|
|||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.flowfile.FlowFile;
|
||||
import org.apache.nifi.processor.Processor;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ProcessGroup objects are containers for processing entities, such as
|
||||
|
@ -84,6 +88,7 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable {
|
|||
/**
|
||||
* @return the ID of the ProcessGroup
|
||||
*/
|
||||
@Override
|
||||
String getIdentifier();
|
||||
|
||||
/**
|
||||
|
@ -159,7 +164,7 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable {
|
|||
* @throws IllegalStateException if the processor is not valid, or is
|
||||
* already running
|
||||
*/
|
||||
void startProcessor(ProcessorNode processor);
|
||||
CompletableFuture<Void> startProcessor(ProcessorNode processor);
|
||||
|
||||
/**
|
||||
* Starts the given Input Port
|
||||
|
@ -187,7 +192,7 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable {
|
|||
*
|
||||
* @param processor to stop
|
||||
*/
|
||||
void stopProcessor(ProcessorNode processor);
|
||||
CompletableFuture<Void> stopProcessor(ProcessorNode processor);
|
||||
|
||||
/**
|
||||
* Stops the given Port
|
||||
|
@ -813,6 +818,15 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable {
|
|||
*/
|
||||
void verifyCanMove(Snippet snippet, ProcessGroup newProcessGroup);
|
||||
|
||||
/**
|
||||
* Ensures that the given variables can be updated
|
||||
*
|
||||
* @param updatedVariables the new set of variable names and values
|
||||
*
|
||||
* @throws IllegalStateException if one or more variables that are listed cannot be updated at this time
|
||||
*/
|
||||
void verifyCanUpdateVariables(Map<String, String> updatedVariables);
|
||||
|
||||
/**
|
||||
* Adds the given template to this Process Group
|
||||
*
|
||||
|
@ -853,4 +867,27 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable {
|
|||
* @return a Set of all Templates that belong to this Process Group and any descendant Process Groups
|
||||
*/
|
||||
Set<Template> findAllTemplates();
|
||||
|
||||
/**
|
||||
* Updates the variables that are provided by this Process Group
|
||||
*
|
||||
* @param variables the variables to provide
|
||||
* @throws IllegalStateException if the Process Group is not in a state that allows the variables to be updated
|
||||
*/
|
||||
void setVariables(Map<String, String> variables);
|
||||
|
||||
/**
|
||||
* Returns the Variable Registry for this Process Group
|
||||
*
|
||||
* @return the Variable Registry for this Process Group
|
||||
*/
|
||||
ComponentVariableRegistry getVariableRegistry();
|
||||
|
||||
/**
|
||||
* Returns a set of all components that are affected by the variable with the given name
|
||||
*
|
||||
* @param variableName the name of the variable
|
||||
* @return a set of all components that are affected by the variable with the given name
|
||||
*/
|
||||
Set<ConfiguredComponent> getComponentsAffectedByVariable(String variableName);
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -195,7 +195,10 @@ import org.apache.nifi.provenance.ProvenanceEventRecord;
|
|||
import org.apache.nifi.provenance.ProvenanceEventType;
|
||||
import org.apache.nifi.provenance.ProvenanceRepository;
|
||||
import org.apache.nifi.provenance.StandardProvenanceEventRecord;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.MutableVariableRegistry;
|
||||
import org.apache.nifi.registry.variable.StandardComponentVariableRegistry;
|
||||
import org.apache.nifi.remote.HttpRemoteSiteListener;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
import org.apache.nifi.remote.RemoteResourceManager;
|
||||
|
@ -495,15 +498,15 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
processScheduler = new StandardProcessScheduler(this, encryptor, stateManagerProvider, this.variableRegistry, this.nifiProperties);
|
||||
processScheduler = new StandardProcessScheduler(this, encryptor, stateManagerProvider, this.nifiProperties);
|
||||
eventDrivenWorkerQueue = new EventDrivenWorkerQueue(false, false, processScheduler);
|
||||
|
||||
final ProcessContextFactory contextFactory = new ProcessContextFactory(contentRepository, flowFileRepository, flowFileEventRepository, counterRepositoryRef.get(), provenanceRepository);
|
||||
processScheduler.setSchedulingAgent(SchedulingStrategy.EVENT_DRIVEN, new EventDrivenSchedulingAgent(
|
||||
eventDrivenEngineRef.get(), this, stateManagerProvider, eventDrivenWorkerQueue, contextFactory, maxEventDrivenThreads.get(), encryptor, this.variableRegistry));
|
||||
eventDrivenEngineRef.get(), this, stateManagerProvider, eventDrivenWorkerQueue, contextFactory, maxEventDrivenThreads.get(), encryptor));
|
||||
|
||||
final QuartzSchedulingAgent quartzSchedulingAgent = new QuartzSchedulingAgent(this, timerDrivenEngineRef.get(), contextFactory, encryptor, this.variableRegistry);
|
||||
final TimerDrivenSchedulingAgent timerDrivenAgent = new TimerDrivenSchedulingAgent(this, timerDrivenEngineRef.get(), contextFactory, encryptor, this.variableRegistry, this.nifiProperties);
|
||||
final QuartzSchedulingAgent quartzSchedulingAgent = new QuartzSchedulingAgent(this, timerDrivenEngineRef.get(), contextFactory, encryptor);
|
||||
final TimerDrivenSchedulingAgent timerDrivenAgent = new TimerDrivenSchedulingAgent(this, timerDrivenEngineRef.get(), contextFactory, encryptor, this.nifiProperties);
|
||||
processScheduler.setSchedulingAgent(SchedulingStrategy.TIMER_DRIVEN, timerDrivenAgent);
|
||||
// PRIMARY_NODE_ONLY is deprecated, but still exists to handle processors that are still defined with it (they haven't been re-configured with executeNode = PRIMARY).
|
||||
processScheduler.setSchedulingAgent(SchedulingStrategy.PRIMARY_NODE_ONLY, timerDrivenAgent);
|
||||
|
@ -540,7 +543,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
this.snippetManager = new SnippetManager();
|
||||
|
||||
final ProcessGroup rootGroup = new StandardProcessGroup(ComponentIdGenerator.generateId().toString(), this, processScheduler,
|
||||
nifiProperties, encryptor, this, this.variableRegistry);
|
||||
nifiProperties, encryptor, this, new MutableVariableRegistry(this.variableRegistry));
|
||||
rootGroup.setName(DEFAULT_ROOT_GROUP_NAME);
|
||||
setRootGroup(rootGroup);
|
||||
instanceId = ComponentIdGenerator.generateId().toString();
|
||||
|
@ -1022,7 +1025,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
* @throws NullPointerException if the argument is null
|
||||
*/
|
||||
public ProcessGroup createProcessGroup(final String id) {
|
||||
return new StandardProcessGroup(requireNonNull(id).intern(), this, processScheduler, nifiProperties, encryptor, this, variableRegistry);
|
||||
return new StandardProcessGroup(requireNonNull(id).intern(), this, processScheduler, nifiProperties, encryptor, this, new MutableVariableRegistry(variableRegistry));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1099,15 +1102,17 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
creationSuccessful = false;
|
||||
}
|
||||
|
||||
final ValidationContextFactory validationContextFactory = new StandardValidationContextFactory(controllerServiceProvider, variableRegistry);
|
||||
final ComponentVariableRegistry componentVarRegistry = new StandardComponentVariableRegistry(this.variableRegistry);
|
||||
final ValidationContextFactory validationContextFactory = new StandardValidationContextFactory(controllerServiceProvider, componentVarRegistry);
|
||||
final ProcessorNode procNode;
|
||||
if (creationSuccessful) {
|
||||
procNode = new StandardProcessorNode(processor, id, validationContextFactory, processScheduler, controllerServiceProvider, nifiProperties, variableRegistry, this);
|
||||
procNode = new StandardProcessorNode(processor, id, validationContextFactory, processScheduler, controllerServiceProvider,
|
||||
nifiProperties, componentVarRegistry, this);
|
||||
} else {
|
||||
final String simpleClassName = type.contains(".") ? StringUtils.substringAfterLast(type, ".") : type;
|
||||
final String componentType = "(Missing) " + simpleClassName;
|
||||
procNode = new StandardProcessorNode(
|
||||
processor, id, validationContextFactory, processScheduler, controllerServiceProvider, componentType, type, nifiProperties, variableRegistry, this, true);
|
||||
procNode = new StandardProcessorNode(processor, id, validationContextFactory, processScheduler, controllerServiceProvider,
|
||||
componentType, type, nifiProperties, componentVarRegistry, this, true);
|
||||
}
|
||||
|
||||
final LogRepository logRepository = LogRepositoryFactory.getRepository(id);
|
||||
|
@ -1223,7 +1228,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
// call OnRemoved for the existing processor using the previous instance class loader
|
||||
try (final NarCloseable x = NarCloseable.withComponentNarLoader(existingInstanceClassLoader)) {
|
||||
final StandardProcessContext processContext = new StandardProcessContext(
|
||||
existingNode, controllerServiceProvider, encryptor, getStateManagerProvider().getStateManager(id), variableRegistry);
|
||||
existingNode, controllerServiceProvider, encryptor, getStateManagerProvider().getStateManager(id));
|
||||
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnRemoved.class, existingNode.getProcessor(), processContext);
|
||||
} finally {
|
||||
ExtensionManager.closeURLClassLoader(id, existingInstanceClassLoader);
|
||||
|
@ -1943,6 +1948,10 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
childGroup.setPosition(toPosition(groupDTO.getPosition()));
|
||||
childGroup.setComments(groupDTO.getComments());
|
||||
childGroup.setName(groupDTO.getName());
|
||||
if (groupDTO.getVariables() != null) {
|
||||
childGroup.setVariables(groupDTO.getVariables());
|
||||
}
|
||||
|
||||
group.addProcessGroup(childGroup);
|
||||
|
||||
final FlowSnippetDTO contents = groupDTO.getContents();
|
||||
|
@ -3124,15 +3133,16 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
creationSuccessful = false;
|
||||
}
|
||||
|
||||
final ValidationContextFactory validationContextFactory = new StandardValidationContextFactory(controllerServiceProvider, variableRegistry);
|
||||
final ComponentVariableRegistry componentVarRegistry = new StandardComponentVariableRegistry(this.variableRegistry);
|
||||
final ValidationContextFactory validationContextFactory = new StandardValidationContextFactory(controllerServiceProvider, componentVarRegistry);
|
||||
final ReportingTaskNode taskNode;
|
||||
if (creationSuccessful) {
|
||||
taskNode = new StandardReportingTaskNode(task, id, this, processScheduler, validationContextFactory, variableRegistry, this);
|
||||
taskNode = new StandardReportingTaskNode(task, id, this, processScheduler, validationContextFactory, componentVarRegistry, this);
|
||||
} else {
|
||||
final String simpleClassName = type.contains(".") ? StringUtils.substringAfterLast(type, ".") : type;
|
||||
final String componentType = "(Missing) " + simpleClassName;
|
||||
|
||||
taskNode = new StandardReportingTaskNode(task, id, this, processScheduler, validationContextFactory, componentType, type, variableRegistry, this, true);
|
||||
taskNode = new StandardReportingTaskNode(task, id, this, processScheduler, validationContextFactory, componentType, type, componentVarRegistry, this, true);
|
||||
}
|
||||
|
||||
taskNode.setName(taskNode.getReportingTask().getClass().getSimpleName());
|
||||
|
@ -3395,7 +3405,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> enableControllerService(final ControllerServiceNode serviceNode) {
|
||||
public CompletableFuture<Void> enableControllerService(final ControllerServiceNode serviceNode) {
|
||||
return controllerServiceProvider.enableControllerService(serviceNode);
|
||||
}
|
||||
|
||||
|
@ -3405,9 +3415,9 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
|
|||
}
|
||||
|
||||
@Override
|
||||
public void disableControllerService(final ControllerServiceNode serviceNode) {
|
||||
public CompletableFuture<Void> disableControllerService(final ControllerServiceNode serviceNode) {
|
||||
serviceNode.verifyCanDisable();
|
||||
controllerServiceProvider.disableControllerService(serviceNode);
|
||||
return controllerServiceProvider.disableControllerService(serviceNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,6 +16,34 @@
|
|||
*/
|
||||
package org.apache.nifi.controller;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
|
@ -92,33 +120,6 @@ import org.w3c.dom.Node;
|
|||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class StandardFlowSynchronizer implements FlowSynchronizer {
|
||||
|
@ -1037,6 +1038,21 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
|
|||
parentGroup.addProcessGroup(processGroup);
|
||||
}
|
||||
|
||||
// Set the variables for the variable registry
|
||||
final Map<String, String> variables = new HashMap<>();
|
||||
final List<Element> variableElements = getChildrenByTagName(processGroupElement, "variable");
|
||||
for (final Element variableElement : variableElements) {
|
||||
final String variableName = variableElement.getAttribute("name");
|
||||
final String variableValue = variableElement.getAttribute("value");
|
||||
if (variableName == null || variableValue == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
variables.put(variableName, variableValue);
|
||||
}
|
||||
|
||||
processGroup.setVariables(variables);
|
||||
|
||||
// Add Controller Services
|
||||
final List<Element> serviceNodeList = getChildrenByTagName(processGroupElement, "controllerService");
|
||||
if (!serviceNodeList.isEmpty()) {
|
||||
|
|
|
@ -16,6 +16,31 @@
|
|||
*/
|
||||
package org.apache.nifi.controller;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
|
||||
|
@ -56,7 +81,7 @@ import org.apache.nifi.processor.ProcessSessionFactory;
|
|||
import org.apache.nifi.processor.Processor;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.scheduling.ExecutionNode;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
|
@ -68,30 +93,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
/**
|
||||
* ProcessorNode provides thread-safe access to a FlowFileProcessor as it exists
|
||||
* within a controlled flow. This node keeps track of the processor, its
|
||||
|
@ -137,7 +138,7 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||
public StandardProcessorNode(final LoggableComponent<Processor> processor, final String uuid,
|
||||
final ValidationContextFactory validationContextFactory, final ProcessScheduler scheduler,
|
||||
final ControllerServiceProvider controllerServiceProvider, final NiFiProperties nifiProperties,
|
||||
final VariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
final ComponentVariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
|
||||
this(processor, uuid, validationContextFactory, scheduler, controllerServiceProvider,
|
||||
processor.getComponent().getClass().getSimpleName(), processor.getComponent().getClass().getCanonicalName(), nifiProperties, variableRegistry, reloadComponent, false);
|
||||
|
@ -147,7 +148,7 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||
final ValidationContextFactory validationContextFactory, final ProcessScheduler scheduler,
|
||||
final ControllerServiceProvider controllerServiceProvider,
|
||||
final String componentType, final String componentCanonicalClass, final NiFiProperties nifiProperties,
|
||||
final VariableRegistry variableRegistry, final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
final ComponentVariableRegistry variableRegistry, final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
|
||||
super(uuid, validationContextFactory, controllerServiceProvider, componentType, componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
|
||||
|
||||
|
@ -1372,13 +1373,13 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public <T extends ProcessContext & ControllerServiceLookup> void stop(final ScheduledExecutorService scheduler,
|
||||
public <T extends ProcessContext & ControllerServiceLookup> CompletableFuture<Void> stop(final ScheduledExecutorService scheduler,
|
||||
final T processContext, final SchedulingAgent schedulingAgent, final ScheduleState scheduleState) {
|
||||
|
||||
final Processor processor = processorRef.get().getProcessor();
|
||||
LOG.info("Stopping processor: " + processor.getClass());
|
||||
|
||||
|
||||
final CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
if (this.scheduledState.compareAndSet(ScheduledState.RUNNING, ScheduledState.STOPPING)) { // will ensure that the Processor represented by this node can only be stopped once
|
||||
scheduleState.incrementActiveThreadCount();
|
||||
|
||||
|
@ -1405,6 +1406,7 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||
|
||||
scheduleState.decrementActiveThreadCount();
|
||||
scheduledState.set(ScheduledState.STOPPED);
|
||||
future.complete(null);
|
||||
} else {
|
||||
// Not all of the active threads have finished. Try again in 100 milliseconds.
|
||||
scheduler.schedule(this, 100, TimeUnit.MILLISECONDS);
|
||||
|
@ -1415,16 +1417,17 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
|
|||
}
|
||||
});
|
||||
} else {
|
||||
/*
|
||||
* We do compareAndSet() instead of set() to ensure that Processor
|
||||
* stoppage is handled consistently including a condition where
|
||||
* Processor never got a chance to transition to RUNNING state
|
||||
* before stop() was called. If that happens the stop processor
|
||||
* routine will be initiated in start() method, otherwise the IF
|
||||
* part will handle the stop processor routine.
|
||||
*/
|
||||
// We do compareAndSet() instead of set() to ensure that Processor
|
||||
// stoppage is handled consistently including a condition where
|
||||
// Processor never got a chance to transition to RUNNING state
|
||||
// before stop() was called. If that happens the stop processor
|
||||
// routine will be initiated in start() method, otherwise the IF
|
||||
// part will handle the stop processor routine.
|
||||
this.scheduledState.compareAndSet(ScheduledState.STARTING, ScheduledState.STOPPING);
|
||||
future.complete(null);
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,14 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.reporting;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.nifi.annotation.configuration.DefaultSchedule;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
|
@ -33,7 +41,7 @@ import org.apache.nifi.controller.service.ControllerServiceNode;
|
|||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
import org.apache.nifi.controller.service.StandardConfigurationContext;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.reporting.ReportingTask;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
|
@ -42,14 +50,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public abstract class AbstractReportingTaskNode extends AbstractConfiguredComponent implements ReportingTaskNode {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractReportingTaskNode.class);
|
||||
|
@ -66,7 +66,7 @@ public abstract class AbstractReportingTaskNode extends AbstractConfiguredCompon
|
|||
|
||||
public AbstractReportingTaskNode(final LoggableComponent<ReportingTask> reportingTask, final String id,
|
||||
final ControllerServiceProvider controllerServiceProvider, final ProcessScheduler processScheduler,
|
||||
final ValidationContextFactory validationContextFactory, final VariableRegistry variableRegistry,
|
||||
final ValidationContextFactory validationContextFactory, final ComponentVariableRegistry variableRegistry,
|
||||
final ReloadComponent reloadComponent) {
|
||||
|
||||
this(reportingTask, id, controllerServiceProvider, processScheduler, validationContextFactory,
|
||||
|
@ -77,7 +77,7 @@ public abstract class AbstractReportingTaskNode extends AbstractConfiguredCompon
|
|||
|
||||
public AbstractReportingTaskNode(final LoggableComponent<ReportingTask> reportingTask, final String id, final ControllerServiceProvider controllerServiceProvider,
|
||||
final ProcessScheduler processScheduler, final ValidationContextFactory validationContextFactory,
|
||||
final String componentType, final String componentCanonicalClass, final VariableRegistry variableRegistry,
|
||||
final String componentType, final String componentCanonicalClass, final ComponentVariableRegistry variableRegistry,
|
||||
final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
|
||||
super(id, validationContextFactory, controllerServiceProvider, componentType, componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
|
||||
|
|
|
@ -22,13 +22,13 @@ import org.apache.nifi.authorization.Resource;
|
|||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.authorization.resource.ResourceType;
|
||||
import org.apache.nifi.controller.ReloadComponent;
|
||||
import org.apache.nifi.controller.FlowController;
|
||||
import org.apache.nifi.controller.LoggableComponent;
|
||||
import org.apache.nifi.controller.ProcessScheduler;
|
||||
import org.apache.nifi.controller.ReloadComponent;
|
||||
import org.apache.nifi.controller.ReportingTaskNode;
|
||||
import org.apache.nifi.controller.ValidationContextFactory;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.reporting.ReportingContext;
|
||||
import org.apache.nifi.reporting.ReportingTask;
|
||||
|
||||
|
@ -38,14 +38,14 @@ public class StandardReportingTaskNode extends AbstractReportingTaskNode impleme
|
|||
|
||||
public StandardReportingTaskNode(final LoggableComponent<ReportingTask> reportingTask, final String id, final FlowController controller,
|
||||
final ProcessScheduler processScheduler, final ValidationContextFactory validationContextFactory,
|
||||
final VariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
final ComponentVariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
super(reportingTask, id, controller, processScheduler, validationContextFactory, variableRegistry, reloadComponent);
|
||||
this.flowController = controller;
|
||||
}
|
||||
|
||||
public StandardReportingTaskNode(final LoggableComponent<ReportingTask> reportingTask, final String id, final FlowController controller,
|
||||
final ProcessScheduler processScheduler, final ValidationContextFactory validationContextFactory,
|
||||
final String componentType, final String canonicalClassName, final VariableRegistry variableRegistry,
|
||||
final String componentType, final String canonicalClassName, final ComponentVariableRegistry variableRegistry,
|
||||
final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
super(reportingTask, id, controller, processScheduler, validationContextFactory, componentType, canonicalClassName,
|
||||
variableRegistry, reloadComponent, isExtensionMissing);
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.apache.nifi.processor.ProcessSessionFactory;
|
|||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.Connectables;
|
||||
import org.apache.nifi.util.FormatUtils;
|
||||
import org.apache.nifi.util.ReflectionUtils;
|
||||
|
@ -62,7 +61,6 @@ public class EventDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
private final ProcessContextFactory contextFactory;
|
||||
private final AtomicInteger maxThreadCount;
|
||||
private final StringEncryptor encryptor;
|
||||
private final VariableRegistry variableRegistry;
|
||||
|
||||
private volatile String adminYieldDuration = "1 sec";
|
||||
|
||||
|
@ -70,8 +68,7 @@ public class EventDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
private final ConcurrentMap<Connectable, ScheduleState> scheduleStates = new ConcurrentHashMap<>();
|
||||
|
||||
public EventDrivenSchedulingAgent(final FlowEngine flowEngine, final ControllerServiceProvider serviceProvider, final StateManagerProvider stateManagerProvider,
|
||||
final EventDrivenWorkerQueue workerQueue, final ProcessContextFactory contextFactory, final int maxThreadCount, final StringEncryptor encryptor,
|
||||
final VariableRegistry variableRegistry) {
|
||||
final EventDrivenWorkerQueue workerQueue, final ProcessContextFactory contextFactory, final int maxThreadCount, final StringEncryptor encryptor) {
|
||||
super(flowEngine);
|
||||
this.serviceProvider = serviceProvider;
|
||||
this.stateManagerProvider = stateManagerProvider;
|
||||
|
@ -79,7 +76,6 @@ public class EventDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
this.contextFactory = contextFactory;
|
||||
this.maxThreadCount = new AtomicInteger(maxThreadCount);
|
||||
this.encryptor = encryptor;
|
||||
this.variableRegistry = variableRegistry;
|
||||
|
||||
for (int i = 0; i < maxThreadCount; i++) {
|
||||
final Runnable eventDrivenTask = new EventDrivenTask(workerQueue);
|
||||
|
@ -188,8 +184,7 @@ public class EventDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
|
||||
if (connectable instanceof ProcessorNode) {
|
||||
final ProcessorNode procNode = (ProcessorNode) connectable;
|
||||
final StandardProcessContext standardProcessContext = new StandardProcessContext(procNode, serviceProvider,
|
||||
encryptor, getStateManager(connectable.getIdentifier()), variableRegistry);
|
||||
final StandardProcessContext standardProcessContext = new StandardProcessContext(procNode, serviceProvider, encryptor, getStateManager(connectable.getIdentifier()));
|
||||
|
||||
final long runNanos = procNode.getRunDuration(TimeUnit.NANOSECONDS);
|
||||
final ProcessSessionFactory sessionFactory;
|
||||
|
|
|
@ -38,7 +38,6 @@ import org.apache.nifi.encrypt.StringEncryptor;
|
|||
import org.apache.nifi.engine.FlowEngine;
|
||||
import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.FormatUtils;
|
||||
import org.quartz.CronExpression;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -51,18 +50,15 @@ public class QuartzSchedulingAgent extends AbstractSchedulingAgent {
|
|||
private final FlowController flowController;
|
||||
private final ProcessContextFactory contextFactory;
|
||||
private final StringEncryptor encryptor;
|
||||
private final VariableRegistry variableRegistry;
|
||||
|
||||
private volatile String adminYieldDuration = "1 sec";
|
||||
private final Map<Object, List<AtomicBoolean>> canceledTriggers = new HashMap<>();
|
||||
|
||||
public QuartzSchedulingAgent(final FlowController flowController, final FlowEngine flowEngine, final ProcessContextFactory contextFactory, final StringEncryptor enryptor,
|
||||
final VariableRegistry variableRegistry) {
|
||||
public QuartzSchedulingAgent(final FlowController flowController, final FlowEngine flowEngine, final ProcessContextFactory contextFactory, final StringEncryptor enryptor) {
|
||||
super(flowEngine);
|
||||
this.flowController = flowController;
|
||||
this.contextFactory = contextFactory;
|
||||
this.encryptor = enryptor;
|
||||
this.variableRegistry = variableRegistry;
|
||||
}
|
||||
|
||||
private StateManager getStateManager(final String componentId) {
|
||||
|
@ -145,7 +141,7 @@ public class QuartzSchedulingAgent extends AbstractSchedulingAgent {
|
|||
if (connectable.getConnectableType() == ConnectableType.PROCESSOR) {
|
||||
final ProcessorNode procNode = (ProcessorNode) connectable;
|
||||
|
||||
final StandardProcessContext standardProcContext = new StandardProcessContext(procNode, flowController, encryptor, getStateManager(connectable.getIdentifier()), variableRegistry);
|
||||
final StandardProcessContext standardProcContext = new StandardProcessContext(procNode, flowController, encryptor, getStateManager(connectable.getIdentifier()));
|
||||
ContinuallyRunProcessorTask runnableTask = new ContinuallyRunProcessorTask(this, procNode, flowController, contextFactory, scheduleState, standardProcContext);
|
||||
continuallyRunTask = runnableTask;
|
||||
} else {
|
||||
|
|
|
@ -53,7 +53,6 @@ import org.apache.nifi.nar.NarCloseable;
|
|||
import org.apache.nifi.processor.Processor;
|
||||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.reporting.ReportingTask;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
import org.apache.nifi.util.FormatUtils;
|
||||
|
@ -84,19 +83,16 @@ public final class StandardProcessScheduler implements ProcessScheduler {
|
|||
private final ScheduledExecutorService componentMonitoringThreadPool = new FlowEngine(8, "StandardProcessScheduler", true);
|
||||
|
||||
private final StringEncryptor encryptor;
|
||||
private final VariableRegistry variableRegistry;
|
||||
|
||||
public StandardProcessScheduler(
|
||||
final ControllerServiceProvider controllerServiceProvider,
|
||||
final StringEncryptor encryptor,
|
||||
final StateManagerProvider stateManagerProvider,
|
||||
final VariableRegistry variableRegistry,
|
||||
final NiFiProperties nifiProperties
|
||||
) {
|
||||
this.controllerServiceProvider = controllerServiceProvider;
|
||||
this.encryptor = encryptor;
|
||||
this.stateManagerProvider = stateManagerProvider;
|
||||
this.variableRegistry = variableRegistry;
|
||||
|
||||
administrativeYieldDuration = nifiProperties.getAdministrativeYieldDuration();
|
||||
administrativeYieldMillis = FormatUtils.getTimeDuration(administrativeYieldDuration, TimeUnit.MILLISECONDS);
|
||||
|
@ -301,15 +297,17 @@ public final class StandardProcessScheduler implements ProcessScheduler {
|
|||
* @see StandardProcessorNode#start(ScheduledExecutorService, long, org.apache.nifi.processor.ProcessContext, Runnable).
|
||||
*/
|
||||
@Override
|
||||
public synchronized void startProcessor(final ProcessorNode procNode) {
|
||||
public synchronized CompletableFuture<Void> startProcessor(final ProcessorNode procNode) {
|
||||
StandardProcessContext processContext = new StandardProcessContext(procNode, this.controllerServiceProvider,
|
||||
this.encryptor, getStateManager(procNode.getIdentifier()), variableRegistry);
|
||||
this.encryptor, getStateManager(procNode.getIdentifier()));
|
||||
final ScheduleState scheduleState = getScheduleState(requireNonNull(procNode));
|
||||
|
||||
final CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
SchedulingAgentCallback callback = new SchedulingAgentCallback() {
|
||||
@Override
|
||||
public void trigger() {
|
||||
getSchedulingAgent(procNode).schedule(procNode, scheduleState);
|
||||
future.complete(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -324,7 +322,9 @@ public final class StandardProcessScheduler implements ProcessScheduler {
|
|||
}
|
||||
};
|
||||
|
||||
LOG.info("Starting {}", procNode);
|
||||
procNode.start(this.componentLifeCycleThreadPool, this.administrativeYieldMillis, processContext, callback);
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -335,12 +335,13 @@ public final class StandardProcessScheduler implements ProcessScheduler {
|
|||
* @see StandardProcessorNode#stop(ScheduledExecutorService, org.apache.nifi.processor.ProcessContext, SchedulingAgent, ScheduleState)
|
||||
*/
|
||||
@Override
|
||||
public synchronized void stopProcessor(final ProcessorNode procNode) {
|
||||
public synchronized CompletableFuture<Void> stopProcessor(final ProcessorNode procNode) {
|
||||
StandardProcessContext processContext = new StandardProcessContext(procNode, this.controllerServiceProvider,
|
||||
this.encryptor, getStateManager(procNode.getIdentifier()), variableRegistry);
|
||||
this.encryptor, getStateManager(procNode.getIdentifier()));
|
||||
final ScheduleState state = getScheduleState(procNode);
|
||||
|
||||
procNode.stop(this.componentLifeCycleThreadPool, processContext, getSchedulingAgent(procNode), state);
|
||||
LOG.info("Stopping {}", procNode);
|
||||
return procNode.stop(this.componentLifeCycleThreadPool, processContext, getSchedulingAgent(procNode), state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -537,20 +538,35 @@ public final class StandardProcessScheduler implements ProcessScheduler {
|
|||
|
||||
@Override
|
||||
public CompletableFuture<Void> enableControllerService(final ControllerServiceNode service) {
|
||||
LOG.info("Enabling " + service);
|
||||
return service.enable(this.componentLifeCycleThreadPool, this.administrativeYieldMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableControllerService(final ControllerServiceNode service) {
|
||||
service.disable(this.componentLifeCycleThreadPool);
|
||||
public CompletableFuture<Void> disableControllerService(final ControllerServiceNode service) {
|
||||
LOG.info("Disabling {}", service);
|
||||
return service.disable(this.componentLifeCycleThreadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableControllerServices(final List<ControllerServiceNode> services) {
|
||||
public CompletableFuture<Void> disableControllerServices(final List<ControllerServiceNode> services) {
|
||||
if (services == null || services.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> future = null;
|
||||
if (!requireNonNull(services).isEmpty()) {
|
||||
for (ControllerServiceNode controllerServiceNode : services) {
|
||||
this.disableControllerService(controllerServiceNode);
|
||||
final CompletableFuture<Void> serviceFuture = this.disableControllerService(controllerServiceNode);
|
||||
|
||||
if (future == null) {
|
||||
future = serviceFuture;
|
||||
} else {
|
||||
future = CompletableFuture.allOf(future, serviceFuture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.apache.nifi.engine.FlowEngine;
|
|||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.FormatUtils;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -51,7 +50,6 @@ public class TimerDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
private final FlowController flowController;
|
||||
private final ProcessContextFactory contextFactory;
|
||||
private final StringEncryptor encryptor;
|
||||
private final VariableRegistry variableRegistry;
|
||||
|
||||
private volatile String adminYieldDuration = "1 sec";
|
||||
|
||||
|
@ -60,13 +58,11 @@ public class TimerDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
final FlowEngine flowEngine,
|
||||
final ProcessContextFactory contextFactory,
|
||||
final StringEncryptor encryptor,
|
||||
final VariableRegistry variableRegistry,
|
||||
final NiFiProperties nifiProperties) {
|
||||
super(flowEngine);
|
||||
this.flowController = flowController;
|
||||
this.contextFactory = contextFactory;
|
||||
this.encryptor = encryptor;
|
||||
this.variableRegistry = variableRegistry;
|
||||
|
||||
final String boredYieldDuration = nifiProperties.getBoredYieldDuration();
|
||||
try {
|
||||
|
@ -109,7 +105,7 @@ public class TimerDrivenSchedulingAgent extends AbstractSchedulingAgent {
|
|||
// Determine the task to run and create it.
|
||||
if (connectable.getConnectableType() == ConnectableType.PROCESSOR) {
|
||||
final ProcessorNode procNode = (ProcessorNode) connectable;
|
||||
final StandardProcessContext standardProcContext = new StandardProcessContext(procNode, flowController, encryptor, getStateManager(connectable.getIdentifier()), variableRegistry);
|
||||
final StandardProcessContext standardProcContext = new StandardProcessContext(procNode, flowController, encryptor, getStateManager(connectable.getIdentifier()));
|
||||
final ContinuallyRunProcessorTask runnableTask = new ContinuallyRunProcessorTask(this, procNode, flowController,
|
||||
contextFactory, scheduleState, standardProcContext);
|
||||
|
||||
|
|
|
@ -144,6 +144,16 @@ public class FlowFromDOMFactory {
|
|||
dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
|
||||
dto.setComments(getString(element, "comment"));
|
||||
|
||||
final Map<String, String> variables = new HashMap<>();
|
||||
final NodeList variableList = DomUtils.getChildNodesByTagName(element, "variable");
|
||||
for (int i = 0; i < variableList.getLength(); i++) {
|
||||
final Element variableElement = (Element) variableList.item(i);
|
||||
final String name = variableElement.getAttribute("name");
|
||||
final String value = variableElement.getAttribute("value");
|
||||
variables.put(name, value);
|
||||
}
|
||||
dto.setVariables(variables);
|
||||
|
||||
final Set<ProcessorDTO> processors = new HashSet<>();
|
||||
final Set<ConnectionDTO> connections = new HashSet<>();
|
||||
final Set<FunnelDTO> funnels = new HashSet<>();
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.apache.nifi.groups.ProcessGroup;
|
|||
import org.apache.nifi.groups.RemoteProcessGroup;
|
||||
import org.apache.nifi.persistence.TemplateSerializer;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
import org.apache.nifi.remote.RootGroupPort;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
|
@ -70,7 +72,7 @@ import java.util.concurrent.TimeUnit;
|
|||
*/
|
||||
public class StandardFlowSerializer implements FlowSerializer {
|
||||
|
||||
private static final String MAX_ENCODING_VERSION = "1.1";
|
||||
private static final String MAX_ENCODING_VERSION = "1.2";
|
||||
|
||||
private final StringEncryptor encryptor;
|
||||
|
||||
|
@ -202,6 +204,18 @@ public class StandardFlowSerializer implements FlowSerializer {
|
|||
for (final Template template : group.getTemplates()) {
|
||||
addTemplate(element, template);
|
||||
}
|
||||
|
||||
final VariableRegistry variableRegistry = group.getVariableRegistry();
|
||||
for (final Map.Entry<VariableDescriptor, String> entry : variableRegistry.getVariableMap().entrySet()) {
|
||||
addVariable(element, entry.getKey().getName(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static void addVariable(final Element parentElement, final String variableName, final String variableValue) {
|
||||
final Element variableElement = parentElement.getOwnerDocument().createElement("variable");
|
||||
variableElement.setAttribute("name", variableName);
|
||||
variableElement.setAttribute("value", variableValue);
|
||||
parentElement.appendChild(variableElement);
|
||||
}
|
||||
|
||||
private static void addBundle(final Element parentElement, final BundleCoordinate coordinate) {
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.controller.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ServiceStateTransition {
|
||||
private ControllerServiceState state = ControllerServiceState.DISABLED;
|
||||
private final List<CompletableFuture<?>> enabledFutures = new ArrayList<>();
|
||||
private final List<CompletableFuture<?>> disabledFutures = new ArrayList<>();
|
||||
|
||||
|
||||
public synchronized boolean transitionToEnabling(final ControllerServiceState expectedState, final CompletableFuture<?> enabledFuture) {
|
||||
if (expectedState != state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = ControllerServiceState.ENABLING;
|
||||
enabledFutures.add(enabledFuture);
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean enable() {
|
||||
if (state != ControllerServiceState.ENABLING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = ControllerServiceState.ENABLED;
|
||||
enabledFutures.stream().forEach(future -> future.complete(null));
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean transitionToDisabling(final ControllerServiceState expectedState, final CompletableFuture<?> disabledFuture) {
|
||||
if (expectedState != state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = ControllerServiceState.DISABLING;
|
||||
disabledFutures.add(disabledFuture);
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void disable() {
|
||||
state = ControllerServiceState.DISABLED;
|
||||
disabledFutures.stream().forEach(future -> future.complete(null));
|
||||
}
|
||||
|
||||
public synchronized ControllerServiceState getState() {
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -16,37 +16,6 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.service;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.documentation.DeprecationNotice;
|
||||
import org.apache.nifi.annotation.lifecycle.OnDisabled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnEnabled;
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.authorization.resource.ResourceType;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.AbstractConfiguredComponent;
|
||||
import org.apache.nifi.controller.ReloadComponent;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
import org.apache.nifi.controller.ControllerService;
|
||||
import org.apache.nifi.controller.LoggableComponent;
|
||||
import org.apache.nifi.controller.ValidationContextFactory;
|
||||
import org.apache.nifi.controller.exception.ControllerServiceInstantiationException;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
import org.apache.nifi.util.ReflectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
|
@ -65,13 +34,44 @@ import java.util.concurrent.locks.Lock;
|
|||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.annotation.behavior.Restricted;
|
||||
import org.apache.nifi.annotation.documentation.DeprecationNotice;
|
||||
import org.apache.nifi.annotation.lifecycle.OnDisabled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnEnabled;
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.authorization.resource.ResourceType;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.ValidationResult;
|
||||
import org.apache.nifi.controller.AbstractConfiguredComponent;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
import org.apache.nifi.controller.ControllerService;
|
||||
import org.apache.nifi.controller.LoggableComponent;
|
||||
import org.apache.nifi.controller.ReloadComponent;
|
||||
import org.apache.nifi.controller.ValidationContextFactory;
|
||||
import org.apache.nifi.controller.exception.ControllerServiceInstantiationException;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.logging.ComponentLog;
|
||||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.util.CharacterFilterUtils;
|
||||
import org.apache.nifi.util.ReflectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StandardControllerServiceNode extends AbstractConfiguredComponent implements ControllerServiceNode {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StandardControllerServiceNode.class);
|
||||
|
||||
private final AtomicReference<ControllerServiceDetails> controllerServiceHolder = new AtomicReference<>(null);
|
||||
private final ControllerServiceProvider serviceProvider;
|
||||
private final AtomicReference<ControllerServiceState> stateRef = new AtomicReference<>(ControllerServiceState.DISABLED);
|
||||
private final ServiceStateTransition stateTransition = new ServiceStateTransition();
|
||||
|
||||
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = rwLock.readLock();
|
||||
|
@ -85,7 +85,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
|
||||
public StandardControllerServiceNode(final LoggableComponent<ControllerService> implementation, final LoggableComponent<ControllerService> proxiedControllerService,
|
||||
final ControllerServiceInvocationHandler invocationHandler, final String id, final ValidationContextFactory validationContextFactory,
|
||||
final ControllerServiceProvider serviceProvider, final VariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
final ControllerServiceProvider serviceProvider, final ComponentVariableRegistry variableRegistry, final ReloadComponent reloadComponent) {
|
||||
|
||||
this(implementation, proxiedControllerService, invocationHandler, id, validationContextFactory, serviceProvider,
|
||||
implementation.getComponent().getClass().getSimpleName(), implementation.getComponent().getClass().getCanonicalName(), variableRegistry, reloadComponent, false);
|
||||
|
@ -94,7 +94,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
public StandardControllerServiceNode(final LoggableComponent<ControllerService> implementation, final LoggableComponent<ControllerService> proxiedControllerService,
|
||||
final ControllerServiceInvocationHandler invocationHandler, final String id, final ValidationContextFactory validationContextFactory,
|
||||
final ControllerServiceProvider serviceProvider, final String componentType, final String componentCanonicalClass,
|
||||
final VariableRegistry variableRegistry, final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
final ComponentVariableRegistry variableRegistry, final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
|
||||
|
||||
super(id, validationContextFactory, serviceProvider, componentType, componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
@ -363,7 +363,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
|
||||
@Override
|
||||
public ControllerServiceState getState() {
|
||||
return stateRef.get();
|
||||
return stateTransition.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -394,7 +394,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
public CompletableFuture<Void> enable(final ScheduledExecutorService scheduler, final long administrativeYieldMillis) {
|
||||
final CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
|
||||
if (this.stateRef.compareAndSet(ControllerServiceState.DISABLED, ControllerServiceState.ENABLING)) {
|
||||
if (this.stateTransition.transitionToEnabling(ControllerServiceState.DISABLED, future)) {
|
||||
synchronized (active) {
|
||||
this.active.set(true);
|
||||
}
|
||||
|
@ -410,17 +410,15 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
|
||||
boolean shouldEnable = false;
|
||||
synchronized (active) {
|
||||
shouldEnable = active.get() && stateRef.compareAndSet(ControllerServiceState.ENABLING, ControllerServiceState.ENABLED);
|
||||
shouldEnable = active.get() && stateTransition.enable();
|
||||
}
|
||||
|
||||
future.complete(null);
|
||||
|
||||
if (!shouldEnable) {
|
||||
LOG.debug("Disabling service " + this + " after it has been enabled due to disable action being initiated.");
|
||||
// Can only happen if user initiated DISABLE operation before service finished enabling. It's state will be
|
||||
// set to DISABLING (see disable() operation)
|
||||
invokeDisable(configContext);
|
||||
stateRef.set(ControllerServiceState.DISABLED);
|
||||
stateTransition.disable();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
future.completeExceptionally(e);
|
||||
|
@ -437,7 +435,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
try (final NarCloseable nc = NarCloseable.withComponentNarLoader(getControllerServiceImplementation().getClass(), getIdentifier())) {
|
||||
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnDisabled.class, getControllerServiceImplementation(), configContext);
|
||||
}
|
||||
stateRef.set(ControllerServiceState.DISABLED);
|
||||
stateTransition.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -464,7 +462,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
* DISABLED state.
|
||||
*/
|
||||
@Override
|
||||
public void disable(ScheduledExecutorService scheduler) {
|
||||
public CompletableFuture<Void> disable(ScheduledExecutorService scheduler) {
|
||||
/*
|
||||
* The reason for synchronization is to ensure consistency of the
|
||||
* service state when another thread is in the middle of enabling this
|
||||
|
@ -475,7 +473,8 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
this.active.set(false);
|
||||
}
|
||||
|
||||
if (this.stateRef.compareAndSet(ControllerServiceState.ENABLED, ControllerServiceState.DISABLING)) {
|
||||
final CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
if (this.stateTransition.transitionToDisabling(ControllerServiceState.ENABLED, future)) {
|
||||
final ConfigurationContext configContext = new StandardConfigurationContext(this, this.serviceProvider, null, getVariableRegistry());
|
||||
scheduler.execute(new Runnable() {
|
||||
@Override
|
||||
|
@ -483,13 +482,15 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
try {
|
||||
invokeDisable(configContext);
|
||||
} finally {
|
||||
stateRef.set(ControllerServiceState.DISABLED);
|
||||
stateTransition.disable();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.stateRef.compareAndSet(ControllerServiceState.ENABLING, ControllerServiceState.DISABLING);
|
||||
this.stateTransition.transitionToDisabling(ControllerServiceState.ENABLING, future);
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -515,7 +516,7 @@ public class StandardControllerServiceNode extends AbstractConfiguredComponent i
|
|||
@Override
|
||||
public Collection<ValidationResult> getValidationErrors(Set<String> serviceIdentifiersNotToValidate) {
|
||||
Collection<ValidationResult> results = null;
|
||||
if (stateRef.get() == ControllerServiceState.DISABLED) {
|
||||
if (getState() == ControllerServiceState.DISABLED) {
|
||||
results = super.getValidationErrors(serviceIdentifiersNotToValidate);
|
||||
}
|
||||
return results != null ? results : Collections.emptySet();
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -62,7 +63,9 @@ import org.apache.nifi.nar.ExtensionManager;
|
|||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.processor.SimpleProcessLogger;
|
||||
import org.apache.nifi.processor.StandardValidationContextFactory;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.StandardComponentVariableRegistry;
|
||||
import org.apache.nifi.reporting.BulletinRepository;
|
||||
import org.apache.nifi.reporting.Severity;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
@ -148,8 +151,9 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
final LoggableComponent<ControllerService> originalLoggableComponent = new LoggableComponent<>(originalService, bundleCoordinate, serviceLogger);
|
||||
final LoggableComponent<ControllerService> proxiedLoggableComponent = new LoggableComponent<>(proxiedService, bundleCoordinate, serviceLogger);
|
||||
|
||||
final ComponentVariableRegistry componentVarRegistry = new StandardComponentVariableRegistry(this.variableRegistry);
|
||||
final ControllerServiceNode serviceNode = new StandardControllerServiceNode(originalLoggableComponent, proxiedLoggableComponent, invocationHandler,
|
||||
id, validationContextFactory, this, variableRegistry, flowController);
|
||||
id, validationContextFactory, this, componentVarRegistry, flowController);
|
||||
serviceNode.setName(rawClass.getSimpleName());
|
||||
|
||||
invocationHandler.setServiceNode(serviceNode);
|
||||
|
@ -226,8 +230,9 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
|
||||
final LoggableComponent<ControllerService> proxiedLoggableComponent = new LoggableComponent<>(proxiedService, bundleCoordinate, null);
|
||||
|
||||
final ComponentVariableRegistry componentVarRegistry = new StandardComponentVariableRegistry(this.variableRegistry);
|
||||
final ControllerServiceNode serviceNode = new StandardControllerServiceNode(proxiedLoggableComponent, proxiedLoggableComponent, invocationHandler, id,
|
||||
new StandardValidationContextFactory(this, variableRegistry), this, componentType, type, variableRegistry, flowController, true);
|
||||
new StandardValidationContextFactory(this, variableRegistry), this, componentType, type, componentVarRegistry, flowController, true);
|
||||
|
||||
serviceCache.putIfAbsent(id, serviceNode);
|
||||
return serviceNode;
|
||||
|
@ -235,9 +240,8 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
|
||||
@Override
|
||||
public Set<ConfiguredComponent> disableReferencingServices(final ControllerServiceNode serviceNode) {
|
||||
// Get a list of all Controller Services that need to be disabled, in the order that they need to be
|
||||
// disabled.
|
||||
final List<ControllerServiceNode> toDisable = findRecursiveReferences(serviceNode, ControllerServiceNode.class);
|
||||
// Get a list of all Controller Services that need to be disabled, in the order that they need to be disabled.
|
||||
final List<ControllerServiceNode> toDisable = serviceNode.getReferences().findRecursiveReferences(ControllerServiceNode.class);
|
||||
|
||||
final Set<ControllerServiceNode> serviceSet = new HashSet<>(toDisable);
|
||||
|
||||
|
@ -258,8 +262,8 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
public Set<ConfiguredComponent> scheduleReferencingComponents(final ControllerServiceNode serviceNode) {
|
||||
// find all of the schedulable components (processors, reporting tasks) that refer to this Controller Service,
|
||||
// or a service that references this controller service, etc.
|
||||
final List<ProcessorNode> processors = findRecursiveReferences(serviceNode, ProcessorNode.class);
|
||||
final List<ReportingTaskNode> reportingTasks = findRecursiveReferences(serviceNode, ReportingTaskNode.class);
|
||||
final List<ProcessorNode> processors = serviceNode.getReferences().findRecursiveReferences(ProcessorNode.class);
|
||||
final List<ReportingTaskNode> reportingTasks = serviceNode.getReferences().findRecursiveReferences(ReportingTaskNode.class);
|
||||
|
||||
final Set<ConfiguredComponent> updated = new HashSet<>();
|
||||
|
||||
|
@ -298,8 +302,8 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
public Set<ConfiguredComponent> unscheduleReferencingComponents(final ControllerServiceNode serviceNode) {
|
||||
// find all of the schedulable components (processors, reporting tasks) that refer to this Controller Service,
|
||||
// or a service that references this controller service, etc.
|
||||
final List<ProcessorNode> processors = findRecursiveReferences(serviceNode, ProcessorNode.class);
|
||||
final List<ReportingTaskNode> reportingTasks = findRecursiveReferences(serviceNode, ReportingTaskNode.class);
|
||||
final List<ProcessorNode> processors = serviceNode.getReferences().findRecursiveReferences(ProcessorNode.class);
|
||||
final List<ReportingTaskNode> reportingTasks = serviceNode.getReferences().findRecursiveReferences(ReportingTaskNode.class);
|
||||
|
||||
final Set<ConfiguredComponent> updated = new HashSet<>();
|
||||
|
||||
|
@ -333,7 +337,7 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> enableControllerService(final ControllerServiceNode serviceNode) {
|
||||
public CompletableFuture<Void> enableControllerService(final ControllerServiceNode serviceNode) {
|
||||
serviceNode.verifyCanEnable();
|
||||
return processScheduler.enableControllerService(serviceNode);
|
||||
}
|
||||
|
@ -450,9 +454,9 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
}
|
||||
|
||||
@Override
|
||||
public void disableControllerService(final ControllerServiceNode serviceNode) {
|
||||
public CompletableFuture<Void> disableControllerService(final ControllerServiceNode serviceNode) {
|
||||
serviceNode.verifyCanDisable();
|
||||
processScheduler.disableControllerService(serviceNode);
|
||||
return processScheduler.disableControllerService(serviceNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -589,43 +593,10 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
return allServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of all components that reference the given referencedNode
|
||||
* (either directly or indirectly through another service) that are also of
|
||||
* the given componentType. The list that is returned is in the order in
|
||||
* which they will need to be 'activated' (enabled/started).
|
||||
*
|
||||
* @param referencedNode node
|
||||
* @param componentType type
|
||||
* @return list of components
|
||||
*/
|
||||
private <T> List<T> findRecursiveReferences(final ControllerServiceNode referencedNode, final Class<T> componentType) {
|
||||
final List<T> references = new ArrayList<>();
|
||||
|
||||
for (final ConfiguredComponent referencingComponent : referencedNode.getReferences().getReferencingComponents()) {
|
||||
if (componentType.isAssignableFrom(referencingComponent.getClass())) {
|
||||
references.add(componentType.cast(referencingComponent));
|
||||
}
|
||||
|
||||
if (referencingComponent instanceof ControllerServiceNode) {
|
||||
final ControllerServiceNode referencingNode = (ControllerServiceNode) referencingComponent;
|
||||
|
||||
// find components recursively that depend on referencingNode.
|
||||
final List<T> recursive = findRecursiveReferences(referencingNode, componentType);
|
||||
|
||||
// For anything that depends on referencing node, we want to add it to the list, but we know
|
||||
// that it must come after the referencing node, so we first remove any existing occurrence.
|
||||
references.removeAll(recursive);
|
||||
references.addAll(recursive);
|
||||
}
|
||||
}
|
||||
|
||||
return references;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfiguredComponent> enableReferencingServices(final ControllerServiceNode serviceNode) {
|
||||
final List<ControllerServiceNode> recursiveReferences = findRecursiveReferences(serviceNode, ControllerServiceNode.class);
|
||||
final List<ControllerServiceNode> recursiveReferences = serviceNode.getReferences().findRecursiveReferences(ControllerServiceNode.class);
|
||||
logger.debug("Enabling the following Referencing Services for {}: {}", serviceNode, recursiveReferences);
|
||||
return enableReferencingServices(serviceNode, recursiveReferences);
|
||||
}
|
||||
|
@ -658,7 +629,7 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
|
||||
@Override
|
||||
public void verifyCanEnableReferencingServices(final ControllerServiceNode serviceNode) {
|
||||
final List<ControllerServiceNode> referencingServices = findRecursiveReferences(serviceNode, ControllerServiceNode.class);
|
||||
final List<ControllerServiceNode> referencingServices = serviceNode.getReferences().findRecursiveReferences(ControllerServiceNode.class);
|
||||
final Set<ControllerServiceNode> referencingServiceSet = new HashSet<>(referencingServices);
|
||||
|
||||
for (final ControllerServiceNode referencingService : referencingServices) {
|
||||
|
@ -668,9 +639,9 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
|
||||
@Override
|
||||
public void verifyCanScheduleReferencingComponents(final ControllerServiceNode serviceNode) {
|
||||
final List<ControllerServiceNode> referencingServices = findRecursiveReferences(serviceNode, ControllerServiceNode.class);
|
||||
final List<ReportingTaskNode> referencingReportingTasks = findRecursiveReferences(serviceNode, ReportingTaskNode.class);
|
||||
final List<ProcessorNode> referencingProcessors = findRecursiveReferences(serviceNode, ProcessorNode.class);
|
||||
final List<ControllerServiceNode> referencingServices = serviceNode.getReferences().findRecursiveReferences(ControllerServiceNode.class);
|
||||
final List<ReportingTaskNode> referencingReportingTasks = serviceNode.getReferences().findRecursiveReferences(ReportingTaskNode.class);
|
||||
final List<ProcessorNode> referencingProcessors = serviceNode.getReferences().findRecursiveReferences(ProcessorNode.class);
|
||||
|
||||
final Set<ControllerServiceNode> referencingServiceSet = new HashSet<>(referencingServices);
|
||||
|
||||
|
@ -689,9 +660,8 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
|
|||
|
||||
@Override
|
||||
public void verifyCanDisableReferencingServices(final ControllerServiceNode serviceNode) {
|
||||
// Get a list of all Controller Services that need to be disabled, in the order that they need to be
|
||||
// disabled.
|
||||
final List<ControllerServiceNode> toDisable = findRecursiveReferences(serviceNode, ControllerServiceNode.class);
|
||||
// Get a list of all Controller Services that need to be disabled, in the order that they need to be disabled.
|
||||
final List<ControllerServiceNode> toDisable = serviceNode.getReferences().findRecursiveReferences(ControllerServiceNode.class);
|
||||
final Set<ControllerServiceNode> serviceSet = new HashSet<>(toDisable);
|
||||
|
||||
for (final ControllerServiceNode nodeToDisable : toDisable) {
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
|
@ -101,4 +103,35 @@ public class StandardControllerServiceReference implements ControllerServiceRefe
|
|||
|
||||
return references;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> List<T> findRecursiveReferences(final Class<T> componentType) {
|
||||
return findRecursiveReferences(referenced, componentType);
|
||||
}
|
||||
|
||||
private <T> List<T> findRecursiveReferences(final ControllerServiceNode referencedNode, final Class<T> componentType) {
|
||||
final List<T> references = new ArrayList<>();
|
||||
|
||||
for (final ConfiguredComponent referencingComponent : referencedNode.getReferences().getReferencingComponents()) {
|
||||
if (componentType.isAssignableFrom(referencingComponent.getClass())) {
|
||||
references.add(componentType.cast(referencingComponent));
|
||||
}
|
||||
|
||||
if (referencingComponent instanceof ControllerServiceNode) {
|
||||
final ControllerServiceNode referencingNode = (ControllerServiceNode) referencingComponent;
|
||||
|
||||
// find components recursively that depend on referencingNode.
|
||||
final List<T> recursive = findRecursiveReferences(referencingNode, componentType);
|
||||
|
||||
// For anything that depends on referencing node, we want to add it to the list, but we know
|
||||
// that it must come after the referencing node, so we first remove any existing occurrence.
|
||||
references.removeAll(recursive);
|
||||
references.addAll(recursive);
|
||||
}
|
||||
}
|
||||
|
||||
return references;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,24 @@
|
|||
*/
|
||||
package org.apache.nifi.fingerprint;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
import org.apache.nifi.components.ConfigurableComponent;
|
||||
|
@ -38,23 +56,6 @@ import org.w3c.dom.Node;
|
|||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* <p>Creates a fingerprint of a flow.xml. The order of elements or attributes in the flow.xml does not influence the fingerprint generation.
|
||||
*
|
||||
|
@ -324,9 +325,22 @@ public class FingerprintFactory {
|
|||
addFunnelFingerprint(builder, funnelElem);
|
||||
}
|
||||
|
||||
// add variables
|
||||
final NodeList variableElems = DomUtils.getChildNodesByTagName(processGroupElem, "variable");
|
||||
final List<Element> sortedVarList = sortElements(variableElems, getVariableNameComparator());
|
||||
for (final Element varElem : sortedVarList) {
|
||||
addVariableFingerprint(builder, varElem);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void addVariableFingerprint(final StringBuilder builder, final Element variableElement) {
|
||||
final String variableName = variableElement.getAttribute("name");
|
||||
final String variableValue = variableElement.getAttribute("value");
|
||||
builder.append(variableName).append("=").append(variableValue);
|
||||
}
|
||||
|
||||
private StringBuilder addFlowFileProcessorFingerprint(final StringBuilder builder, final Element processorElem) throws FingerprintException {
|
||||
// id
|
||||
appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "id"));
|
||||
|
@ -662,6 +676,27 @@ public class FingerprintFactory {
|
|||
};
|
||||
}
|
||||
|
||||
private Comparator<Element> getVariableNameComparator() {
|
||||
return new Comparator<Element>() {
|
||||
@Override
|
||||
public int compare(final Element e1, final Element e2) {
|
||||
if (e1 == null && e2 == null) {
|
||||
return 0;
|
||||
}
|
||||
if (e1 == null) {
|
||||
return 1;
|
||||
}
|
||||
if (e2 == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final String varName1 = e1.getAttribute("name");
|
||||
final String varName2 = e2.getAttribute("name");
|
||||
return varName1.compareTo(varName2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Comparator<Element> getProcessorPropertiesComparator() {
|
||||
return new Comparator<Element>() {
|
||||
@Override
|
||||
|
|
|
@ -16,13 +16,31 @@
|
|||
*/
|
||||
package org.apache.nifi.groups;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.apache.nifi.annotation.lifecycle.OnRemoved;
|
||||
import org.apache.nifi.annotation.lifecycle.OnShutdown;
|
||||
import org.apache.nifi.attribute.expression.language.Query;
|
||||
import org.apache.nifi.attribute.expression.language.VariableImpact;
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
|
@ -39,6 +57,7 @@ import org.apache.nifi.connectable.Port;
|
|||
import org.apache.nifi.connectable.Position;
|
||||
import org.apache.nifi.connectable.Positionable;
|
||||
import org.apache.nifi.controller.ConfigurationContext;
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
import org.apache.nifi.controller.ControllerService;
|
||||
import org.apache.nifi.controller.FlowController;
|
||||
import org.apache.nifi.controller.ProcessorNode;
|
||||
|
@ -50,13 +69,15 @@ import org.apache.nifi.controller.label.Label;
|
|||
import org.apache.nifi.controller.scheduling.StandardProcessScheduler;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
import org.apache.nifi.controller.service.ControllerServiceReference;
|
||||
import org.apache.nifi.controller.service.StandardConfigurationContext;
|
||||
import org.apache.nifi.encrypt.StringEncryptor;
|
||||
import org.apache.nifi.logging.LogRepositoryFactory;
|
||||
import org.apache.nifi.nar.ExtensionManager;
|
||||
import org.apache.nifi.nar.NarCloseable;
|
||||
import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.variable.MutableVariableRegistry;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
import org.apache.nifi.remote.RootGroupPort;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
@ -66,20 +87,7 @@ import org.apache.nifi.web.api.dto.TemplateDTO;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
public final class StandardProcessGroup implements ProcessGroup {
|
||||
|
||||
|
@ -104,7 +112,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
private final Map<String, ControllerServiceNode> controllerServices = new HashMap<>();
|
||||
private final Map<String, Template> templates = new HashMap<>();
|
||||
private final StringEncryptor encryptor;
|
||||
private final VariableRegistry variableRegistry;
|
||||
private final MutableVariableRegistry variableRegistry;
|
||||
|
||||
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = rwLock.readLock();
|
||||
|
@ -114,7 +122,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
|
||||
public StandardProcessGroup(final String id, final ControllerServiceProvider serviceProvider, final StandardProcessScheduler scheduler,
|
||||
final NiFiProperties nifiProps, final StringEncryptor encryptor, final FlowController flowController,
|
||||
final VariableRegistry variableRegistry) {
|
||||
final MutableVariableRegistry variableRegistry) {
|
||||
this.id = id;
|
||||
this.controllerServiceProvider = serviceProvider;
|
||||
this.parent = new AtomicReference<>();
|
||||
|
@ -361,7 +369,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
private void shutdown(final ProcessGroup procGroup) {
|
||||
for (final ProcessorNode node : procGroup.getProcessors()) {
|
||||
try (final NarCloseable x = NarCloseable.withComponentNarLoader(node.getProcessor().getClass(), node.getIdentifier())) {
|
||||
final StandardProcessContext processContext = new StandardProcessContext(node, controllerServiceProvider, encryptor, getStateManager(node.getIdentifier()), variableRegistry);
|
||||
final StandardProcessContext processContext = new StandardProcessContext(node, controllerServiceProvider, encryptor, getStateManager(node.getIdentifier()));
|
||||
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnShutdown.class, node.getProcessor(), processContext);
|
||||
}
|
||||
}
|
||||
|
@ -548,6 +556,8 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
writeLock.lock();
|
||||
try {
|
||||
group.setParent(this);
|
||||
group.getVariableRegistry().setParent(getVariableRegistry());
|
||||
|
||||
processGroups.put(Objects.requireNonNull(group).getIdentifier(), group);
|
||||
flowController.onProcessGroupAdded(group);
|
||||
} finally {
|
||||
|
@ -709,6 +719,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
processor.setProcessGroup(this);
|
||||
processor.getVariableRegistry().setParent(getVariableRegistry());
|
||||
processors.put(processorId, processor);
|
||||
flowController.onProcessorAdded(processor);
|
||||
} finally {
|
||||
|
@ -732,7 +743,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
try (final NarCloseable x = NarCloseable.withComponentNarLoader(processor.getProcessor().getClass(), processor.getIdentifier())) {
|
||||
final StandardProcessContext processContext = new StandardProcessContext(processor, controllerServiceProvider, encryptor, getStateManager(processor.getIdentifier()), variableRegistry);
|
||||
final StandardProcessContext processContext = new StandardProcessContext(processor, controllerServiceProvider, encryptor, getStateManager(processor.getIdentifier()));
|
||||
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnRemoved.class, processor.getProcessor(), processContext);
|
||||
} catch (final Exception e) {
|
||||
throw new ComponentLifeCycleException("Failed to invoke 'OnRemoved' methods of processor with id " + processor.getIdentifier(), e);
|
||||
|
@ -1081,7 +1092,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void startProcessor(final ProcessorNode processor) {
|
||||
public CompletableFuture<Void> startProcessor(final ProcessorNode processor) {
|
||||
readLock.lock();
|
||||
try {
|
||||
if (getProcessor(processor.getIdentifier()) == null) {
|
||||
|
@ -1092,10 +1103,10 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
if (state == ScheduledState.DISABLED) {
|
||||
throw new IllegalStateException("Processor is disabled");
|
||||
} else if (state == ScheduledState.RUNNING) {
|
||||
return;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
scheduler.startProcessor(processor);
|
||||
return scheduler.startProcessor(processor);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
|
@ -1162,7 +1173,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void stopProcessor(final ProcessorNode processor) {
|
||||
public CompletableFuture<Void> stopProcessor(final ProcessorNode processor) {
|
||||
readLock.lock();
|
||||
try {
|
||||
if (!processors.containsKey(processor.getIdentifier())) {
|
||||
|
@ -1173,10 +1184,10 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
if (state == ScheduledState.DISABLED) {
|
||||
throw new IllegalStateException("Processor is disabled");
|
||||
} else if (state == ScheduledState.STOPPED) {
|
||||
return;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
scheduler.stopProcessor(processor);
|
||||
return scheduler.stopProcessor(processor);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
|
@ -1854,6 +1865,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
service.setProcessGroup(this);
|
||||
service.getVariableRegistry().setParent(getVariableRegistry());
|
||||
this.controllerServices.put(service.getIdentifier(), service);
|
||||
LOG.info("{} added to {}", service, this);
|
||||
} finally {
|
||||
|
@ -2583,4 +2595,129 @@ public final class StandardProcessGroup implements ProcessGroup {
|
|||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableVariableRegistry getVariableRegistry() {
|
||||
return variableRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyCanUpdateVariables(final Map<String, String> updatedVariables) {
|
||||
if (updatedVariables == null || updatedVariables.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
final Set<String> updatedVariableNames = getUpdatedVariables(updatedVariables);
|
||||
if (updatedVariableNames.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final ProcessorNode processor : findAllProcessors()) {
|
||||
if (!processor.isRunning()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final String variableName : updatedVariableNames) {
|
||||
for (final VariableImpact impact : getVariableImpact(processor)) {
|
||||
if (impact.isImpacted(variableName)) {
|
||||
throw new IllegalStateException("Cannot update variable '" + variableName + "' because it is referenced by " + processor + ", which is currently running");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final ControllerServiceNode service : findAllControllerServices()) {
|
||||
if (!service.isActive()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final String variableName : updatedVariableNames) {
|
||||
for (final VariableImpact impact : getVariableImpact(service)) {
|
||||
if (impact.isImpacted(variableName)) {
|
||||
throw new IllegalStateException("Cannot update variable '" + variableName + "' because it is referenced by " + service + ", which is currently running");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfiguredComponent> getComponentsAffectedByVariable(final String variableName) {
|
||||
final Set<ConfiguredComponent> affected = new HashSet<>();
|
||||
|
||||
// Determine any Processors that references the variable
|
||||
for (final ProcessorNode processor : findAllProcessors()) {
|
||||
for (final VariableImpact impact : getVariableImpact(processor)) {
|
||||
if (impact.isImpacted(variableName)) {
|
||||
affected.add(processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine any Controller Service that references the variable. If Service A references a variable,
|
||||
// then that means that any other component that references that service is also affected, so recursively
|
||||
// find any references to that service and add it.
|
||||
for (final ControllerServiceNode service : findAllControllerServices()) {
|
||||
for (final VariableImpact impact : getVariableImpact(service)) {
|
||||
if (impact.isImpacted(variableName)) {
|
||||
affected.add(service);
|
||||
|
||||
final ControllerServiceReference reference = service.getReferences();
|
||||
affected.addAll(reference.findRecursiveReferences(ConfiguredComponent.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affected;
|
||||
}
|
||||
|
||||
|
||||
private Set<String> getUpdatedVariables(final Map<String, String> newVariableValues) {
|
||||
final Set<String> updatedVariableNames = new HashSet<>();
|
||||
|
||||
final MutableVariableRegistry registry = getVariableRegistry();
|
||||
for (final Map.Entry<String, String> entry : newVariableValues.entrySet()) {
|
||||
final String varName = entry.getKey();
|
||||
final String newValue = entry.getValue();
|
||||
|
||||
final String curValue = registry.getVariableValue(varName);
|
||||
if (!Objects.equals(newValue, curValue)) {
|
||||
updatedVariableNames.add(varName);
|
||||
}
|
||||
}
|
||||
|
||||
return updatedVariableNames;
|
||||
}
|
||||
|
||||
private List<VariableImpact> getVariableImpact(final ConfiguredComponent component) {
|
||||
return component.getProperties().values().stream()
|
||||
.map(propVal -> Query.prepare(propVal).getVariableImpact())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVariables(final Map<String, String> variables) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
verifyCanUpdateVariables(variables);
|
||||
|
||||
if (variables == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<VariableDescriptor, String> variableMap = new HashMap<>();
|
||||
variables.entrySet().stream() // cannot use Collectors.toMap because value may be null
|
||||
.forEach(entry -> variableMap.put(new VariableDescriptor(entry.getKey()), entry.getValue()));
|
||||
|
||||
variableRegistry.setVariables(variableMap);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import java.util.Set;
|
|||
|
||||
import org.apache.nifi.attribute.expression.language.PreparedQuery;
|
||||
import org.apache.nifi.attribute.expression.language.Query;
|
||||
import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
|
||||
import org.apache.nifi.attribute.expression.language.Query.Range;
|
||||
import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.components.PropertyValue;
|
||||
import org.apache.nifi.components.state.StateManager;
|
||||
|
@ -37,7 +37,6 @@ import org.apache.nifi.controller.ControllerServiceLookup;
|
|||
import org.apache.nifi.controller.ProcessorNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
import org.apache.nifi.encrypt.StringEncryptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.Connectables;
|
||||
|
||||
public class StandardProcessContext implements ProcessContext, ControllerServiceLookup {
|
||||
|
@ -47,15 +46,12 @@ public class StandardProcessContext implements ProcessContext, ControllerService
|
|||
private final Map<PropertyDescriptor, PreparedQuery> preparedQueries;
|
||||
private final StringEncryptor encryptor;
|
||||
private final StateManager stateManager;
|
||||
private final VariableRegistry variableRegistry;
|
||||
|
||||
public StandardProcessContext(final ProcessorNode processorNode, final ControllerServiceProvider controllerServiceProvider, final StringEncryptor encryptor, final StateManager stateManager,
|
||||
final VariableRegistry variableRegistry) {
|
||||
public StandardProcessContext(final ProcessorNode processorNode, final ControllerServiceProvider controllerServiceProvider, final StringEncryptor encryptor, final StateManager stateManager) {
|
||||
this.procNode = processorNode;
|
||||
this.controllerServiceProvider = controllerServiceProvider;
|
||||
this.encryptor = encryptor;
|
||||
this.stateManager = stateManager;
|
||||
this.variableRegistry = variableRegistry;
|
||||
|
||||
preparedQueries = new HashMap<>();
|
||||
for (final Map.Entry<PropertyDescriptor, String> entry : procNode.getProperties().entrySet()) {
|
||||
|
@ -93,12 +89,12 @@ public class StandardProcessContext implements ProcessContext, ControllerService
|
|||
final String setPropertyValue = procNode.getProperty(descriptor);
|
||||
final String propValue = (setPropertyValue == null) ? descriptor.getDefaultValue() : setPropertyValue;
|
||||
|
||||
return new StandardPropertyValue(propValue, this, preparedQueries.get(descriptor), variableRegistry);
|
||||
return new StandardPropertyValue(propValue, this, preparedQueries.get(descriptor), procNode.getVariableRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyValue newPropertyValue(final String rawValue) {
|
||||
return new StandardPropertyValue(rawValue, this, Query.prepare(rawValue), variableRegistry);
|
||||
return new StandardPropertyValue(rawValue, this, Query.prepare(rawValue), procNode.getVariableRegistry());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -53,8 +53,8 @@ public class StandardValidationContext implements ValidationContext {
|
|||
private final String componentId;
|
||||
|
||||
public StandardValidationContext(final ControllerServiceProvider controllerServiceProvider, final Map<PropertyDescriptor, String> properties,
|
||||
final String annotationData, final String groupId, final String componentId, VariableRegistry variableRegistry) {
|
||||
this(controllerServiceProvider, Collections.<String> emptySet(), properties, annotationData, groupId, componentId,variableRegistry);
|
||||
final String annotationData, final String groupId, final String componentId, final VariableRegistry variableRegistry) {
|
||||
this(controllerServiceProvider, Collections.<String> emptySet(), properties, annotationData, groupId, componentId, variableRegistry);
|
||||
}
|
||||
|
||||
public StandardValidationContext(
|
||||
|
@ -63,7 +63,8 @@ public class StandardValidationContext implements ValidationContext {
|
|||
final Map<PropertyDescriptor, String> properties,
|
||||
final String annotationData,
|
||||
final String groupId,
|
||||
final String componentId, VariableRegistry variableRegistry) {
|
||||
final String componentId,
|
||||
final VariableRegistry variableRegistry) {
|
||||
this.controllerServiceProvider = controllerServiceProvider;
|
||||
this.properties = new HashMap<>(properties);
|
||||
this.annotationData = annotationData;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.util;
|
||||
package org.apache.nifi.registry.variable;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -76,13 +76,14 @@ public class FileBasedVariableRegistry implements VariableRegistry {
|
|||
} catch (final IOException ioe) {
|
||||
LOG.error("Unable to complete variable registry loading from files due to ", ioe);
|
||||
}
|
||||
|
||||
LOG.info("Loaded a total of {} properties. Including precedence overrides effective accessible registry key size is {}", totalPropertiesLoaded, newMap.size());
|
||||
map = newMap;
|
||||
map = Collections.unmodifiableMap(newMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<VariableDescriptor, String> getVariableMap() {
|
||||
return Collections.unmodifiableMap(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.registry.variable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
|
||||
public class MutableVariableRegistry extends StandardComponentVariableRegistry implements VariableRegistry {
|
||||
private volatile Map<VariableDescriptor, String> variableMap = new HashMap<>();
|
||||
|
||||
public MutableVariableRegistry(final VariableRegistry parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<VariableDescriptor, String> getVariableMap() {
|
||||
return variableMap;
|
||||
}
|
||||
|
||||
public void setVariables(final Map<VariableDescriptor, String> variables) {
|
||||
final Map<VariableDescriptor, String> curVariableMap = this.variableMap;
|
||||
final Map<VariableDescriptor, String> updatedVariableMap = new HashMap<>(curVariableMap);
|
||||
for (final Map.Entry<VariableDescriptor, String> entry : variables.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
updatedVariableMap.remove(entry.getKey());
|
||||
} else {
|
||||
updatedVariableMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
this.variableMap = Collections.unmodifiableMap(updatedVariableMap);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.registry.variable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
|
||||
public class StandardComponentVariableRegistry implements ComponentVariableRegistry {
|
||||
private volatile VariableRegistry parent;
|
||||
|
||||
public StandardComponentVariableRegistry(final VariableRegistry parent) {
|
||||
this.parent = Objects.requireNonNull(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<VariableDescriptor, String> getVariableMap() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableRegistry getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(final VariableRegistry parentRegistry) {
|
||||
this.parent = parentRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableDescriptor getVariableKey(final String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final VariableDescriptor spec = new VariableDescriptor(name);
|
||||
for (final Map.Entry<VariableDescriptor, String> entry : getVariableMap().entrySet()) {
|
||||
if (entry.getKey().equals(spec)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVariableValue(final String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final VariableDescriptor descriptor = new VariableDescriptor(name);
|
||||
final String value = getVariableMap().get(descriptor);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return parent.getVariableValue(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVariableValue(final VariableDescriptor descriptor) {
|
||||
if (descriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String value = getVariableMap().get(descriptor);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return parent.getVariableValue(descriptor);
|
||||
}
|
||||
}
|
|
@ -147,9 +147,15 @@
|
|||
<xs:element name="connection" type="ConnectionType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="controllerService" type="ControllerServiceType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="template" type="TemplateType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="variable" type="VariableType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VariableType">
|
||||
<xs:attribute name="name" />
|
||||
<xs:attribute name="value" />
|
||||
</xs:complexType>
|
||||
|
||||
<!-- Same as ProcessGroupType except that instead of input ports & output ports being of type PortType,
|
||||
they are of type RootGroupPortType -->
|
||||
<xs:complexType name="RootProcessGroupType">
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</bean>
|
||||
|
||||
<!-- variable registry -->
|
||||
<bean id="variableRegistry" class="org.apache.nifi.util.FileBasedVariableRegistry">
|
||||
<bean id="variableRegistry" class="org.apache.nifi.registry.variable.FileBasedVariableRegistry">
|
||||
<constructor-arg type="java.nio.file.Path[]" value="#{nifiProperties.getVariableRegistryPropertiesPaths()}" />
|
||||
</bean>
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.apache.nifi.controller.serialization.StandardFlowSerializer;
|
|||
import org.apache.nifi.encrypt.StringEncryptor;
|
||||
import org.apache.nifi.events.VolatileBulletinRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.api.dto.ConnectableDTO;
|
||||
import org.apache.nifi.web.api.dto.ConnectionDTO;
|
||||
|
|
|
@ -49,9 +49,9 @@ import org.apache.nifi.nar.SystemBundle;
|
|||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.reporting.BulletinRepository;
|
||||
import org.apache.nifi.scheduling.SchedulingStrategy;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.api.dto.BundleDTO;
|
||||
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
|
||||
|
|
|
@ -17,6 +17,26 @@
|
|||
|
||||
package org.apache.nifi.controller;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.apache.nifi.annotation.lifecycle.OnScheduled;
|
||||
import org.apache.nifi.annotation.lifecycle.OnStopped;
|
||||
import org.apache.nifi.annotation.lifecycle.OnUnscheduled;
|
||||
|
@ -46,6 +66,7 @@ import org.apache.nifi.processor.exception.ProcessException;
|
|||
import org.apache.nifi.processor.util.StandardValidators;
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.StandardComponentVariableRegistry;
|
||||
import org.apache.nifi.test.processors.ModifiesClasspathNoAnnotationProcessor;
|
||||
import org.apache.nifi.test.processors.ModifiesClasspathProcessor;
|
||||
import org.apache.nifi.util.MockPropertyValue;
|
||||
|
@ -56,26 +77,6 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class TestStandardProcessorNode {
|
||||
|
||||
private MockVariableRegistry variableRegistry;
|
||||
|
@ -98,10 +99,10 @@ public class TestStandardProcessorNode {
|
|||
|
||||
final LoggableComponent<Processor> loggableComponent = new LoggableComponent<>(processor, coordinate, null);
|
||||
final StandardProcessorNode procNode = new StandardProcessorNode(loggableComponent, uuid, createValidationContextFactory(), null, null,
|
||||
NiFiProperties.createBasicNiFiProperties(null, null), VariableRegistry.EMPTY_REGISTRY, reloadComponent);
|
||||
NiFiProperties.createBasicNiFiProperties(null, null), new StandardComponentVariableRegistry(VariableRegistry.EMPTY_REGISTRY), reloadComponent);
|
||||
final ScheduledExecutorService taskScheduler = new FlowEngine(2, "TestClasspathResources", true);
|
||||
|
||||
final StandardProcessContext processContext = new StandardProcessContext(procNode, null, null, null, null);
|
||||
final StandardProcessContext processContext = new StandardProcessContext(procNode, null, null, null);
|
||||
final SchedulingAgentCallback schedulingAgentCallback = new SchedulingAgentCallback() {
|
||||
@Override
|
||||
public void postMonitor() {
|
||||
|
@ -414,7 +415,8 @@ public class TestStandardProcessorNode {
|
|||
processor.initialize(initContext);
|
||||
|
||||
final LoggableComponent<Processor> loggableComponent = new LoggableComponent<>(processor, systemBundle.getBundleDetails().getCoordinate(), componentLog);
|
||||
return new StandardProcessorNode(loggableComponent, uuid, validationContextFactory, processScheduler, null, niFiProperties, variableRegistry, reloadComponent);
|
||||
return new StandardProcessorNode(loggableComponent, uuid, validationContextFactory, processScheduler,
|
||||
null, niFiProperties, new StandardComponentVariableRegistry(variableRegistry), reloadComponent);
|
||||
}
|
||||
|
||||
private static class MockReloadComponent implements ReloadComponent {
|
||||
|
|
|
@ -16,15 +16,6 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.reporting;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.nifi.admin.service.AuditService;
|
||||
import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
|
||||
|
@ -45,14 +36,23 @@ import org.apache.nifi.nar.ExtensionManager;
|
|||
import org.apache.nifi.nar.SystemBundle;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.reporting.BulletinRepository;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestStandardReportingContext {
|
||||
|
||||
private FlowController controller;
|
||||
|
|
|
@ -46,7 +46,7 @@ import org.apache.nifi.processor.ProcessSession;
|
|||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
|
|
@ -74,6 +74,7 @@ import org.apache.nifi.processor.StandardProcessorInitializationContext;
|
|||
import org.apache.nifi.processor.StandardValidationContextFactory;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.StandardComponentVariableRegistry;
|
||||
import org.apache.nifi.reporting.AbstractReportingTask;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.reporting.ReportingContext;
|
||||
|
@ -110,7 +111,7 @@ public class TestStandardProcessScheduler {
|
|||
systemBundle = SystemBundle.create(nifiProperties);
|
||||
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
|
||||
|
||||
scheduler = new StandardProcessScheduler(Mockito.mock(ControllerServiceProvider.class), null, stateMgrProvider, variableRegistry, nifiProperties);
|
||||
scheduler = new StandardProcessScheduler(Mockito.mock(ControllerServiceProvider.class), null, stateMgrProvider, nifiProperties);
|
||||
scheduler.setSchedulingAgent(SchedulingStrategy.TIMER_DRIVEN, Mockito.mock(SchedulingAgent.class));
|
||||
|
||||
reportingTask = new TestReportingTask();
|
||||
|
@ -122,7 +123,8 @@ public class TestStandardProcessScheduler {
|
|||
final ComponentLog logger = Mockito.mock(ComponentLog.class);
|
||||
final ReloadComponent reloadComponent = Mockito.mock(ReloadComponent.class);
|
||||
final LoggableComponent<ReportingTask> loggableComponent = new LoggableComponent<>(reportingTask, systemBundle.getBundleDetails().getCoordinate(), logger);
|
||||
taskNode = new StandardReportingTaskNode(loggableComponent, UUID.randomUUID().toString(), null, scheduler, validationContextFactory, variableRegistry, reloadComponent);
|
||||
taskNode = new StandardReportingTaskNode(loggableComponent, UUID.randomUUID().toString(), null, scheduler, validationContextFactory,
|
||||
new StandardComponentVariableRegistry(variableRegistry), reloadComponent);
|
||||
|
||||
controller = Mockito.mock(FlowController.class);
|
||||
|
||||
|
@ -196,7 +198,7 @@ public class TestStandardProcessScheduler {
|
|||
final LoggableComponent<Processor> loggableComponent = new LoggableComponent<>(proc, systemBundle.getBundleDetails().getCoordinate(), null);
|
||||
final ProcessorNode procNode = new StandardProcessorNode(loggableComponent, uuid,
|
||||
new StandardValidationContextFactory(serviceProvider, variableRegistry),
|
||||
scheduler, serviceProvider, nifiProperties, VariableRegistry.EMPTY_REGISTRY, reloadComponent);
|
||||
scheduler, serviceProvider, nifiProperties, new StandardComponentVariableRegistry(VariableRegistry.EMPTY_REGISTRY), reloadComponent);
|
||||
rootGroup.addProcessor(procNode);
|
||||
|
||||
Map<String, String> procProps = new HashMap<>();
|
||||
|
@ -580,6 +582,6 @@ public class TestStandardProcessScheduler {
|
|||
}
|
||||
|
||||
private ProcessScheduler createScheduler() {
|
||||
return new StandardProcessScheduler(null, null, stateMgrProvider, variableRegistry, nifiProperties);
|
||||
return new StandardProcessScheduler(null, null, stateMgrProvider, nifiProperties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.apache.nifi.nar.ExtensionManager;
|
|||
import org.apache.nifi.nar.SystemBundle;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.reporting.BulletinRepository;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
|
@ -24,8 +24,8 @@ import org.apache.nifi.nar.ExtensionManager;
|
|||
import org.apache.nifi.nar.NarClassLoaders;
|
||||
import org.apache.nifi.nar.SystemBundle;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.util.FileBasedVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
|
|
@ -17,6 +17,22 @@
|
|||
*/
|
||||
package org.apache.nifi.controller.service;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.nifi.bundle.Bundle;
|
||||
import org.apache.nifi.components.state.StateManager;
|
||||
import org.apache.nifi.components.state.StateManagerProvider;
|
||||
|
@ -40,6 +56,8 @@ import org.apache.nifi.nar.SystemBundle;
|
|||
import org.apache.nifi.processor.Processor;
|
||||
import org.apache.nifi.processor.StandardValidationContextFactory;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.MutableVariableRegistry;
|
||||
import org.apache.nifi.registry.variable.StandardComponentVariableRegistry;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -49,22 +67,6 @@ import org.mockito.Mockito;
|
|||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestStandardControllerServiceProvider {
|
||||
|
||||
private static StateManagerProvider stateManagerProvider = new StateManagerProvider() {
|
||||
|
@ -129,7 +131,7 @@ public class TestStandardControllerServiceProvider {
|
|||
}
|
||||
|
||||
private StandardProcessScheduler createScheduler() {
|
||||
return new StandardProcessScheduler(null, null, stateManagerProvider, variableRegistry, niFiProperties);
|
||||
return new StandardProcessScheduler(null, null, stateManagerProvider, niFiProperties);
|
||||
}
|
||||
|
||||
private void setProperty(ControllerServiceNode serviceNode, String propName, String propValue) {
|
||||
|
@ -432,9 +434,10 @@ public class TestStandardControllerServiceProvider {
|
|||
final LoggableComponent<Processor> dummyProcessor = new LoggableComponent<>(new DummyProcessor(), systemBundle.getBundleDetails().getCoordinate(), null);
|
||||
final ProcessorNode procNode = new StandardProcessorNode(dummyProcessor, UUID.randomUUID().toString(),
|
||||
new StandardValidationContextFactory(serviceProvider, null), scheduler, serviceProvider, niFiProperties,
|
||||
VariableRegistry.EMPTY_REGISTRY, reloadComponent);
|
||||
new StandardComponentVariableRegistry(VariableRegistry.EMPTY_REGISTRY), reloadComponent);
|
||||
|
||||
final ProcessGroup group = new StandardProcessGroup(UUID.randomUUID().toString(), serviceProvider, scheduler, null, null, Mockito.mock(FlowController.class), variableRegistry);
|
||||
final ProcessGroup group = new StandardProcessGroup(UUID.randomUUID().toString(), serviceProvider, scheduler, null, null, Mockito.mock(FlowController.class),
|
||||
new MutableVariableRegistry(variableRegistry));
|
||||
group.addProcessor(procNode);
|
||||
procNode.setProcessGroup(group);
|
||||
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
package org.apache.nifi.controller.service.mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
|
@ -32,6 +34,7 @@ import org.apache.nifi.connectable.Funnel;
|
|||
import org.apache.nifi.connectable.Port;
|
||||
import org.apache.nifi.connectable.Position;
|
||||
import org.apache.nifi.connectable.Positionable;
|
||||
import org.apache.nifi.controller.ConfiguredComponent;
|
||||
import org.apache.nifi.controller.FlowController;
|
||||
import org.apache.nifi.controller.ProcessorNode;
|
||||
import org.apache.nifi.controller.Snippet;
|
||||
|
@ -41,12 +44,15 @@ import org.apache.nifi.controller.service.ControllerServiceNode;
|
|||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.groups.ProcessGroupCounts;
|
||||
import org.apache.nifi.groups.RemoteProcessGroup;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.MutableVariableRegistry;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
|
||||
public class MockProcessGroup implements ProcessGroup {
|
||||
private final Map<String, ControllerServiceNode> serviceMap = new HashMap<>();
|
||||
private final Map<String, ProcessorNode> processorMap = new HashMap<>();
|
||||
private final FlowController flowController;
|
||||
private final MutableVariableRegistry variableRegistry = new MutableVariableRegistry(VariableRegistry.ENVIRONMENT_SYSTEM_REGISTRY);
|
||||
|
||||
public MockProcessGroup(final FlowController flowController) {
|
||||
this.flowController = flowController;
|
||||
|
@ -143,8 +149,8 @@ public class MockProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void startProcessor(final ProcessorNode processor) {
|
||||
|
||||
public CompletableFuture<Void> startProcessor(final ProcessorNode processor) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -163,8 +169,8 @@ public class MockProcessGroup implements ProcessGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void stopProcessor(final ProcessorNode processor) {
|
||||
|
||||
public CompletableFuture<Void> stopProcessor(final ProcessorNode processor) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -601,4 +607,22 @@ public class MockProcessGroup implements ProcessGroup {
|
|||
@Override
|
||||
public void verifyCanStop(final Connectable connectable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableVariableRegistry getVariableRegistry() {
|
||||
return variableRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyCanUpdateVariables(Map<String, String> updatedVariables) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVariables(Map<String, String> variables) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConfiguredComponent> getComponentsAffectedByVariable(String variableName) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.nio.file.Paths;
|
|||
import java.util.Map;
|
||||
import org.apache.nifi.registry.VariableDescriptor;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.variable.FileBasedVariableRegistry;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.nifi.action.details.FlowChangeMoveDetails;
|
|||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
import org.apache.nifi.controller.ScheduledState;
|
||||
import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
|
||||
import org.apache.nifi.web.dao.ProcessGroupDAO;
|
||||
|
@ -175,6 +176,60 @@ public class ProcessGroupAuditor extends NiFiAuditor {
|
|||
+ "execution(void scheduleComponents(java.lang.String, org.apache.nifi.controller.ScheduledState, java.util.Set)) && "
|
||||
+ "args(groupId, state)")
|
||||
public void scheduleComponentsAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ScheduledState state) throws Throwable {
|
||||
final Operation operation;
|
||||
// determine the running state
|
||||
if (ScheduledState.RUNNING.equals(state)) {
|
||||
operation = Operation.Start;
|
||||
} else {
|
||||
operation = Operation.Stop;
|
||||
}
|
||||
|
||||
saveUpdateAction(proceedingJoinPoint, groupId, operation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Audits the update of controller serivce state
|
||||
*
|
||||
* @param proceedingJoinPoint join point
|
||||
* @param groupId group id
|
||||
* @param state controller serivce state state
|
||||
* @throws Throwable ex
|
||||
*/
|
||||
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
|
||||
+ "execution(java.util.concurrent.Future activateControllerServices(java.lang.String, org.apache.nifi.controller.service.ControllerServiceState, java.util.Set)) && "
|
||||
+ "args(groupId, state)")
|
||||
public void activateControllerServicesAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId, ControllerServiceState state) throws Throwable {
|
||||
|
||||
// determine the service state
|
||||
final Operation operation;
|
||||
if (ControllerServiceState.ENABLED.equals(state)) {
|
||||
operation = Operation.Enable;
|
||||
} else {
|
||||
operation = Operation.Disable;
|
||||
}
|
||||
|
||||
saveUpdateAction(proceedingJoinPoint, groupId, operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Audits the update of process group variable registry.
|
||||
*
|
||||
* @param proceedingJoinPoint join point
|
||||
* @param groupId group id
|
||||
* @throws Throwable ex
|
||||
*/
|
||||
@Around("within(org.apache.nifi.web.dao.ProcessGroupDAO+) && "
|
||||
+ "execution(org.apache.nifi.groups.ProcessGroup updateVariableRegistry(org.apache.nifi.web.api.dto.VariableRegistryDTO)) && "
|
||||
+ "args(groupId)")
|
||||
public void updateVariableRegistryAdvice(ProceedingJoinPoint proceedingJoinPoint, String groupId) throws Throwable {
|
||||
final Operation operation = Operation.Configure;
|
||||
saveUpdateAction(proceedingJoinPoint, groupId, operation);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void saveUpdateAction(final ProceedingJoinPoint proceedingJoinPoint, final String groupId, final Operation operation) throws Throwable {
|
||||
ProcessGroupDAO processGroupDAO = getProcessGroupDAO();
|
||||
ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
|
||||
|
||||
|
@ -191,13 +246,7 @@ public class ProcessGroupAuditor extends NiFiAuditor {
|
|||
action.setSourceName(processGroup.getName());
|
||||
action.setSourceType(Component.ProcessGroup);
|
||||
action.setTimestamp(new Date());
|
||||
|
||||
// determine the running state
|
||||
if (ScheduledState.RUNNING.equals(state)) {
|
||||
action.setOperation(Operation.Start);
|
||||
} else {
|
||||
action.setOperation(Operation.Stop);
|
||||
}
|
||||
action.setOperation(operation);
|
||||
|
||||
// add this action
|
||||
saveAction(action, logger);
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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.registry.variable;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class VariableRegistryUpdateRequest {
|
||||
private final String requestId;
|
||||
private final String processGroupId;
|
||||
private volatile Date submissionTime = new Date();
|
||||
private volatile Date lastUpdated = new Date();
|
||||
private volatile boolean complete = false;
|
||||
|
||||
private final AtomicReference<String> failureReason = new AtomicReference<>();
|
||||
|
||||
private final VariableRegistryUpdateStep identifyComponentsStep = new VariableRegistryUpdateStep("Identifying components affected");
|
||||
private final VariableRegistryUpdateStep stopProcessors = new VariableRegistryUpdateStep("Stopping affected Processors");
|
||||
private final VariableRegistryUpdateStep disableServices = new VariableRegistryUpdateStep("Disabling affected Controller Services");
|
||||
private final VariableRegistryUpdateStep applyUpdates = new VariableRegistryUpdateStep("Applying Updates");
|
||||
private final VariableRegistryUpdateStep enableServices = new VariableRegistryUpdateStep("Re-Enabling affected Controller Services");
|
||||
private final VariableRegistryUpdateStep startProcessors = new VariableRegistryUpdateStep("Restarting affected Processors");
|
||||
|
||||
public VariableRegistryUpdateRequest(final String requestId, final String processGroupId) {
|
||||
this.requestId = requestId;
|
||||
this.processGroupId = processGroupId;
|
||||
}
|
||||
|
||||
public String getProcessGroupId() {
|
||||
return processGroupId;
|
||||
}
|
||||
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public Date getSubmissionTime() {
|
||||
return submissionTime;
|
||||
}
|
||||
|
||||
public Date getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void setLastUpdated(Date lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getIdentifyRelevantComponentsStep() {
|
||||
return identifyComponentsStep;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getStopProcessorsStep() {
|
||||
return stopProcessors;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getDisableServicesStep() {
|
||||
return disableServices;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getApplyUpdatesStep() {
|
||||
return applyUpdates;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getEnableServicesStep() {
|
||||
return enableServices;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStep getStartProcessorsStep() {
|
||||
return startProcessors;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
public String getFailureReason() {
|
||||
return failureReason.get();
|
||||
}
|
||||
|
||||
public void setFailureReason(String reason) {
|
||||
this.failureReason.set(reason);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
this.failureReason.compareAndSet(null, "Update was cancelled");
|
||||
this.complete = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.registry.variable;
|
||||
|
||||
public class VariableRegistryUpdateStep {
|
||||
private final String description;
|
||||
private volatile boolean complete;
|
||||
private volatile String failureReason;
|
||||
|
||||
public VariableRegistryUpdateStep(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setComplete(boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
public String getFailureReason() {
|
||||
return failureReason;
|
||||
}
|
||||
|
||||
public void setFailureReason(String failureReason) {
|
||||
this.failureReason = failureReason;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,13 @@
|
|||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.nifi.authorization.AuthorizeAccess;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
|
@ -24,6 +31,7 @@ import org.apache.nifi.controller.repository.claim.ContentDirection;
|
|||
import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
|
||||
import org.apache.nifi.web.api.dto.AffectedComponentDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinBoardDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinQueryDTO;
|
||||
|
@ -57,6 +65,7 @@ import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
|
|||
import org.apache.nifi.web.api.dto.TemplateDTO;
|
||||
import org.apache.nifi.web.api.dto.UserDTO;
|
||||
import org.apache.nifi.web.api.dto.UserGroupDTO;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
|
||||
import org.apache.nifi.web.api.dto.action.HistoryDTO;
|
||||
import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
|
||||
import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
|
||||
|
@ -67,6 +76,7 @@ import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
|
|||
import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
|
||||
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
|
||||
import org.apache.nifi.web.api.entity.ActionEntity;
|
||||
import org.apache.nifi.web.api.entity.ActivateControllerServicesEntity;
|
||||
import org.apache.nifi.web.api.entity.BulletinEntity;
|
||||
import org.apache.nifi.web.api.entity.ConnectionEntity;
|
||||
import org.apache.nifi.web.api.entity.ConnectionStatusEntity;
|
||||
|
@ -96,13 +106,7 @@ import org.apache.nifi.web.api.entity.StatusHistoryEntity;
|
|||
import org.apache.nifi.web.api.entity.TemplateEntity;
|
||||
import org.apache.nifi.web.api.entity.UserEntity;
|
||||
import org.apache.nifi.web.api.entity.UserGroupEntity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import org.apache.nifi.web.api.entity.VariableRegistryEntity;
|
||||
|
||||
/**
|
||||
* Defines the NiFiServiceFacade interface.
|
||||
|
@ -886,6 +890,48 @@ public interface NiFiServiceFacade {
|
|||
*/
|
||||
ProcessGroupEntity getProcessGroup(String groupId);
|
||||
|
||||
/**
|
||||
* Returns the Variable Registry for the Process Group with the given ID
|
||||
*
|
||||
* @param groupId the ID of the Process Group
|
||||
* @param includeAncestorGroups whether or not to include the variables that are defined in the the process group's parent group & its parent group, etc.
|
||||
* @return the Variable Registry transfer object
|
||||
*/
|
||||
VariableRegistryEntity getVariableRegistry(String groupId, boolean includeAncestorGroups);
|
||||
|
||||
/**
|
||||
* Returns a Variable Registry that includes the variables in the given DTO but has the affected components populated
|
||||
*
|
||||
* @param variableRegistryDto the Variable Registry that contains the variables of interest
|
||||
* @return a Variable Registry that has the affected components populated
|
||||
*/
|
||||
VariableRegistryEntity populateAffectedComponents(VariableRegistryDTO variableRegistryDto);
|
||||
|
||||
/**
|
||||
* Updates the variable registry on behalf of the user currently logged in
|
||||
*
|
||||
* @param revision Revision to compare with current base revision
|
||||
* @param variableRegistryDto the Variable Registry
|
||||
*/
|
||||
VariableRegistryEntity updateVariableRegistry(Revision revision, VariableRegistryDTO variableRegistryDto);
|
||||
|
||||
/**
|
||||
* Updates the variable registry on behalf of the given user
|
||||
*
|
||||
* @param user the user who performed the action
|
||||
* @param revision Revision to compare with current base revision
|
||||
* @param variableRegistryDto the Variable Registry
|
||||
*/
|
||||
VariableRegistryEntity updateVariableRegistry(NiFiUser user, Revision revision, VariableRegistryDTO variableRegistryDto);
|
||||
|
||||
/**
|
||||
* Determines which components will be affected by updating the given Variable Registry
|
||||
*
|
||||
* @param variableRegistryDto the variable registry
|
||||
* @return the components that will be affected
|
||||
*/
|
||||
Set<AffectedComponentDTO> getComponentsAffectedByVariableRegistryUpdate(VariableRegistryDTO variableRegistryDto);
|
||||
|
||||
/**
|
||||
* Gets all process groups in the specified parent group.
|
||||
*
|
||||
|
@ -904,7 +950,37 @@ public interface NiFiServiceFacade {
|
|||
void verifyScheduleComponents(String processGroupId, ScheduledState state, Set<String> componentIds);
|
||||
|
||||
/**
|
||||
* Schedules all applicable components under the specified ProcessGroup.
|
||||
* Verifies the controller services with the given ID's can be enabled or disabled
|
||||
*
|
||||
* @param processGroupId the ID of the process group
|
||||
* @param state the state
|
||||
* @param serviceIds the id's of the services
|
||||
*/
|
||||
void verifyActivateControllerServices(String processGroupId, ControllerServiceState state, Set<String> serviceIds);
|
||||
|
||||
/**
|
||||
* Enables or disables the controller services with the given IDs & Revisions on behalf of the currently logged in user
|
||||
*
|
||||
* @param processGroupId the ID of the process group
|
||||
* @param state the desired state of the services
|
||||
* @param serviceRevisions a mapping of Controller Service ID to current Revision
|
||||
* @return snapshot
|
||||
*/
|
||||
ActivateControllerServicesEntity activateControllerServices(String processGroupId, ControllerServiceState state, Map<String, Revision> serviceRevisions);
|
||||
|
||||
/**
|
||||
* Enables or disables the controller services with the given IDs & Revisions on behalf of the given user
|
||||
*
|
||||
* @param user the user performing the action
|
||||
* @param processGroupId the ID of the process group
|
||||
* @param state the desired state of the services
|
||||
* @param serviceRevisions a mapping of Controller Service ID to current Revision
|
||||
* @return snapshot
|
||||
*/
|
||||
ActivateControllerServicesEntity activateControllerServices(NiFiUser user, String processGroupId, ControllerServiceState state, Map<String, Revision> serviceRevisions);
|
||||
|
||||
/**
|
||||
* Schedules all applicable components under the specified ProcessGroup on behalf of the currently logged in user.
|
||||
*
|
||||
* @param processGroupId The ProcessGroup id
|
||||
* @param state schedule state
|
||||
|
@ -913,6 +989,17 @@ public interface NiFiServiceFacade {
|
|||
*/
|
||||
ScheduleComponentsEntity scheduleComponents(String processGroupId, ScheduledState state, Map<String, Revision> componentRevisions);
|
||||
|
||||
/**
|
||||
* Schedules all applicable components under the specified ProcessGroup on behalf of the given user.
|
||||
*
|
||||
* @param user the user performing the action
|
||||
* @param processGroupId The ProcessGroup id
|
||||
* @param state schedule state
|
||||
* @param componentRevisions components and their revision
|
||||
* @return snapshot
|
||||
*/
|
||||
ScheduleComponentsEntity scheduleComponents(NiFiUser user, String processGroupId, ScheduledState state, Map<String, Revision> componentRevisions);
|
||||
|
||||
/**
|
||||
* Updates the specified process group.
|
||||
*
|
||||
|
@ -922,6 +1009,14 @@ public interface NiFiServiceFacade {
|
|||
*/
|
||||
ProcessGroupEntity updateProcessGroup(Revision revision, ProcessGroupDTO processGroupDTO);
|
||||
|
||||
/**
|
||||
* Verifies that the Process Group identified by the given DTO can be updated in the manner appropriate according
|
||||
* to the DTO
|
||||
*
|
||||
* @param processGroupDTO the DTO that indicates the updates to occur
|
||||
*/
|
||||
void verifyUpdateProcessGroup(ProcessGroupDTO processGroupDTO);
|
||||
|
||||
/**
|
||||
* Verifies the specified process group can be removed.
|
||||
*
|
||||
|
@ -1378,9 +1473,22 @@ public interface NiFiServiceFacade {
|
|||
* Gets all controller services that belong to the given group and its parent/ancestor groups
|
||||
*
|
||||
* @param groupId the id of the process group of interest
|
||||
* @param includeAncestorGroups if true, parent and ancestor groups' services will be returned as well
|
||||
* @param includeDescendantGroups if true, child and descendant groups' services will be returned as well
|
||||
* @return services
|
||||
*/
|
||||
Set<ControllerServiceEntity> getControllerServices(String groupId);
|
||||
Set<ControllerServiceEntity> getControllerServices(String groupId, boolean includeAncestorGroups, boolean includeDescendantGroups);
|
||||
|
||||
/**
|
||||
* Gets all controller services that belong to the given group and its parent/ancestor groups
|
||||
*
|
||||
* @param groupId the id of the process group of interest
|
||||
* @param includeAncestorGroups if true, parent and ancestor groups' services will be returned as well
|
||||
* @param includeDescendantGroups if true, child and descendant groups' services will be returned as well
|
||||
* @param user the user that is retrieving the Controller Services
|
||||
* @return services
|
||||
*/
|
||||
Set<ControllerServiceEntity> getControllerServices(String groupId, boolean includeAncestorGroups, boolean includeDescendantGroups, NiFiUser user);
|
||||
|
||||
/**
|
||||
* Gets the specified controller service.
|
||||
|
|
|
@ -102,6 +102,18 @@ public class NiFiServiceFacadeLock {
|
|||
return proceedWithWriteLock(proceedingJoinPoint);
|
||||
}
|
||||
|
||||
@Around("within(org.apache.nifi.web.NiFiServiceFacade+) && "
|
||||
+ "execution(* activate*(..))")
|
||||
public Object activateLock(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
return proceedWithWriteLock(proceedingJoinPoint);
|
||||
}
|
||||
|
||||
@Around("within(org.apache.nifi.web.NiFiServiceFacade+) && "
|
||||
+ "execution(* populate*(..))")
|
||||
public Object populateLock(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
return proceedWithWriteLock(proceedingJoinPoint);
|
||||
}
|
||||
|
||||
@Around("within(org.apache.nifi.web.NiFiServiceFacade+) && "
|
||||
+ "execution(* get*(..))")
|
||||
public Object getLock(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
|
||||
|
|
|
@ -16,7 +16,31 @@
|
|||
*/
|
||||
package org.apache.nifi.web;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.nifi.action.Action;
|
||||
import org.apache.nifi.action.Component;
|
||||
import org.apache.nifi.action.FlowChangeAction;
|
||||
|
@ -84,6 +108,7 @@ import org.apache.nifi.groups.RemoteProcessGroup;
|
|||
import org.apache.nifi.history.History;
|
||||
import org.apache.nifi.history.HistoryQuery;
|
||||
import org.apache.nifi.history.PreviousValue;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.remote.RootGroupPort;
|
||||
import org.apache.nifi.reporting.Bulletin;
|
||||
import org.apache.nifi.reporting.BulletinQuery;
|
||||
|
@ -92,6 +117,7 @@ import org.apache.nifi.reporting.ComponentType;
|
|||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
|
||||
import org.apache.nifi.web.api.dto.AccessPolicySummaryDTO;
|
||||
import org.apache.nifi.web.api.dto.AffectedComponentDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinBoardDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinDTO;
|
||||
import org.apache.nifi.web.api.dto.BulletinQueryDTO;
|
||||
|
@ -137,6 +163,7 @@ import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
|
|||
import org.apache.nifi.web.api.dto.TemplateDTO;
|
||||
import org.apache.nifi.web.api.dto.UserDTO;
|
||||
import org.apache.nifi.web.api.dto.UserGroupDTO;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
|
||||
import org.apache.nifi.web.api.dto.action.HistoryDTO;
|
||||
import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
|
||||
import org.apache.nifi.web.api.dto.flow.FlowDTO;
|
||||
|
@ -157,6 +184,7 @@ import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
|
|||
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
|
||||
import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity;
|
||||
import org.apache.nifi.web.api.entity.ActionEntity;
|
||||
import org.apache.nifi.web.api.entity.ActivateControllerServicesEntity;
|
||||
import org.apache.nifi.web.api.entity.BulletinEntity;
|
||||
import org.apache.nifi.web.api.entity.ComponentReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ConnectionEntity;
|
||||
|
@ -190,6 +218,8 @@ import org.apache.nifi.web.api.entity.TemplateEntity;
|
|||
import org.apache.nifi.web.api.entity.TenantEntity;
|
||||
import org.apache.nifi.web.api.entity.UserEntity;
|
||||
import org.apache.nifi.web.api.entity.UserGroupEntity;
|
||||
import org.apache.nifi.web.api.entity.VariableEntity;
|
||||
import org.apache.nifi.web.api.entity.VariableRegistryEntity;
|
||||
import org.apache.nifi.web.controller.ControllerFacade;
|
||||
import org.apache.nifi.web.dao.AccessPolicyDAO;
|
||||
import org.apache.nifi.web.dao.ConnectionDAO;
|
||||
|
@ -217,28 +247,7 @@ import org.apache.nifi.web.util.SnippetUtils;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Implementation of NiFiServiceFacade that performs revision checking.
|
||||
|
@ -422,6 +431,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
processGroupDAO.verifyScheduleComponents(groupId, state, componentIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyActivateControllerServices(final String groupId, final ControllerServiceState state, final Set<String> serviceIds) {
|
||||
processGroupDAO.verifyActivateControllerServices(groupId, state, serviceIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyDeleteProcessGroup(final String groupId) {
|
||||
processGroupDAO.verifyDelete(groupId);
|
||||
|
@ -624,6 +638,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
*/
|
||||
private <D, C> RevisionUpdate<D> updateComponent(final Revision revision, final Authorizable authorizable, final Supplier<C> daoUpdate, final Function<C, D> dtoCreation) {
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
return updateComponent(user, revision, authorizable, daoUpdate, dtoCreation);
|
||||
}
|
||||
|
||||
private <D, C> RevisionUpdate<D> updateComponent(final NiFiUser user, final Revision revision, final Authorizable authorizable, final Supplier<C> daoUpdate, final Function<C, D> dtoCreation) {
|
||||
try {
|
||||
final RevisionUpdate<D> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(revision), user, new UpdateRevisionTask<D>() {
|
||||
@Override
|
||||
|
@ -773,6 +791,81 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
return entityFactory.createRemoteProcessGroupPortEntity(snapshot.getComponent(), updatedRevision, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<AffectedComponentDTO> getComponentsAffectedByVariableRegistryUpdate(final VariableRegistryDTO variableRegistryDto) {
|
||||
final ProcessGroup group = processGroupDAO.getProcessGroup(variableRegistryDto.getProcessGroupId());
|
||||
if (group == null) {
|
||||
throw new ResourceNotFoundException("Could not find Process Group with ID " + variableRegistryDto.getProcessGroupId());
|
||||
}
|
||||
|
||||
final Map<String, String> variableMap = new HashMap<>();
|
||||
variableRegistryDto.getVariables().stream() // have to use forEach here instead of using Collectors.toMap because value may be null
|
||||
.map(VariableEntity::getVariable)
|
||||
.forEach(var -> variableMap.put(var.getName(), var.getValue()));
|
||||
|
||||
final Set<AffectedComponentDTO> affectedComponentDtos = new HashSet<>();
|
||||
|
||||
final Set<String> updatedVariableNames = getUpdatedVariables(group, variableMap);
|
||||
for (final String variableName : updatedVariableNames) {
|
||||
final Set<ConfiguredComponent> affectedComponents = group.getComponentsAffectedByVariable(variableName);
|
||||
|
||||
for (final ConfiguredComponent component : affectedComponents) {
|
||||
if (component instanceof ProcessorNode) {
|
||||
final ProcessorNode procNode = (ProcessorNode) component;
|
||||
if (procNode.isRunning()) {
|
||||
affectedComponentDtos.add(dtoFactory.createAffectedComponentDto(procNode));
|
||||
}
|
||||
} else if (component instanceof ControllerServiceNode) {
|
||||
final ControllerServiceNode serviceNode = (ControllerServiceNode) component;
|
||||
if (serviceNode.isActive()) {
|
||||
affectedComponentDtos.add(dtoFactory.createAffectedComponentDto(serviceNode));
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Found unexpected type of Component [" + component.getCanonicalClassName() + "] dependending on variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affectedComponentDtos;
|
||||
}
|
||||
|
||||
private Set<String> getUpdatedVariables(final ProcessGroup group, final Map<String, String> newVariableValues) {
|
||||
final Set<String> updatedVariableNames = new HashSet<>();
|
||||
|
||||
final ComponentVariableRegistry registry = group.getVariableRegistry();
|
||||
for (final Map.Entry<String, String> entry : newVariableValues.entrySet()) {
|
||||
final String varName = entry.getKey();
|
||||
final String newValue = entry.getValue();
|
||||
|
||||
final String curValue = registry.getVariableValue(varName);
|
||||
if (!Objects.equals(newValue, curValue)) {
|
||||
updatedVariableNames.add(varName);
|
||||
}
|
||||
}
|
||||
|
||||
return updatedVariableNames;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public VariableRegistryEntity updateVariableRegistry(Revision revision, VariableRegistryDTO variableRegistryDto) {
|
||||
return updateVariableRegistry(NiFiUserUtils.getNiFiUser(), revision, variableRegistryDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableRegistryEntity updateVariableRegistry(NiFiUser user, Revision revision, VariableRegistryDTO variableRegistryDto) {
|
||||
final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(variableRegistryDto.getProcessGroupId());
|
||||
final RevisionUpdate<VariableRegistryDTO> snapshot = updateComponent(user, revision,
|
||||
processGroupNode,
|
||||
() -> processGroupDAO.updateVariableRegistry(variableRegistryDto),
|
||||
processGroup -> dtoFactory.createVariableRegistryDto(processGroup));
|
||||
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroupNode);
|
||||
final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification());
|
||||
return entityFactory.createVariableRegistryEntity(snapshot.getComponent(), updatedRevision, permissions);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ProcessGroupEntity updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) {
|
||||
final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(processGroupDTO.getId());
|
||||
|
@ -789,15 +882,28 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
return entityFactory.createProcessGroupEntity(snapshot.getComponent(), updatedRevision, permissions, status, bulletinEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyUpdateProcessGroup(ProcessGroupDTO processGroupDTO) {
|
||||
if (processGroupDAO.hasProcessGroup(processGroupDTO.getId())) {
|
||||
processGroupDAO.verifyUpdate(processGroupDTO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduleComponentsEntity scheduleComponents(final String processGroupId, final ScheduledState state, final Map<String, Revision> componentRevisions) {
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
return scheduleComponents(user, processGroupId, state, componentRevisions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduleComponentsEntity scheduleComponents(final NiFiUser user, final String processGroupId, final ScheduledState state, final Map<String, Revision> componentRevisions) {
|
||||
|
||||
final RevisionUpdate<ScheduleComponentsEntity> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(componentRevisions.values()), user, new
|
||||
UpdateRevisionTask<ScheduleComponentsEntity>() {
|
||||
@Override
|
||||
public RevisionUpdate<ScheduleComponentsEntity> update() {
|
||||
// schedule the components
|
||||
processGroupDAO.scheduleComponents(processGroupId, state, componentRevisions.keySet());
|
||||
processGroupDAO.scheduleComponents(processGroupId, state, componentRevisions.keySet());
|
||||
|
||||
// update the revisions
|
||||
final Map<String, Revision> updatedRevisions = new HashMap<>();
|
||||
|
@ -820,6 +926,46 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
return updatedComponent.getComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivateControllerServicesEntity activateControllerServices(final String processGroupId, final ControllerServiceState state, final Map<String, Revision> serviceRevisions) {
|
||||
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
return activateControllerServices(user, processGroupId, state, serviceRevisions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivateControllerServicesEntity activateControllerServices(final NiFiUser user, final String processGroupId, final ControllerServiceState state,
|
||||
final Map<String, Revision> serviceRevisions) {
|
||||
|
||||
final RevisionUpdate<ActivateControllerServicesEntity> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(serviceRevisions.values()), user,
|
||||
new UpdateRevisionTask<ActivateControllerServicesEntity>() {
|
||||
@Override
|
||||
public RevisionUpdate<ActivateControllerServicesEntity> update() {
|
||||
// schedule the components
|
||||
processGroupDAO.activateControllerServices(processGroupId, state, serviceRevisions.keySet());
|
||||
|
||||
// update the revisions
|
||||
final Map<String, Revision> updatedRevisions = new HashMap<>();
|
||||
for (final Revision revision : serviceRevisions.values()) {
|
||||
final Revision currentRevision = revisionManager.getRevision(revision.getComponentId());
|
||||
updatedRevisions.put(revision.getComponentId(), currentRevision.incrementRevision(revision.getClientId()));
|
||||
}
|
||||
|
||||
// save
|
||||
controllerFacade.save();
|
||||
|
||||
// gather details for response
|
||||
final ActivateControllerServicesEntity entity = new ActivateControllerServicesEntity();
|
||||
entity.setId(processGroupId);
|
||||
entity.setState(state.name());
|
||||
return new StandardRevisionUpdate<>(entity, null, new HashSet<>(updatedRevisions.values()));
|
||||
}
|
||||
});
|
||||
|
||||
return updatedComponent.getComponent();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ControllerConfigurationEntity updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) {
|
||||
final RevisionUpdate<ControllerConfigurationDTO> updatedComponent = updateComponent(
|
||||
|
@ -3062,7 +3208,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
return createProcessGroupEntity(processGroup);
|
||||
}
|
||||
|
||||
private ControllerServiceEntity createControllerServiceEntity(final ControllerServiceNode serviceNode, final Set<String> serviceIds) {
|
||||
private ControllerServiceEntity createControllerServiceEntity(final ControllerServiceNode serviceNode, final Set<String> serviceIds, final NiFiUser user) {
|
||||
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(serviceNode);
|
||||
|
||||
final ControllerServiceReference ref = serviceNode.getReferences();
|
||||
|
@ -3070,26 +3216,77 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
dto.setReferencingComponents(referencingComponentsEntity.getControllerServiceReferencingComponents());
|
||||
|
||||
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(serviceNode.getIdentifier()));
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(serviceNode);
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(serviceNode, user);
|
||||
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(serviceNode.getIdentifier()));
|
||||
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
|
||||
return entityFactory.createControllerServiceEntity(dto, revision, permissions, bulletinEntities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ControllerServiceEntity> getControllerServices(final String groupId) {
|
||||
final Set<ControllerServiceNode> serviceNodes = controllerServiceDAO.getControllerServices(groupId);
|
||||
public VariableRegistryEntity getVariableRegistry(final String groupId, final boolean includeAncestorGroups) {
|
||||
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
|
||||
if (processGroup == null) {
|
||||
throw new ResourceNotFoundException("Could not find group with ID " + groupId);
|
||||
}
|
||||
|
||||
return createVariableRegistryEntity(processGroup, includeAncestorGroups);
|
||||
}
|
||||
|
||||
private VariableRegistryEntity createVariableRegistryEntity(final ProcessGroup processGroup, final boolean includeAncestorGroups) {
|
||||
final VariableRegistryDTO registryDto = dtoFactory.createVariableRegistryDto(processGroup);
|
||||
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(processGroup.getIdentifier()));
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
|
||||
|
||||
if (includeAncestorGroups) {
|
||||
ProcessGroup parent = processGroup.getParent();
|
||||
while (parent != null) {
|
||||
final PermissionsDTO parentPerms = dtoFactory.createPermissionsDto(processGroup);
|
||||
if (Boolean.TRUE.equals(parentPerms.getCanRead())) {
|
||||
final VariableRegistryDTO parentRegistryDto = dtoFactory.createVariableRegistryDto(parent);
|
||||
final Set<VariableEntity> parentVariables = parentRegistryDto.getVariables();
|
||||
registryDto.getVariables().addAll(parentVariables);
|
||||
}
|
||||
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
return entityFactory.createVariableRegistryEntity(registryDto, revision, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableRegistryEntity populateAffectedComponents(final VariableRegistryDTO variableRegistryDto) {
|
||||
final String groupId = variableRegistryDto.getProcessGroupId();
|
||||
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
|
||||
if (processGroup == null) {
|
||||
throw new ResourceNotFoundException("Could not find group with ID " + groupId);
|
||||
}
|
||||
|
||||
final VariableRegistryDTO registryDto = dtoFactory.populateAffectedComponents(variableRegistryDto, processGroup);
|
||||
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(processGroup.getIdentifier()));
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
|
||||
return entityFactory.createVariableRegistryEntity(registryDto, revision, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ControllerServiceEntity> getControllerServices(final String groupId, final boolean includeAncestorGroups, final boolean includeDescendantGroups) {
|
||||
return getControllerServices(groupId, includeAncestorGroups, includeDescendantGroups, NiFiUserUtils.getNiFiUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ControllerServiceEntity> getControllerServices(final String groupId, final boolean includeAncestorGroups, final boolean includeDescendantGroups, final NiFiUser user) {
|
||||
final Set<ControllerServiceNode> serviceNodes = controllerServiceDAO.getControllerServices(groupId, includeAncestorGroups, includeDescendantGroups);
|
||||
final Set<String> serviceIds = serviceNodes.stream().map(service -> service.getIdentifier()).collect(Collectors.toSet());
|
||||
|
||||
return serviceNodes.stream()
|
||||
.map(serviceNode -> createControllerServiceEntity(serviceNode, serviceIds))
|
||||
.map(serviceNode -> createControllerServiceEntity(serviceNode, serviceIds, user))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerServiceEntity getControllerService(final String controllerServiceId) {
|
||||
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId);
|
||||
return createControllerServiceEntity(controllerService, Sets.newHashSet(controllerServiceId));
|
||||
return createControllerServiceEntity(controllerService, Sets.newHashSet(controllerServiceId), NiFiUserUtils.getNiFiUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -608,6 +608,11 @@ public abstract class ApplicationResource {
|
|||
serviceFacade.authorizeAccess(authorizer);
|
||||
serviceFacade.verifyRevision(revision, user);
|
||||
|
||||
// verify if necessary
|
||||
if (verifier != null) {
|
||||
verifier.run();
|
||||
}
|
||||
|
||||
return action.apply(revision, entity);
|
||||
}
|
||||
}
|
||||
|
@ -657,6 +662,11 @@ public abstract class ApplicationResource {
|
|||
serviceFacade.authorizeAccess(authorizer);
|
||||
serviceFacade.verifyRevisions(revisions, user);
|
||||
|
||||
// verify if necessary
|
||||
if (verifier != null) {
|
||||
verifier.run();
|
||||
}
|
||||
|
||||
return action.apply(revisions, entity);
|
||||
}
|
||||
}
|
||||
|
@ -820,16 +830,16 @@ public abstract class ApplicationResource {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replicates the request to the given node
|
||||
*
|
||||
* @param method the HTTP method
|
||||
* @param nodeUuid the UUID of the node to replicate the request to
|
||||
* @return the response from the node
|
||||
* @throws UnknownNodeException if the nodeUuid given does not map to any node in the cluster
|
||||
*/
|
||||
protected Response replicate(final String method, final String nodeUuid) {
|
||||
return replicate(method, getRequestParameters(), nodeUuid);
|
||||
|
||||
private void ensureFlowInitialized() {
|
||||
if (!flowController.isInitialized()) {
|
||||
throw new IllegalClusterStateException("Cluster is still in the process of voting on the appropriate Data Flow.");
|
||||
}
|
||||
}
|
||||
|
||||
protected Response replicate(final String method, final Object entity, final String nodeUuid, final Map<String, String> headersToOverride) {
|
||||
final URI path = getAbsolutePath();
|
||||
return replicate(path, method, entity, nodeUuid, headersToOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -845,22 +855,16 @@ public abstract class ApplicationResource {
|
|||
return replicate(method, entity, nodeUuid, null);
|
||||
}
|
||||
|
||||
private void ensureFlowInitialized() {
|
||||
if (!flowController.isInitialized()) {
|
||||
throw new IllegalClusterStateException("Cluster is still in the process of voting on the appropriate Data Flow.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replicates the request to the given node
|
||||
*
|
||||
* @param method the HTTP method
|
||||
* @param entity the Entity to replicate
|
||||
* @param method the HTTP method
|
||||
* @param entity the Entity to replicate
|
||||
* @param nodeUuid the UUID of the node to replicate the request to
|
||||
* @return the response from the node
|
||||
* @throws UnknownNodeException if the nodeUuid given does not map to any node in the cluster
|
||||
*/
|
||||
protected Response replicate(final String method, final Object entity, final String nodeUuid, final Map<String, String> headersToOverride) {
|
||||
protected Response replicate(final URI path, final String method, final Object entity, final String nodeUuid, final Map<String, String> headersToOverride) {
|
||||
// since we're cluster we must specify the cluster node identifier
|
||||
if (nodeUuid == null) {
|
||||
throw new IllegalArgumentException("The cluster node identifier must be specified.");
|
||||
|
@ -873,7 +877,6 @@ public abstract class ApplicationResource {
|
|||
|
||||
ensureFlowInitialized();
|
||||
|
||||
final URI path = getAbsolutePath();
|
||||
try {
|
||||
final Map<String, String> headers = headersToOverride == null ? getHeaders() : getHeaders(headersToOverride);
|
||||
|
||||
|
@ -996,6 +999,12 @@ public abstract class ApplicationResource {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected NodeResponse replicateNodeResponse(final String method, final Object entity, final Map<String, String> headersToOverride) throws InterruptedException {
|
||||
final URI path = getAbsolutePath();
|
||||
return replicateNodeResponse(path, method, entity, headersToOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replicates the request to all nodes in the cluster using the provided method and entity. The headers
|
||||
* used will be those provided by the {@link #getHeaders()} method. The URI that will be used will be
|
||||
|
@ -1009,10 +1018,9 @@ public abstract class ApplicationResource {
|
|||
* @throws InterruptedException if interrupted while replicating the request
|
||||
* @see #replicate(String, Object, Map)
|
||||
*/
|
||||
protected NodeResponse replicateNodeResponse(final String method, final Object entity, final Map<String, String> headersToOverride) throws InterruptedException {
|
||||
protected NodeResponse replicateNodeResponse(final URI path, final String method, final Object entity, final Map<String, String> headersToOverride) throws InterruptedException {
|
||||
ensureFlowInitialized();
|
||||
|
||||
final URI path = getAbsolutePath();
|
||||
final Map<String, String> headers = headersToOverride == null ? getHeaders() : getHeaders(headersToOverride);
|
||||
|
||||
// Determine whether we should replicate only to the cluster coordinator, or if we should replicate directly
|
||||
|
|
|
@ -36,6 +36,8 @@ import org.apache.nifi.cluster.coordination.node.NodeConnectionState;
|
|||
import org.apache.nifi.cluster.manager.NodeResponse;
|
||||
import org.apache.nifi.cluster.protocol.NodeIdentifier;
|
||||
import org.apache.nifi.controller.ScheduledState;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.nar.NarClassLoaders;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
|
@ -61,6 +63,7 @@ import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
|
|||
import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
|
||||
import org.apache.nifi.web.api.entity.AboutEntity;
|
||||
import org.apache.nifi.web.api.entity.ActionEntity;
|
||||
import org.apache.nifi.web.api.entity.ActivateControllerServicesEntity;
|
||||
import org.apache.nifi.web.api.entity.BannerEntity;
|
||||
import org.apache.nifi.web.api.entity.BulletinBoardEntity;
|
||||
import org.apache.nifi.web.api.entity.ClusteSummaryEntity;
|
||||
|
@ -118,6 +121,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -388,7 +392,7 @@ public class FlowResource extends ApplicationResource {
|
|||
}
|
||||
|
||||
// get all the controller services
|
||||
final Set<ControllerServiceEntity> controllerServices = serviceFacade.getControllerServices(null);
|
||||
final Set<ControllerServiceEntity> controllerServices = serviceFacade.getControllerServices(null, false, false);
|
||||
controllerServiceResource.populateRemainingControllerServiceEntitiesContent(controllerServices);
|
||||
|
||||
// create the response entity
|
||||
|
@ -426,11 +430,10 @@ public class FlowResource extends ApplicationResource {
|
|||
}
|
||||
)
|
||||
public Response getControllerServicesFromGroup(
|
||||
@ApiParam(
|
||||
value = "The process group id.",
|
||||
required = true
|
||||
)
|
||||
@PathParam("id") String groupId) throws InterruptedException {
|
||||
@ApiParam(value = "The process group id.", required = true) @PathParam("id") String groupId,
|
||||
@ApiParam("Whether or not to include parent/ancestory process groups") @QueryParam("includeAncestorGroups") @DefaultValue("true") boolean includeAncestorGroups,
|
||||
@ApiParam("Whether or not to include descendant process groups") @QueryParam("includeDescendantGroups") @DefaultValue("false") boolean includeDescendantGroups
|
||||
) throws InterruptedException {
|
||||
|
||||
authorizeFlow();
|
||||
|
||||
|
@ -439,7 +442,7 @@ public class FlowResource extends ApplicationResource {
|
|||
}
|
||||
|
||||
// get all the controller services
|
||||
final Set<ControllerServiceEntity> controllerServices = serviceFacade.getControllerServices(groupId);
|
||||
final Set<ControllerServiceEntity> controllerServices = serviceFacade.getControllerServices(groupId, includeAncestorGroups, includeDescendantGroups);
|
||||
controllerServiceResource.populateRemainingControllerServiceEntitiesContent(controllerServices);
|
||||
|
||||
// create the response entity
|
||||
|
@ -512,7 +515,7 @@ public class FlowResource extends ApplicationResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("process-groups/{id}")
|
||||
@ApiOperation(
|
||||
value = "Schedule or unschedule comopnents in the specified Process Group.",
|
||||
value = "Schedule or unschedule components in the specified Process Group.",
|
||||
response = ScheduleComponentsEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Read - /flow", type = ""),
|
||||
|
@ -570,7 +573,7 @@ public class FlowResource extends ApplicationResource {
|
|||
|
||||
// ensure authorized for each processor we will attempt to schedule
|
||||
group.findAllProcessors().stream()
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PROCESSORS : ProcessGroup.UNSCHEDULABLE_PROCESSORS)
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PROCESSORS : ProcessGroup.UNSCHEDULABLE_PROCESSORS)
|
||||
.filter(processor -> processor.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
|
||||
.forEach(processor -> {
|
||||
componentIds.add(processor.getIdentifier());
|
||||
|
@ -578,7 +581,7 @@ public class FlowResource extends ApplicationResource {
|
|||
|
||||
// ensure authorized for each input port we will attempt to schedule
|
||||
group.findAllInputPorts().stream()
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
|
||||
.filter(inputPort -> inputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
|
||||
.forEach(inputPort -> {
|
||||
componentIds.add(inputPort.getIdentifier());
|
||||
|
@ -586,7 +589,7 @@ public class FlowResource extends ApplicationResource {
|
|||
|
||||
// ensure authorized for each output port we will attempt to schedule
|
||||
group.findAllOutputPorts().stream()
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
|
||||
.filter(ScheduledState.RUNNING.equals(state) ? ProcessGroup.SCHEDULABLE_PORTS : ProcessGroup.UNSCHEDULABLE_PORTS)
|
||||
.filter(outputPort -> outputPort.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
|
||||
.forEach(outputPort -> {
|
||||
componentIds.add(outputPort.getIdentifier());
|
||||
|
@ -640,7 +643,129 @@ public class FlowResource extends ApplicationResource {
|
|||
componentsToSchedule.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getRevision(e.getValue(), e.getKey())));
|
||||
|
||||
// update the process group
|
||||
final ScheduleComponentsEntity entity = serviceFacade.scheduleComponents(id, scheduledState, componentRevisions);
|
||||
final ScheduleComponentsEntity entity = serviceFacade.scheduleComponents(id, scheduledState, componentRevisions);
|
||||
return generateOkResponse(entity).build();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Path("process-groups/{id}/controller-services")
|
||||
@ApiOperation(value = "Enable or disable Controller Services in the specified Process Group.",
|
||||
response = ActivateControllerServicesEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Read - /flow", type = ""),
|
||||
@Authorization(value = "Write - /{component-type}/{uuid} - For every service being enabled/disabled", type = "")
|
||||
})
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
|
||||
@ApiResponse(code = 401, message = "Client could not be authenticated."),
|
||||
@ApiResponse(code = 403, message = "Client is not authorized to make this request."),
|
||||
@ApiResponse(code = 404, message = "The specified resource could not be found."),
|
||||
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
|
||||
}
|
||||
)
|
||||
public Response activateControllerServices(
|
||||
@Context HttpServletRequest httpServletRequest,
|
||||
@ApiParam(value = "The process group id.", required = true)
|
||||
@PathParam("id") String id,
|
||||
@ApiParam(value = "The request to schedule or unschedule. If the comopnents in the request are not specified, all authorized components will be considered.", required = true)
|
||||
final ActivateControllerServicesEntity requestEntity) {
|
||||
|
||||
// ensure the same id is being used
|
||||
if (!id.equals(requestEntity.getId())) {
|
||||
throw new IllegalArgumentException(String.format("The process group id (%s) in the request body does "
|
||||
+ "not equal the process group id of the requested resource (%s).", requestEntity.getId(), id));
|
||||
}
|
||||
|
||||
final ControllerServiceState state;
|
||||
if (requestEntity.getState() == null) {
|
||||
throw new IllegalArgumentException("The controller service state must be specified.");
|
||||
} else {
|
||||
try {
|
||||
state = ControllerServiceState.valueOf(requestEntity.getState());
|
||||
} catch (final IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException(String.format("The controller service state must be one of [%s].",
|
||||
StringUtils.join(EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.DISABLED), ", ")));
|
||||
}
|
||||
}
|
||||
|
||||
// ensure its a supported scheduled state
|
||||
if (ControllerServiceState.DISABLING.equals(state) || ControllerServiceState.ENABLING.equals(state)) {
|
||||
throw new IllegalArgumentException(String.format("The scheduled must be one of [%s].",
|
||||
StringUtils.join(EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.DISABLED), ", ")));
|
||||
}
|
||||
|
||||
// if the components are not specified, gather all components and their current revision
|
||||
if (requestEntity.getComponents() == null) {
|
||||
// get the current revisions for the components being updated
|
||||
final Set<Revision> revisions = serviceFacade.getRevisionsFromGroup(id, group -> {
|
||||
final Set<String> componentIds = new HashSet<>();
|
||||
|
||||
final Predicate<ControllerServiceNode> filter;
|
||||
if (ControllerServiceState.ENABLED.equals(state)) {
|
||||
filter = service -> !service.isActive() && service.isValid();
|
||||
} else {
|
||||
filter = service -> service.isActive();
|
||||
}
|
||||
|
||||
group.findAllControllerServices().stream()
|
||||
.filter(filter)
|
||||
.filter(service -> service.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()))
|
||||
.forEach(service -> componentIds.add(service.getIdentifier()));
|
||||
return componentIds;
|
||||
});
|
||||
|
||||
// build the component mapping
|
||||
final Map<String, RevisionDTO> componentsToSchedule = new HashMap<>();
|
||||
revisions.forEach(revision -> {
|
||||
final RevisionDTO dto = new RevisionDTO();
|
||||
dto.setClientId(revision.getClientId());
|
||||
dto.setVersion(revision.getVersion());
|
||||
componentsToSchedule.put(revision.getComponentId(), dto);
|
||||
});
|
||||
|
||||
// set the components and their current revision
|
||||
requestEntity.setComponents(componentsToSchedule);
|
||||
}
|
||||
|
||||
if (isReplicateRequest()) {
|
||||
return replicate(HttpMethod.PUT, requestEntity);
|
||||
}
|
||||
|
||||
final Map<String, RevisionDTO> requestComponentsToSchedule = requestEntity.getComponents();
|
||||
final Map<String, Revision> requestComponentRevisions =
|
||||
requestComponentsToSchedule.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getRevision(e.getValue(), e.getKey())));
|
||||
final Set<Revision> requestRevisions = new HashSet<>(requestComponentRevisions.values());
|
||||
|
||||
return withWriteLock(
|
||||
serviceFacade,
|
||||
requestEntity,
|
||||
requestRevisions,
|
||||
lookup -> {
|
||||
// ensure access to the flow
|
||||
authorizeFlow();
|
||||
|
||||
// ensure access to every component being scheduled
|
||||
requestComponentsToSchedule.keySet().forEach(componentId -> {
|
||||
final Authorizable authorizable = lookup.getControllerService(componentId).getAuthorizable();
|
||||
authorizable.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser());
|
||||
});
|
||||
},
|
||||
() -> serviceFacade.verifyActivateControllerServices(id, state, requestComponentRevisions.keySet()),
|
||||
(revisions, scheduleComponentsEntity) -> {
|
||||
final ControllerServiceState serviceState = ControllerServiceState.valueOf(scheduleComponentsEntity.getState());
|
||||
|
||||
final Map<String, RevisionDTO> componentsToSchedule = scheduleComponentsEntity.getComponents();
|
||||
final Map<String, Revision> componentRevisions =
|
||||
componentsToSchedule.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> getRevision(e.getValue(), e.getKey())));
|
||||
|
||||
// update the controller services
|
||||
final ActivateControllerServicesEntity entity = serviceFacade.activateControllerServices(id, serviceState, componentRevisions);
|
||||
return generateOkResponse(entity).build();
|
||||
}
|
||||
);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,6 +16,33 @@
|
|||
*/
|
||||
package org.apache.nifi.web.api.dto;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.action.Action;
|
||||
|
@ -47,6 +74,7 @@ import org.apache.nifi.authorization.Resource;
|
|||
import org.apache.nifi.authorization.User;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ComponentAuthorizable;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
import org.apache.nifi.bundle.Bundle;
|
||||
import org.apache.nifi.bundle.BundleCoordinate;
|
||||
|
@ -110,6 +138,9 @@ import org.apache.nifi.provenance.lineage.ComputeLineageSubmission;
|
|||
import org.apache.nifi.provenance.lineage.LineageEdge;
|
||||
import org.apache.nifi.provenance.lineage.LineageNode;
|
||||
import org.apache.nifi.provenance.lineage.ProvenanceEventLineageNode;
|
||||
import org.apache.nifi.registry.ComponentVariableRegistry;
|
||||
import org.apache.nifi.registry.variable.VariableRegistryUpdateRequest;
|
||||
import org.apache.nifi.registry.variable.VariableRegistryUpdateStep;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
import org.apache.nifi.remote.RootGroupPort;
|
||||
import org.apache.nifi.reporting.Bulletin;
|
||||
|
@ -161,35 +192,10 @@ import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity;
|
|||
import org.apache.nifi.web.api.entity.ProcessorStatusSnapshotEntity;
|
||||
import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusSnapshotEntity;
|
||||
import org.apache.nifi.web.api.entity.TenantEntity;
|
||||
import org.apache.nifi.web.api.entity.VariableEntity;
|
||||
import org.apache.nifi.web.controller.ControllerFacade;
|
||||
import org.apache.nifi.web.revision.RevisionManager;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class DtoFactory {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
@ -1712,9 +1718,34 @@ public final class DtoFactory {
|
|||
* @return dto
|
||||
*/
|
||||
public PermissionsDTO createPermissionsDto(final Authorizable authorizable) {
|
||||
return createPermissionsDto(authorizable, NiFiUserUtils.getNiFiUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the PermissionsDTO based on the specified Authorizable for the given user
|
||||
*
|
||||
* @param authorizable authorizable
|
||||
* @param user the NiFi User for which the Permissions are being created
|
||||
* @return dto
|
||||
*/
|
||||
public PermissionsDTO createPermissionsDto(final Authorizable authorizable, final NiFiUser user) {
|
||||
final PermissionsDTO dto = new PermissionsDTO();
|
||||
dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()));
|
||||
dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()));
|
||||
dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ, user));
|
||||
dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE, user));
|
||||
return dto;
|
||||
}
|
||||
|
||||
public AffectedComponentDTO createAffectedComponentDto(final ConfiguredComponent component) {
|
||||
final AffectedComponentDTO dto = new AffectedComponentDTO();
|
||||
dto.setComponentId(component.getIdentifier());
|
||||
dto.setParentGroupId(component.getProcessGroupIdentifier());
|
||||
|
||||
if (component instanceof ProcessorNode) {
|
||||
dto.setComponentType(AffectedComponentDTO.COMPONENT_TYPE_PROCESSOR);
|
||||
} else if (component instanceof ControllerServiceNode) {
|
||||
dto.setComponentType(AffectedComponentDTO.COMPONENT_TYPE_CONTROLLER_SERVICE);
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
@ -1998,6 +2029,10 @@ public final class DtoFactory {
|
|||
dto.setComments(group.getComments());
|
||||
dto.setName(group.getName());
|
||||
|
||||
final Map<String, String> variables = group.getVariableRegistry().getVariableMap().entrySet().stream()
|
||||
.collect(Collectors.toMap(entry -> entry.getKey().getName(), entry -> entry.getValue()));
|
||||
group.setVariables(variables);
|
||||
|
||||
final ProcessGroup parentGroup = group.getParent();
|
||||
if (parentGroup != null) {
|
||||
dto.setParentGroupId(parentGroup.getIdentifier());
|
||||
|
@ -2079,6 +2114,128 @@ public final class DtoFactory {
|
|||
return deprecationNotice == null ? null : deprecationNotice.reason();
|
||||
}
|
||||
|
||||
|
||||
public VariableRegistryDTO createVariableRegistryDto(final ProcessGroup processGroup) {
|
||||
final ComponentVariableRegistry variableRegistry = processGroup.getVariableRegistry();
|
||||
|
||||
final List<String> variableNames = variableRegistry.getVariableMap().keySet().stream()
|
||||
.map(descriptor -> descriptor.getName())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final Set<VariableEntity> variableEntities = new LinkedHashSet<>();
|
||||
|
||||
for (final String variableName : variableNames) {
|
||||
final VariableDTO variableDto = new VariableDTO();
|
||||
variableDto.setName(variableName);
|
||||
variableDto.setValue(variableRegistry.getVariableValue(variableName));
|
||||
variableDto.setProcessGroupId(processGroup.getIdentifier());
|
||||
|
||||
final Set<ConfiguredComponent> affectedComponents = processGroup.getComponentsAffectedByVariable(variableName);
|
||||
final Set<AffectedComponentDTO> affectedComponentDtos = affectedComponents.stream()
|
||||
.map(component -> createAffectedComponentDto(component))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
boolean canWrite = true;
|
||||
for (final ConfiguredComponent component : affectedComponents) {
|
||||
final PermissionsDTO permissions = createPermissionsDto(component);
|
||||
if (!permissions.getCanRead() || !permissions.getCanWrite()) {
|
||||
canWrite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
variableDto.setAffectedComponents(affectedComponentDtos);
|
||||
|
||||
final VariableEntity variableEntity = new VariableEntity();
|
||||
variableEntity.setVariable(variableDto);
|
||||
variableEntity.setCanWrite(canWrite);
|
||||
|
||||
variableEntities.add(variableEntity);
|
||||
}
|
||||
|
||||
final VariableRegistryDTO registryDto = new VariableRegistryDTO();
|
||||
registryDto.setProcessGroupId(processGroup.getIdentifier());
|
||||
registryDto.setVariables(variableEntities);
|
||||
|
||||
return registryDto;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateRequestDTO createVariableRegistryUpdateRequestDto(final VariableRegistryUpdateRequest request) {
|
||||
final VariableRegistryUpdateRequestDTO dto = new VariableRegistryUpdateRequestDTO();
|
||||
dto.setComplete(request.isComplete());
|
||||
dto.setFailureReason(request.getFailureReason());
|
||||
dto.setLastUpdated(request.getLastUpdated());
|
||||
dto.setProcessGroupId(request.getProcessGroupId());
|
||||
dto.setRequestId(request.getRequestId());
|
||||
dto.setSubmissionTime(request.getSubmissionTime());
|
||||
|
||||
final List<VariableRegistryUpdateStepDTO> updateSteps = new ArrayList<>();
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getIdentifyRelevantComponentsStep()));
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getStopProcessorsStep()));
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getDisableServicesStep()));
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getApplyUpdatesStep()));
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getEnableServicesStep()));
|
||||
updateSteps.add(createVariableRegistryUpdateStepDto(request.getStartProcessorsStep()));
|
||||
dto.setUpdateSteps(updateSteps);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public VariableRegistryUpdateStepDTO createVariableRegistryUpdateStepDto(final VariableRegistryUpdateStep step) {
|
||||
final VariableRegistryUpdateStepDTO dto = new VariableRegistryUpdateStepDTO();
|
||||
dto.setComplete(step.isComplete());
|
||||
dto.setDescription(step.getDescription());
|
||||
dto.setFailureReason(step.getFailureReason());
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
||||
public VariableRegistryDTO populateAffectedComponents(final VariableRegistryDTO variableRegistry, final ProcessGroup group) {
|
||||
if (!group.getIdentifier().equals(variableRegistry.getProcessGroupId())) {
|
||||
throw new IllegalArgumentException("Variable Registry does not have the same Group ID as the given Process Group");
|
||||
}
|
||||
|
||||
final Set<VariableEntity> variableEntities = new LinkedHashSet<>();
|
||||
|
||||
for (final VariableEntity inputEntity : variableRegistry.getVariables()) {
|
||||
final VariableEntity entity = new VariableEntity();
|
||||
|
||||
final VariableDTO inputDto = inputEntity.getVariable();
|
||||
final VariableDTO variableDto = new VariableDTO();
|
||||
variableDto.setName(inputDto.getName());
|
||||
variableDto.setValue(inputDto.getValue());
|
||||
variableDto.setProcessGroupId(group.getIdentifier());
|
||||
|
||||
final Set<ConfiguredComponent> affectedComponents = group.getComponentsAffectedByVariable(variableDto.getName());
|
||||
final Set<AffectedComponentDTO> affectedComponentDtos = affectedComponents.stream()
|
||||
.map(component -> createAffectedComponentDto(component))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
boolean canWrite = true;
|
||||
for (final ConfiguredComponent component : affectedComponents) {
|
||||
final PermissionsDTO permissions = createPermissionsDto(component);
|
||||
if (!permissions.getCanRead() || !permissions.getCanWrite()) {
|
||||
canWrite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
variableDto.setAffectedComponents(affectedComponentDtos);
|
||||
|
||||
entity.setCanWrite(canWrite);
|
||||
entity.setVariable(inputDto);
|
||||
|
||||
variableEntities.add(entity);
|
||||
}
|
||||
|
||||
final VariableRegistryDTO registryDto = new VariableRegistryDTO();
|
||||
registryDto.setProcessGroupId(group.getIdentifier());
|
||||
registryDto.setVariables(variableEntities);
|
||||
|
||||
return registryDto;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the capability description from the specified class.
|
||||
*/
|
||||
|
@ -3016,6 +3173,10 @@ public final class DtoFactory {
|
|||
copy.setActiveRemotePortCount(original.getActiveRemotePortCount());
|
||||
copy.setInactiveRemotePortCount(original.getInactiveRemotePortCount());
|
||||
|
||||
if (original.getVariables() != null) {
|
||||
copy.setVariables(new HashMap<>(original.getVariables()));
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ import org.apache.nifi.web.api.entity.StatusHistoryEntity;
|
|||
import org.apache.nifi.web.api.entity.TenantEntity;
|
||||
import org.apache.nifi.web.api.entity.UserEntity;
|
||||
import org.apache.nifi.web.api.entity.UserGroupEntity;
|
||||
import org.apache.nifi.web.api.entity.VariableRegistryEntity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -431,6 +432,18 @@ public final class EntityFactory {
|
|||
return entity;
|
||||
}
|
||||
|
||||
public VariableRegistryEntity createVariableRegistryEntity(final VariableRegistryDTO dto, final RevisionDTO revision, final PermissionsDTO permissions) {
|
||||
final VariableRegistryEntity entity = new VariableRegistryEntity();
|
||||
entity.setProcessGroupRevision(revision);
|
||||
if (dto != null) {
|
||||
if (permissions != null && permissions.getCanRead()) {
|
||||
entity.setVariableRegistry(dto);
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public ControllerServiceEntity createControllerServiceEntity(final ControllerServiceDTO dto, final RevisionDTO revision, final PermissionsDTO permissions, final List<BulletinEntity> bulletins) {
|
||||
final ControllerServiceEntity entity = new ControllerServiceEntity();
|
||||
entity.setRevision(revision);
|
||||
|
|
|
@ -63,7 +63,7 @@ public interface ControllerServiceDAO {
|
|||
*
|
||||
* @return The controller services
|
||||
*/
|
||||
Set<ControllerServiceNode> getControllerServices(String groupId);
|
||||
Set<ControllerServiceNode> getControllerServices(String groupId, boolean includeAncestorGroups, boolean includeDescendantGroups);
|
||||
|
||||
/**
|
||||
* Updates the specified controller service.
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
*/
|
||||
package org.apache.nifi.web.dao;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.nifi.controller.ScheduledState;
|
||||
import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
|
||||
|
||||
import java.util.Set;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
|
||||
|
||||
public interface ProcessGroupDAO {
|
||||
|
||||
|
@ -64,13 +67,33 @@ public interface ProcessGroupDAO {
|
|||
*/
|
||||
void verifyScheduleComponents(String groupId, ScheduledState state, Set<String> componentIds);
|
||||
|
||||
/**
|
||||
* Verifies the specified controller services can be modified
|
||||
*
|
||||
* @param groupId the ID of the process group
|
||||
* @param state the desired state
|
||||
* @param serviceIds the ID's of the controller services
|
||||
*/
|
||||
void verifyActivateControllerServices(String groupId, ControllerServiceState state, Set<String> serviceIds);
|
||||
|
||||
/**
|
||||
* Schedules the components in the specified process group.
|
||||
*
|
||||
* @param groupId id
|
||||
* @param state scheduled state
|
||||
*
|
||||
* @return a Future that can be used to wait for the services to finish starting or stopping
|
||||
*/
|
||||
void scheduleComponents(String groupId, ScheduledState state, Set<String> componentIds);
|
||||
Future<Void> scheduleComponents(String groupId, ScheduledState state, Set<String> componentIds);
|
||||
|
||||
/**
|
||||
* Enables or disables the controller services in the specified process group
|
||||
*
|
||||
* @param groupId the id of the group
|
||||
* @param state the desired state
|
||||
* @param serviceIds the ID's of the services to enable or disable
|
||||
*/
|
||||
Future<Void> activateControllerServices(String groupId, ControllerServiceState state, Set<String> serviceIds);
|
||||
|
||||
/**
|
||||
* Updates the specified process group.
|
||||
|
@ -80,6 +103,21 @@ public interface ProcessGroupDAO {
|
|||
*/
|
||||
ProcessGroup updateProcessGroup(ProcessGroupDTO processGroup);
|
||||
|
||||
/**
|
||||
* Updates the specified variable registry
|
||||
*
|
||||
* @param variableRegistry the Variable Registry
|
||||
* @return the Process Group that was updated
|
||||
*/
|
||||
ProcessGroup updateVariableRegistry(VariableRegistryDTO variableRegistry);
|
||||
|
||||
/**
|
||||
* Verifies that the specified updates to a current Process Group can be applied at this time
|
||||
*
|
||||
* @param processGroup the DTO That describes the changes to occur
|
||||
*/
|
||||
void verifyUpdate(ProcessGroupDTO processGroup);
|
||||
|
||||
/**
|
||||
* Verifies the specified process group can be removed.
|
||||
*
|
||||
|
|
|
@ -124,7 +124,7 @@ public class StandardControllerServiceDAO extends ComponentDAO implements Contro
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<ControllerServiceNode> getControllerServices(final String groupId) {
|
||||
public Set<ControllerServiceNode> getControllerServices(final String groupId, final boolean includeAncestorGroups, final boolean includeDescendantGroups) {
|
||||
if (groupId == null) {
|
||||
return flowController.getRootControllerServices();
|
||||
} else {
|
||||
|
@ -134,7 +134,12 @@ public class StandardControllerServiceDAO extends ComponentDAO implements Contro
|
|||
throw new ResourceNotFoundException("Could not find Process Group with ID " + groupId);
|
||||
}
|
||||
|
||||
return procGroup.getControllerServices(true);
|
||||
final Set<ControllerServiceNode> serviceNodes = procGroup.getControllerServices(includeAncestorGroups);
|
||||
if (includeDescendantGroups) {
|
||||
serviceNodes.addAll(procGroup.findAllControllerServices());
|
||||
}
|
||||
|
||||
return serviceNodes;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
*/
|
||||
package org.apache.nifi.web.dao.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.nifi.connectable.Connectable;
|
||||
import org.apache.nifi.connectable.ConnectableType;
|
||||
import org.apache.nifi.connectable.Port;
|
||||
|
@ -23,14 +30,15 @@ import org.apache.nifi.connectable.Position;
|
|||
import org.apache.nifi.controller.FlowController;
|
||||
import org.apache.nifi.controller.ProcessorNode;
|
||||
import org.apache.nifi.controller.ScheduledState;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.apache.nifi.web.ResourceNotFoundException;
|
||||
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
|
||||
import org.apache.nifi.web.api.dto.VariableRegistryDTO;
|
||||
import org.apache.nifi.web.api.entity.VariableEntity;
|
||||
import org.apache.nifi.web.dao.ProcessGroupDAO;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGroupDAO {
|
||||
|
||||
private FlowController flowController;
|
||||
|
@ -63,6 +71,10 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
|
|||
return flowController.getGroup(groupId) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyUpdate(final ProcessGroupDTO processGroup) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessGroup getProcessGroup(String groupId) {
|
||||
return locateProcessGroup(flowController, groupId);
|
||||
|
@ -99,14 +111,32 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
|
|||
}
|
||||
|
||||
@Override
|
||||
public void scheduleComponents(final String groupId, final ScheduledState state, final Set<String> componentIds) {
|
||||
public void verifyActivateControllerServices(final String groupId, final ControllerServiceState state, final Set<String> serviceIds) {
|
||||
final ProcessGroup group = locateProcessGroup(flowController, groupId);
|
||||
|
||||
group.findAllControllerServices().stream()
|
||||
.filter(service -> serviceIds.contains(service.getIdentifier()))
|
||||
.forEach(service -> {
|
||||
if (state == ControllerServiceState.ENABLED) {
|
||||
service.verifyCanEnable();
|
||||
} else {
|
||||
service.verifyCanDisable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> scheduleComponents(final String groupId, final ScheduledState state, final Set<String> componentIds) {
|
||||
final ProcessGroup group = locateProcessGroup(flowController, groupId);
|
||||
|
||||
CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
|
||||
|
||||
for (final String componentId : componentIds) {
|
||||
final Connectable connectable = group.findLocalConnectable(componentId);
|
||||
if (ScheduledState.RUNNING.equals(state)) {
|
||||
if (ConnectableType.PROCESSOR.equals(connectable.getConnectableType())) {
|
||||
connectable.getProcessGroup().startProcessor((ProcessorNode) connectable);
|
||||
final CompletableFuture<?> processorFuture = connectable.getProcessGroup().startProcessor((ProcessorNode) connectable);
|
||||
future = CompletableFuture.allOf(future, processorFuture);
|
||||
} else if (ConnectableType.INPUT_PORT.equals(connectable.getConnectableType())) {
|
||||
connectable.getProcessGroup().startInputPort((Port) connectable);
|
||||
} else if (ConnectableType.OUTPUT_PORT.equals(connectable.getConnectableType())) {
|
||||
|
@ -114,7 +144,8 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
|
|||
}
|
||||
} else {
|
||||
if (ConnectableType.PROCESSOR.equals(connectable.getConnectableType())) {
|
||||
connectable.getProcessGroup().stopProcessor((ProcessorNode) connectable);
|
||||
final CompletableFuture<?> processorFuture = connectable.getProcessGroup().stopProcessor((ProcessorNode) connectable);
|
||||
future = CompletableFuture.allOf(future, processorFuture);
|
||||
} else if (ConnectableType.INPUT_PORT.equals(connectable.getConnectableType())) {
|
||||
connectable.getProcessGroup().stopInputPort((Port) connectable);
|
||||
} else if (ConnectableType.OUTPUT_PORT.equals(connectable.getConnectableType())) {
|
||||
|
@ -122,6 +153,27 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Void> activateControllerServices(final String groupId, final ControllerServiceState state, final Set<String> serviceIds) {
|
||||
final ProcessGroup group = locateProcessGroup(flowController, groupId);
|
||||
|
||||
CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
|
||||
for (final String serviceId : serviceIds) {
|
||||
final ControllerServiceNode serviceNode = group.findControllerService(serviceId);
|
||||
if (ControllerServiceState.ENABLED.equals(state)) {
|
||||
final CompletableFuture<Void> serviceFuture = flowController.enableControllerService(serviceNode);
|
||||
future = CompletableFuture.allOf(future, serviceFuture);
|
||||
} else {
|
||||
final CompletableFuture<Void> serviceFuture = flowController.disableControllerService(serviceNode);
|
||||
future = CompletableFuture.allOf(future, serviceFuture);
|
||||
}
|
||||
}
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,6 +196,22 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou
|
|||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcessGroup updateVariableRegistry(final VariableRegistryDTO variableRegistry) {
|
||||
final ProcessGroup group = locateProcessGroup(flowController, variableRegistry.getProcessGroupId());
|
||||
if (group == null) {
|
||||
throw new ResourceNotFoundException("Could not find Process Group with ID " + variableRegistry.getProcessGroupId());
|
||||
}
|
||||
|
||||
final Map<String, String> variableMap = new HashMap<>();
|
||||
variableRegistry.getVariables().stream() // have to use forEach here instead of using Collectors.toMap because value may be null
|
||||
.map(VariableEntity::getVariable)
|
||||
.forEach(var -> variableMap.put(var.getName(), var.getValue()));
|
||||
|
||||
group.setVariables(variableMap);
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyDelete(String groupId) {
|
||||
ProcessGroup group = locateProcessGroup(flowController, groupId);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.web.util;
|
||||
|
||||
public interface Pause {
|
||||
|
||||
/**
|
||||
* Waits up to given amount of time, and returns <code>true</code> if the action being performed
|
||||
* should continue, <code>false</code> if the action being performed has been cancelled
|
||||
*
|
||||
* @return <code>true</code> if the action should continue, <code>false</code> otherwise
|
||||
*/
|
||||
boolean pause();
|
||||
|
||||
}
|
|
@ -284,6 +284,7 @@
|
|||
<property name="requestReplicator" ref="requestReplicator" />
|
||||
<property name="authorizer" ref="authorizer"/>
|
||||
<property name="flowController" ref="flowController" />
|
||||
<property name="dtoFactory" ref="dtoFactory" />
|
||||
</bean>
|
||||
<bean id="processorResource" class="org.apache.nifi.web.api.ProcessorResource" scope="singleton">
|
||||
<property name="serviceFacade" ref="serviceFacade"/>
|
||||
|
|
Loading…
Reference in New Issue