This is an automated email from the ASF dual-hosted git repository.
joewitt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 4ff9cdd NIFI-8173, NIFI-8174: This closes #4784. Updated Parameter
Contexts to allow for unsetting a parameter value / setting it to null. Allow
Parameters to make use of Expression Language. Updated docs to illustrated how
EL is evaluated
4ff9cdd is described below
commit 4ff9cddf159e974c7a5a5c9aa9e238c520d37dc3
Author: Mark Payne <[email protected]>
AuthorDate: Tue Jan 26 14:54:17 2021 -0500
NIFI-8173, NIFI-8174: This closes #4784. Updated Parameter Contexts to
allow for unsetting a parameter value / setting it to null. Allow Parameters to
make use of Expression Language. Updated docs to illustrated how EL is evaluated
Signed-off-by: Joe Witt <[email protected]>
---
.../nifi/parameter/StandardParameterReference.java | 2 +-
.../nifi/parameter/StandardParameterTokenList.java | 15 +-
.../parameter/TestStandardParameterTokenList.java | 3 +-
nifi-docs/src/main/asciidoc/user-guide.adoc | 25 ++-
.../org/apache/nifi/web/api/dto/ParameterDTO.java | 11 ++
.../nifi/parameter/StandardParameterContext.java | 7 +-
.../nifi/processor/StandardProcessContext.java | 2 +-
.../parameter/TestStandardParameterContext.java | 7 +-
.../nifi/controller/AbstractComponentNode.java | 10 --
.../serialization/StandardFlowSerializer.java | 45 ++---
.../src/main/resources/FlowConfiguration.xsd | 2 +-
.../web/dao/impl/StandardParameterContextDAO.java | 25 ++-
.../webapp/js/nf/canvas/nf-parameter-contexts.js | 16 +-
.../EvaluatePropertiesWithDifferentELScopes.java | 97 ++++++++++
.../nifi/processors/tests/system/WriteToFile.java | 103 +++++++++++
.../services/org.apache.nifi.processor.Processor | 2 +
.../system/parameters/ParameterContextIT.java | 198 ++++++++++++++++++++-
17 files changed, 510 insertions(+), 60 deletions(-)
diff --git
a/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterReference.java
b/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterReference.java
index 4f270f1..ec596e6 100644
---
a/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterReference.java
+++
b/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterReference.java
@@ -68,6 +68,6 @@ public class StandardParameterReference implements
ParameterReference {
}
final Optional<Parameter> parameter =
parameterLookup.getParameter(parameterName);
- return parameter.map(Parameter::getValue).orElse(referenceText);
+ return parameter.map(Parameter::getValue).orElse(null);
}
}
diff --git
a/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterTokenList.java
b/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterTokenList.java
index f9c0a0f..3959895 100644
---
a/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterTokenList.java
+++
b/nifi-commons/nifi-parameter/src/main/java/org/apache/nifi/parameter/StandardParameterTokenList.java
@@ -76,12 +76,18 @@ public class StandardParameterTokenList implements
ParameterTokenList {
private String substitute(final Function<ParameterToken, String>
transform) {
final StringBuilder sb = new StringBuilder();
+ int nullCount = 0;
int lastEndOffset = -1;
for (final ParameterToken token : tokens) {
final int startOffset = token.getStartOffset();
sb.append(input, lastEndOffset + 1, startOffset);
- sb.append(transform.apply(token));
+ final String transformed = transform.apply(token);
+ if (transformed == null) {
+ nullCount++;
+ } else {
+ sb.append(transformed);
+ }
lastEndOffset = token.getEndOffset();
}
@@ -90,7 +96,12 @@ public class StandardParameterTokenList implements
ParameterTokenList {
sb.append(input, lastEndOffset + 1, input.length());
}
- return sb.toString();
+ final String substituted = sb.toString();
+ if (nullCount == tokens.size() && !tokens.isEmpty() &&
substituted.isEmpty()) {
+ return null;
+ }
+
+ return substituted;
}
@Override
diff --git
a/nifi-commons/nifi-parameter/src/test/java/org/apache/nifi/parameter/TestStandardParameterTokenList.java
b/nifi-commons/nifi-parameter/src/test/java/org/apache/nifi/parameter/TestStandardParameterTokenList.java
index bfac611..7f5afe7 100644
---
a/nifi-commons/nifi-parameter/src/test/java/org/apache/nifi/parameter/TestStandardParameterTokenList.java
+++
b/nifi-commons/nifi-parameter/src/test/java/org/apache/nifi/parameter/TestStandardParameterTokenList.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Optional;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
public class TestStandardParameterTokenList {
@@ -60,7 +61,7 @@ public class TestStandardParameterTokenList {
Mockito.when(paramContext.getParameter(Mockito.anyString())).thenReturn(Optional.empty());
final StandardParameterTokenList references = new
StandardParameterTokenList("#{foo}", referenceList);
- assertEquals("#{foo}", references.substitute(paramContext));
+ assertNull(references.substitute(paramContext));
}
@Test
diff --git a/nifi-docs/src/main/asciidoc/user-guide.adoc
b/nifi-docs/src/main/asciidoc/user-guide.adoc
index f5647d4..88d9d7f 100644
--- a/nifi-docs/src/main/asciidoc/user-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/user-guide.adoc
@@ -881,7 +881,8 @@ The Add Parameter window has the following settings:
- *Name* - A name that is used to denote the Parameter. Only alpha-numeric
characters (a-z, A-Z, 0-9), hyphens ( - ), underscores ( _ ), periods ( . ),
and spaces are allowed.
-- *Value* - The value that will be used when the Parameter is referenced.
Parameter values do not support Expression Language or embedded parameter
references.
+- *Value* - The value that will be used when the Parameter is referenced. If a
Parameter makes use of the Expression Language, it is important to note that
the Expression Language will be evaluated
+in the context of the component that references the Parameter. Please see the
<<parameters-and-el>> section below for more information.
- *Set empty string* - Check to explicitly set the value of the Parameter to
an empty string. Unchecked by default. (Note: If checked but a value is set,
the checkbox is ignored.)
@@ -900,6 +901,28 @@ image:parameters-validate-affected-components.png[Validate
Affected Components]
The Referencing Components section now lists an aggregation of all the
components referenced by the set of parameters added/edited/deleted, organized
by process group.
+[[parameters-and-el]]
+==== Parameters and Expression Language
+
+When adding a Parameter that makes use of the Expression Language, it is
important to understand the context in which the Expression Language will be
evaluated. The expression is always evaluated
+in the context of the Process or Controller Service that references the
Parameter. Take, for example, a scenario where Parameter with the name `Time`
is added with a value of `${now()}`. The
+Expression Language results in a call to determine the system time when it is
evaluated. When added as a Parameter, the system time is not evaluated when the
Parameter is added, but rather when a
+Processor or Controller Service evaluates the Expression. That is, if a
Processor has a Property whose value is set to `#{Time}` it will function in
exactly the same manner as if the Property's
+value were set to `${now()}`. Each time that the property is referenced, it
will produce a different timestamp.
+
+Furthermore, some Properties do not allow for Expression Language, while
others allow for Expression Language but do not evaluate expressions against
FlowFile attributes. To help understand how
+this works, consider a Parameter named `File` whose value is `${filename}`.
Then consider three different properties, each with a different Expression
Language Scope and a FlowFile whose filename
+is `test.txt`. If each of those Properties is set to `#{File}`, then the
follow table illustrates the resultant value.
+
+|===
+| Configured Property Value | Expression Language Scope | Effective Property
Value | Notes
+
+| #{File} | FlowFile Attributes | test.txt | The filename is resolved by
looking at the `filename` attribute.
+| #{File} | Variable Registry Only | _Empty String_ | FlowFile attributes are
not in scope, and we assume there is no Variable in the Variable Registry named
"filename"
+| #{File} | None | ${filename} | The literal text "${filename}" will be
unevaluated.
+|===
+
+
[[assigning_parameter_context_to_PG]]
==== Assigning a Parameter Context to a Process Group
For a component to reference a Parameter, its Process Group must first be
assigned a Parameter Context. Once assigned, processors and controller services
within that Process Group may only reference Parameters within that Parameter
Context.
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java
index 4cbeb6f..7d48bec 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java
@@ -28,6 +28,7 @@ public class ParameterDTO {
private String description;
private Boolean sensitive;
private String value;
+ private Boolean valueRemoved;
private Set<AffectedComponentEntity> referencingComponents;
@ApiModelProperty("The name of the Parameter")
@@ -66,6 +67,16 @@ public class ParameterDTO {
this.value = value;
}
+ @ApiModelProperty("Whether or not the value of the Parameter was removed.
When a request is made to change a parameter, the value may be null. The
absence of the value may be used either to " +
+ "indicate that the value is not to be changed, or that the value is to
be set to null (i.e., removed). This denotes which of the two scenarios is
being encountered.")
+ public Boolean getValueRemoved() {
+ return valueRemoved;
+ }
+
+ public void setValueRemoved(final Boolean valueRemoved) {
+ this.valueRemoved = valueRemoved;
+ }
+
@ApiModelProperty("The set of all components in the flow that are
referencing this Parameter")
public Set<AffectedComponentEntity> getReferencingComponents() {
return referencingComponents;
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/parameter/StandardParameterContext.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/parameter/StandardParameterContext.java
index 6485827..763e0fd 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/parameter/StandardParameterContext.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/parameter/StandardParameterContext.java
@@ -172,12 +172,7 @@ public class StandardParameterContext implements
ParameterContext {
}
private String getFullyPopulatedValue(final Parameter proposedParameter) {
- if (proposedParameter.getValue() != null) {
- return proposedParameter.getValue();
- }
-
- final Parameter oldParameter =
parameters.get(proposedParameter.getDescriptor());
- return oldParameter == null ? null : oldParameter.getValue();
+ return proposedParameter.getValue();
}
private ParameterDescriptor getFullyPopulatedDescriptor(final Parameter
proposedParameter) {
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
index d7030ef..ca66598 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
@@ -67,7 +67,7 @@ public class StandardProcessContext implements
ProcessContext, ControllerService
properties =
Collections.unmodifiableMap(processorNode.getEffectivePropertyValues());
preparedQueries = new HashMap<>();
- for (final Map.Entry<PropertyDescriptor, String> entry :
processorNode.getRawPropertyValues().entrySet()) {
+ for (final Map.Entry<PropertyDescriptor, String> entry :
properties.entrySet()) {
final PropertyDescriptor desc = entry.getKey();
String value = entry.getValue();
if (value == null) {
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/parameter/TestStandardParameterContext.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/parameter/TestStandardParameterContext.java
index 2be492e..15b268f 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/parameter/TestStandardParameterContext.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/parameter/TestStandardParameterContext.java
@@ -33,6 +33,7 @@ import java.util.Set;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
public class TestStandardParameterContext {
@@ -53,12 +54,12 @@ public class TestStandardParameterContext {
final Parameter abcParam = context.getParameter("abc").get();
assertEquals(abcDescriptor, abcParam.getDescriptor());
- Assert.assertNull(abcParam.getDescriptor().getDescription());
+ assertNull(abcParam.getDescriptor().getDescription());
assertEquals("123", abcParam.getValue());
final Parameter xyzParam = context.getParameter("xyz").get();
assertEquals(xyzDescriptor, xyzParam.getDescriptor());
- Assert.assertNull(xyzParam.getDescriptor().getDescription());
+ assertNull(xyzParam.getDescriptor().getDescription());
assertEquals("242526", xyzParam.getValue());
final Map<String, Parameter> secondParameters = new HashMap<>();
@@ -124,7 +125,7 @@ public class TestStandardParameterContext {
abcParam = context.getParameter("abc").get();
assertEquals(abcDescriptor, abcParam.getDescriptor());
assertEquals("Updated Again",
abcParam.getDescriptor().getDescription());
- assertEquals("321", abcParam.getValue());
+ assertNull(abcParam.getValue());
}
@Test
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
index 9c44f7a..a40c729 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
@@ -673,16 +673,6 @@ public abstract class AbstractComponentNode implements
ComponentNode {
.valid(false)
.explanation("Property references Parameter '" +
paramName + "' but the currently selected Parameter Context does not have a
Parameter with that name")
.build());
-
- continue;
- }
-
- if (!validationContext.isParameterSet(paramName)) {
- results.add(new ValidationResult.Builder()
- .subject(propertyDescriptor.getDisplayName())
- .valid(false)
- .explanation("Property references Parameter '" +
paramName + "' but the currently selected Parameter Context does not have a
value set for that Parameter")
- .build());
}
}
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
index 950da5c..b382930 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
@@ -16,22 +16,6 @@
*/
package org.apache.nifi.controller.serialization;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.connectable.ConnectableType;
@@ -72,6 +56,23 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
/**
* Serializes a Flow Controller as XML to an output stream.
*
@@ -175,11 +176,13 @@ public class StandardFlowSerializer implements
FlowSerializer<Document> {
addStringElement(parameterElement, "description",
descriptor.getDescription());
addStringElement(parameterElement, "sensitive",
String.valueOf(descriptor.isSensitive()));
- if (descriptor.isSensitive()) {
- final String parameterValue = parameter.getValue();
- addStringElement(parameterElement, "value", parameterValue == null
? null : ENC_PREFIX + encryptor.encrypt(parameterValue) + ENC_SUFFIX);
- } else {
- addStringElement(parameterElement, "value", parameter.getValue());
+ if (parameter.getValue() != null) {
+ if (descriptor.isSensitive()) {
+ final String parameterValue = parameter.getValue();
+ addStringElement(parameterElement, "value", parameterValue ==
null ? null : ENC_PREFIX + encryptor.encrypt(parameterValue) + ENC_SUFFIX);
+ } else {
+ addStringElement(parameterElement, "value",
parameter.getValue());
+ }
}
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
index 36d7d92..fd3577b 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
@@ -77,7 +77,7 @@
<xs:element name="name" type="NonEmptyStringType" />
<xs:element name="description" type="xs:string" />
<xs:element name="sensitive" type="xs:boolean" />
- <xs:element name="value" type="xs:string" />
+ <xs:element name="value" type="xs:string" minOccurs="0"
maxOccurs="1" />
</xs:sequence>
</xs:complexType>
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardParameterContextDAO.java
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardParameterContextDAO.java
index bb5ec9a..583806e 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardParameterContextDAO.java
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardParameterContextDAO.java
@@ -40,6 +40,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
public class StandardParameterContextDAO implements ParameterContextDAO {
@@ -57,7 +58,7 @@ public class StandardParameterContextDAO implements
ParameterContextDAO {
@Override
public ParameterContext createParameterContext(final ParameterContextDTO
parameterContextDto) {
- final Map<String, Parameter> parameters =
getParameters(parameterContextDto);
+ final Map<String, Parameter> parameters =
getParameters(parameterContextDto, null);
final ParameterContext parameterContext =
flowManager.createParameterContext(parameterContextDto.getId(),
parameterContextDto.getName(), parameters);
if (parameterContextDto.getDescription() != null) {
parameterContext.setDescription(parameterContextDto.getDescription());
@@ -65,7 +66,7 @@ public class StandardParameterContextDAO implements
ParameterContextDAO {
return parameterContext;
}
- private Map<String, Parameter> getParameters(final ParameterContextDTO
parameterContextDto) {
+ private Map<String, Parameter> getParameters(final ParameterContextDTO
parameterContextDto, final ParameterContext context) {
final Set<ParameterEntity> parameterEntities =
parameterContextDto.getParameters();
if (parameterEntities == null) {
return Collections.emptyMap();
@@ -83,7 +84,7 @@ public class StandardParameterContextDAO implements
ParameterContextDAO {
if (deletion) {
parameterMap.put(parameterDto.getName().trim(), null);
} else {
- final Parameter parameter = createParameter(parameterDto);
+ final Parameter parameter = createParameter(parameterDto,
context);
parameterMap.put(parameterDto.getName().trim(), parameter);
}
}
@@ -91,14 +92,26 @@ public class StandardParameterContextDAO implements
ParameterContextDAO {
return parameterMap;
}
- private Parameter createParameter(final ParameterDTO dto) {
+ private Parameter createParameter(final ParameterDTO dto, final
ParameterContext context) {
final ParameterDescriptor descriptor = new
ParameterDescriptor.Builder()
.name(dto.getName())
.description(dto.getDescription())
.sensitive(Boolean.TRUE.equals(dto.getSensitive()))
.build();
- return new Parameter(descriptor, dto.getValue());
+ final String value;
+ if (dto.getValue() == null &&
Boolean.TRUE.equals(dto.getValueRemoved())) {
+ // Value is being explicitly set to null
+ value = null;
+ } else if (dto.getValue() == null && context != null) {
+ // Value was just never supplied. Use the value from the Parameter
Context, if there is one.
+ final Optional<Parameter> optionalParameter =
context.getParameter(dto.getName());
+ value =
optionalParameter.map(Parameter::getValue).orElse(dto.getValue());
+ } else {
+ value = dto.getValue();
+ }
+
+ return new Parameter(descriptor, value);
}
@Override
@@ -132,7 +145,7 @@ public class StandardParameterContextDAO implements
ParameterContextDAO {
}
if (parameterContextDto.getParameters() != null) {
- final Map<String, Parameter> parameters =
getParameters(parameterContextDto);
+ final Map<String, Parameter> parameters =
getParameters(parameterContextDto, context);
context.setParameters(parameters);
}
diff --git
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js
index c86df4d..7bbe867 100644
---
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js
+++
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-parameter-contexts.js
@@ -270,6 +270,13 @@
// if modified grab what's changed
if (this.hasValueChanged) {
parameter['value'] = this.value;
+
+ if (_.isEmpty(this.value) && !this.isEmptyStringSet) {
+ // No value is set, and the 'Set empty string'
checkbox was not set. The value is expected to be null.
+ // Because sensitive parameter values are not known,
when a sensitive parameter is updated, its value is send back as null.
+ // To disambiguate between a value explicitly being
null, an empty string, and a value not be provided, we need to set the
'valueRemoved' flag.
+ parameter['valueRemoved'] = true;
+ }
}
parameter['description'] = this.description;
@@ -854,12 +861,9 @@
var isSensitive =
$('#parameter-dialog').find('input[name="sensitive"]:checked').val() ===
'sensitive' ? true : false;
var validateValue = function () {
- // updates to a parameter cannot have a null value
- if (!this.isNew) {
- if (_.isEmpty(this.value) && !this.isEmptyStringSet) {
- return false;
- }
- }
+ // in previous versions, updates to a parameter were not allowed
to have a null value.
+ // This has changed, but the validation function is left intact
for now because it is likely that
+ // we may introduce additional validation in the future.
return true;
};
diff --git
a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/EvaluatePropertiesWithDifferentELScopes.java
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/EvaluatePropertiesWithDifferentELScopes.java
new file mode 100644
index 0000000..dfc071b
--- /dev/null
+++
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/EvaluatePropertiesWithDifferentELScopes.java
@@ -0,0 +1,97 @@
+/*
+ * 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.processors.tests.system;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.expression.ExpressionLanguageScope;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.util.StandardValidators;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class EvaluatePropertiesWithDifferentELScopes extends AbstractProcessor
{
+ static final PropertyDescriptor EVALUATE_FLOWFILE_CONTEXT = new
PropertyDescriptor.Builder()
+ .name("FlowFile Context")
+ .description("The value of the property will be evaluated with
FlowFile attributes")
+ .required(false)
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+ .build();
+ static final PropertyDescriptor EVALUATE_VARIABLE_REGISTRY_CONTEXT = new
PropertyDescriptor.Builder()
+ .name("Variable Registry Context")
+ .description("The value of the property will be evaluated with only
with the Variable Registry")
+ .required(false)
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+ .build();
+ static final PropertyDescriptor EVALUATE_NO_EL_CONTEXT = new
PropertyDescriptor.Builder()
+ .name("Expression Language Not Evaluated")
+ .description("The value of the property will be evaluated without
evaluating Expression Language")
+ .required(false)
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .expressionLanguageSupported(ExpressionLanguageScope.NONE)
+ .build();
+
+ public static final Relationship REL_SUCCESS = new Relationship.Builder()
+ .name("success")
+ .build();
+
+ @Override
+ public Set<Relationship> getRelationships() {
+ return Collections.singleton(REL_SUCCESS);
+ }
+
+ @Override
+ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+ return Arrays.asList(EVALUATE_FLOWFILE_CONTEXT,
EVALUATE_VARIABLE_REGISTRY_CONTEXT, EVALUATE_NO_EL_CONTEXT);
+ }
+
+ @Override
+ public void onTrigger(final ProcessContext context, final ProcessSession
session) throws ProcessException {
+ FlowFile flowFile = session.get();
+ if (flowFile == null) {
+ return;
+ }
+
+ final Integer flowFileContext =
context.getProperty(EVALUATE_FLOWFILE_CONTEXT).evaluateAttributeExpressions(flowFile).asInteger();
+ final Integer variableRegistryContext =
context.getProperty(EVALUATE_VARIABLE_REGISTRY_CONTEXT).evaluateAttributeExpressions().asInteger();
+ final String noElContext =
context.getProperty(EVALUATE_NO_EL_CONTEXT).getValue();
+
+ if (flowFileContext != null) {
+ session.adjustCounter("flowfile", flowFileContext, false);
+ }
+
+ if (variableRegistryContext != null) {
+ session.adjustCounter("variable.registry",
variableRegistryContext, false);
+ }
+
+ if (noElContext != null && noElContext.matches("[0-9]+")) {
+ session.adjustCounter("no.el.evaluation",
Integer.parseInt(noElContext), false);
+ }
+
+ session.transfer(flowFile, REL_SUCCESS);
+ }
+}
diff --git
a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/WriteToFile.java
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/WriteToFile.java
new file mode 100644
index 0000000..e5086cc
--- /dev/null
+++
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/processors/tests/system/WriteToFile.java
@@ -0,0 +1,103 @@
+/*
+ * 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.processors.tests.system;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.PropertyDescriptor.Builder;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.stream.io.StreamUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static
org.apache.nifi.expression.ExpressionLanguageScope.FLOWFILE_ATTRIBUTES;
+import static
org.apache.nifi.processor.util.StandardValidators.NON_EMPTY_VALIDATOR;
+
+public class WriteToFile extends AbstractProcessor {
+
+ static final PropertyDescriptor FILENAME = new Builder()
+ .name("Filename")
+ .displayName("Filename")
+ .description("The file to write the FlowFile contents to")
+ .required(true)
+ .addValidator(NON_EMPTY_VALIDATOR)
+ .expressionLanguageSupported(FLOWFILE_ATTRIBUTES)
+ .defaultValue("target/WriteToFile.out")
+ .build();
+
+ static final Relationship REL_SUCCESS = new Relationship.Builder()
+ .name("success")
+ .build();
+
+ static final Relationship REL_FAILURE = new Relationship.Builder()
+ .name("failure")
+ .build();
+
+ @Override
+ public Set<Relationship> getRelationships() {
+ return new HashSet<>(Arrays.asList(REL_SUCCESS, REL_FAILURE));
+ }
+
+ @Override
+ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+ return Collections.singletonList(FILENAME);
+ }
+
+ @Override
+ public void onTrigger(final ProcessContext context, final ProcessSession
session) throws ProcessException {
+ FlowFile flowFile = session.get();
+ if (flowFile == null) {
+ return;
+ }
+
+ final String filename =
context.getProperty(FILENAME).evaluateAttributeExpressions(flowFile).getValue();
+ final File file = new File(filename);
+ final File dir = file.getParentFile();
+ if (!dir.exists() && !dir.mkdirs()) {
+ getLogger().error("Could not write FlowFile to {} because the
directory does not exist and could not be created", file.getAbsolutePath());
+ session.transfer(flowFile, REL_FAILURE);
+ return;
+ }
+
+ try (final OutputStream out = new FileOutputStream(file);
+ final InputStream in = session.read(flowFile)) {
+ StreamUtils.copy(in, out);
+ } catch (final Exception e) {
+ getLogger().error("Could not write FlowFile to {}",
file.getAbsolutePath(), e);
+ session.transfer(flowFile, REL_FAILURE);
+ return;
+ }
+
+ session.transfer(flowFile, REL_SUCCESS);
+
+ getLogger().info("Wrote one FlowFile of size {} to {}",
flowFile.getSize(), file.getAbsolutePath());
+ session.getProvenanceReporter().send(flowFile,
file.toURI().toString());
+ }
+}
diff --git
a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
index ce4347a..169a9c6 100644
---
a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
+++
b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
@@ -17,6 +17,7 @@ org.apache.nifi.processors.tests.system.CountEvents
org.apache.nifi.processors.tests.system.CountFlowFiles
org.apache.nifi.processors.tests.system.DependOnProperties
org.apache.nifi.processors.tests.system.Duplicate
+org.apache.nifi.processors.tests.system.EvaluatePropertiesWithDifferentELScopes
org.apache.nifi.processors.tests.system.FakeProcessor
org.apache.nifi.processors.tests.system.FakeDynamicPropertiesProcessor
org.apache.nifi.processors.tests.system.GenerateFlowFile
@@ -26,3 +27,4 @@ org.apache.nifi.processors.tests.system.Sleep
org.apache.nifi.processors.tests.system.TerminateFlowFile
org.apache.nifi.processors.tests.system.ThrowProcessException
org.apache.nifi.processors.tests.system.ValidateFileExists
+org.apache.nifi.processors.tests.system.WriteToFile
\ No newline at end of file
diff --git
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/parameters/ParameterContextIT.java
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/parameters/ParameterContextIT.java
index 2221789..17f07e1 100644
---
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/parameters/ParameterContextIT.java
+++
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/parameters/ParameterContextIT.java
@@ -31,9 +31,14 @@ import org.apache.nifi.web.api.entity.ProcessGroupEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.junit.Test;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+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.stream.Collectors;
@@ -104,7 +109,7 @@ public class ParameterContextIT extends NiFiSystemIT {
}
- @Test(timeout = 30000)
+ @Test
public void testAddingMissingParameterMakesProcessorValid() throws
NiFiClientException, IOException, InterruptedException {
final ProcessorEntity createdProcessorEntity =
createProcessor(TEST_PROCESSORS_PACKAGE + ".CountEvents", NIFI_GROUP_ID,
TEST_EXTENSIONS_ARTIFACT_ID, getNiFiVersion());
final String processorId = createdProcessorEntity.getId();
@@ -125,6 +130,197 @@ public class ParameterContextIT extends NiFiSystemIT {
}
@Test
+ public void testValidationWithRequiredPropertiesAndDefault() throws
NiFiClientException, IOException, InterruptedException {
+ final ProcessorEntity generate =
getClientUtil().createProcessor("GenerateFlowFile");
+ getClientUtil().updateProcessorProperties(generate,
Collections.singletonMap("File Size", "#{foo}"));
+ getClientUtil().setAutoTerminatedRelationships(generate, "success");
+
+ final String processorId = generate.getId();
+
+ waitForInvalidProcessor(processorId);
+
+ final ParameterEntity fooKB = createParameterEntity("foo", null,
false, "1 KB");
+ final Set<ParameterEntity> parameters = new HashSet<>();
+ parameters.add(fooKB);
+ final ParameterContextEntity contextEntity =
createParameterContextEntity(getTestName(), null, parameters);
+ final ParameterContextEntity createdContextEntity =
getNifiClient().getParamContextClient().createParamContext(contextEntity);
+
+ setParameterContext("root", createdContextEntity);
+ waitForValidProcessor(processorId);
+
+ final ParameterEntity fooNull = createParameterEntity("foo", null,
false, null);
+
createdContextEntity.getComponent().setParameters(Collections.singleton(fooNull));
+
getNifiClient().getParamContextClient().updateParamContext(createdContextEntity);
+ // Should remain valid because property has a default.
+ waitForValidProcessor(processorId);
+ }
+
+ @Test(timeout=30000)
+ public void testValidationWithRequiredPropertiesAndNoDefault() throws
NiFiClientException, IOException, InterruptedException {
+ final ProcessorEntity generate =
getClientUtil().createProcessor("DependOnProperties");
+ final Map<String, String> properties = new HashMap<>();
+ properties.put("Always Required", "#{foo}");
+ properties.put("Required If Always Required Is Bar Or Baz", "15");
+ getClientUtil().updateProcessorProperties(generate, properties);
+ final String processorId = generate.getId();
+
+ waitForInvalidProcessor(processorId);
+
+ final ParameterEntity fooBar = createParameterEntity("foo", null,
false, "bar");
+ final Set<ParameterEntity> parameters = new HashSet<>();
+ parameters.add(fooBar);
+ final ParameterContextEntity contextEntity =
createParameterContextEntity(getTestName(), null, parameters);
+ final ParameterContextEntity createdContextEntity =
getNifiClient().getParamContextClient().createParamContext(contextEntity);
+
+ setParameterContext("root", createdContextEntity);
+ waitForValidProcessor(processorId);
+
+ final ParameterEntity fooNull = createParameterEntity("foo", null,
false, null);
+
createdContextEntity.getComponent().setParameters(Collections.singleton(fooNull));
+
getNifiClient().getParamContextClient().updateParamContext(createdContextEntity);
+ // Should become invalid because property is required and has no
default
+ waitForInvalidProcessor(processorId);
+ }
+
+ @Test
+ public void testParametersReferencingEL() throws NiFiClientException,
IOException, InterruptedException {
+ final ProcessorEntity generate =
getClientUtil().createProcessor("GenerateFlowFile");
+ getClientUtil().updateProcessorProperties(generate,
Collections.singletonMap("a", "1"));
+ getClientUtil().updateProcessorSchedulingPeriod(generate, "10 min");
+
+ final ProcessorEntity evaluate =
getClientUtil().createProcessor("EvaluatePropertiesWithDifferentELScopes");
+ final Map<String, String> evaluateProperties = new HashMap<>();
+ evaluateProperties.put("FlowFile Context", "#{A}");
+ evaluateProperties.put("Variable Registry Context", "#{A Replace With
5}");
+ evaluateProperties.put("Expression Language Not Evaluated", "#{Eleven
A}");
+ getClientUtil().updateProcessorProperties(evaluate,
evaluateProperties);
+
+ getClientUtil().createConnection(generate, evaluate, "success");
+ getClientUtil().setAutoTerminatedRelationships(evaluate, "success");
+
+ final Set<ParameterEntity> parameters = new HashSet<>();
+ parameters.add(createParameterEntity("A", null, false, "${a}"));
+ parameters.add(createParameterEntity("A Replace With 5", null, false,
"${a:replaceNull(5)}"));
+ parameters.add(createParameterEntity("Eleven A", null, false,
"11${a}"));
+ final ParameterContextEntity contextEntity =
createParameterContextEntity(getTestName(), null, parameters);
+ final ParameterContextEntity createdContextEntity =
getNifiClient().getParamContextClient().createParamContext(contextEntity);
+
+ setParameterContext("root", createdContextEntity);
+
+ waitForValidProcessor(generate.getId());
+ waitForValidProcessor(evaluate.getId());
+
+ getClientUtil().startProcessGroupComponents("root");
+
+ waitFor(() -> {
+ try {
+ return
getClientUtil().getCountersAsMap(evaluate.getId()).get("flowfile") ==
getNumberOfNodes();
+ } catch (final Exception e) {
+ return false;
+ }
+ });
+
+ final Map<String, Long> counters =
getClientUtil().getCountersAsMap(evaluate.getId());
+ assertEquals(getNumberOfNodes(), counters.get("flowfile").longValue());
+ assertEquals(5L * getNumberOfNodes(),
counters.get("variable.registry").longValue()); // Since no value present in
variable registry, will replace null with 5.
+ assertFalse(counters.containsKey("no.el.evaluation")); // Should not
be evaluated
+
+ // Update parameters so that Eleven A has the value 11 without
evaluating EL.
+ final Set<ParameterEntity> updatedParameters = new HashSet<>();
+ updatedParameters.add(createParameterEntity("A", null, false, "${a}"));
+ updatedParameters.add(createParameterEntity("A Replace With 5", null,
false, "${a:replaceNull(5)}"));
+ updatedParameters.add(createParameterEntity("Eleven A", null, false,
"11"));
+ final ParameterContextEntity updatedContextEntity =
createParameterContextEntity(getTestName() + "-2", null, updatedParameters);
+ final ParameterContextEntity secondContextEntity =
getNifiClient().getParamContextClient().createParamContext(updatedContextEntity);
+
+ // Stop process group so we can change the Parameter Context, then
change the context and restart.
+ getClientUtil().stopProcessGroupComponents("root");
+ setParameterContext("root", secondContextEntity);
+ getClientUtil().startProcessGroupComponents("root");
+
+ // Wait for the 'no.el.evaluation' counter to be set
+ waitFor(() -> {
+ try {
+ return
getClientUtil().getCountersAsMap(evaluate.getId()).get("no.el.evaluation") ==
11 * getNumberOfNodes();
+ } catch (final Exception e) {
+ return false;
+ }
+ });
+ }
+
+ @Test
+ public void testParameterWithOptionalProperty() throws
NiFiClientException, IOException, InterruptedException {
+ final ProcessorEntity generate =
getClientUtil().createProcessor("GenerateFlowFile");
+ getClientUtil().updateProcessorSchedulingPeriod(generate, "10 min");
+
+ final Map<String, String> generateProperties = new HashMap<>();
+ generateProperties.put("Text", "#{Text}");
+ generateProperties.put("File Size", "1 KB");
+ getClientUtil().updateProcessorProperties(generate,
generateProperties);
+
+ final ProcessorEntity writeFile =
getClientUtil().createProcessor("WriteToFile");
+ final File file = new
File("target/testParameterWithOptionalProperty.txt");
+ getClientUtil().updateProcessorProperties(writeFile,
Collections.singletonMap("Filename", file.getAbsolutePath()));
+
+ getClientUtil().createConnection(generate, writeFile, "success");
+ getClientUtil().setAutoTerminatedRelationships(writeFile, new
HashSet<>(Arrays.asList("success", "failure")));
+
+ final Set<ParameterEntity> parameters = new HashSet<>();
+ final ParameterContextEntity contextEntity =
createParameterContextEntity(getTestName(), null, parameters);
+ final ParameterContextEntity createdContextEntity =
getNifiClient().getParamContextClient().createParamContext(contextEntity);
+
+ setParameterContext("root", createdContextEntity);
+
+ // Processor should be invalid because it references a Parameter
(Text) that does not exist
+ waitForInvalidProcessor(generate.getId());
+
+ // Update the Parameter Context to add new parameter but with null
value.
+ final ParameterEntity nullText = createParameterEntity("Text", "Text",
false, null);
+ createdContextEntity.getComponent().getParameters().add(nullText);
+
getNifiClient().getParamContextClient().updateParamContext(createdContextEntity);
+
+ waitForValidProcessor(generate.getId());
+
+ getClientUtil().startProcessGroupComponents("root");
+
+ // Ensure that the file is written with a file size of 1 KB
+ waitFor(() -> {
+ try {
+ return file.exists() && file.length() == 1024;
+ } catch (final Exception e) {
+ return false;
+ }
+ });
+
+ // Update Parameter to have a specific value
+ createdContextEntity.getComponent().getParameters().remove(nullText);
+ final String customText = "Some Custom Text";
+
createdContextEntity.getComponent().getParameters().add(createParameterEntity("Text",
"Text", false, customText));
+
+
getNifiClient().getParamContextClient().updateParamContext(createdContextEntity);
+
+ // Wait for file to be written out
+ waitFor(() -> {
+ try {
+ final boolean correctSize = file.exists() && file.length() ==
customText.length();
+ if (!correctSize) {
+ return false;
+ }
+
+ final List<String> lines = Files.readAllLines(file.toPath());
+ if (lines.size() != 1) {
+ return false;
+ }
+
+ return customText.equals(lines.get(0));
+ } catch (final Exception e) {
+ return false;
+ }
+ });
+
+ }
+
+ @Test
public void testProcessorStartedAfterLongValidationPeriod() throws
NiFiClientException, IOException, InterruptedException {
final ParameterContextEntity createdContextEntity =
createParameterContext("sleep", "6 secs");