This is an automated email from the ASF dual-hosted git repository.
pvillard31 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 c7fa678a12c NIFI-16324 Include property defaults during Connector
Verify Configuration (#11651)
c7fa678a12c is described below
commit c7fa678a12c0a9e5c5774bb2590c85bdc76162bc
Author: Mark Payne <[email protected]>
AuthorDate: Wed Sep 9 05:57:14 2026 -0400
NIFI-16324 Include property defaults during Connector Verify Configuration
(#11651)
---
.../connector/StandardConnectorNode.java | 34 ++++++++++++++++-
.../connector/TestStandardConnectorNode.java | 43 ++++++++++++++++++++++
2 files changed, 75 insertions(+), 2 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
index 06b87484e8e..6a883dd710d 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
@@ -1669,6 +1669,7 @@ public class StandardConnectorNode implements
ConnectorNode, GroupedComponent {
final Map<String, String> resolvedProperties = new HashMap<>();
final Map<String, ConnectorPropertyDescriptor> descriptorLookup =
buildPropertyDescriptorLookup(configurationStep);
+ final StepConfiguration effectiveConfiguration =
createEffectiveStepConfiguration(configurationStep.getName(),
configurationOverrides);
try {
// Secret References can be expensive to lookup so we don't want
to call getSecret() for each one. Instead, we
@@ -1680,7 +1681,7 @@ public class StandardConnectorNode implements
ConnectorNode, GroupedComponent {
.filter(entry -> !isEmptySecretReference((SecretReference)
entry.getValue()))
.filter(entry -> {
final ConnectorPropertyDescriptor descriptor =
descriptorLookup.get(entry.getKey());
- return descriptor == null ||
isPropertyDependencySatisfied(descriptor, descriptorLookup::get,
configurationOverrides);
+ return descriptor == null ||
isPropertyDependencySatisfied(descriptor, descriptorLookup::get,
effectiveConfiguration);
})
.map(entry -> (SecretReference) entry.getValue())
.collect(Collectors.toSet());
@@ -1703,7 +1704,7 @@ public class StandardConnectorNode implements
ConnectorNode, GroupedComponent {
}
final ConnectorPropertyDescriptor descriptor =
descriptorLookup.get(propertyName);
- if (descriptor != null &&
!isPropertyDependencySatisfied(descriptor, descriptorLookup::get,
configurationOverrides)) {
+ if (descriptor != null &&
!isPropertyDependencySatisfied(descriptor, descriptorLookup::get,
effectiveConfiguration)) {
// Omit values for properties that are not applicable so
merged configuration does not retain stale overrides
// (createWithOverrides removes keys when the override
value is null).
resolvedProperties.put(propertyName, null);
@@ -1733,6 +1734,14 @@ public class StandardConnectorNode implements
ConnectorNode, GroupedComponent {
invalidAssetRefs.add((AssetReference) valueReference);
}
}
+
+ for (final ConnectorPropertyDescriptor descriptor :
descriptorLookup.values()) {
+ if (descriptor.getDefaultValue() != null
+ &&
!effectiveConfiguration.getPropertyValues().containsKey(descriptor.getName())
+ && isPropertyDependencySatisfied(descriptor,
descriptorLookup::get, effectiveConfiguration)) {
+ resolvedProperties.put(descriptor.getName(),
descriptor.getDefaultValue());
+ }
+ }
} catch (final IOException ioe) {
throw new UncheckedIOException("Failed to resolve Secret
references for " + this, ioe);
}
@@ -1740,6 +1749,27 @@ public class StandardConnectorNode implements
ConnectorNode, GroupedComponent {
return resolvedProperties;
}
+ private StepConfiguration createEffectiveStepConfiguration(final String
stepName, final StepConfiguration configurationOverrides) {
+ final Map<String, ConnectorValueReference> effectiveProperties = new
HashMap<>();
+ final NamedStepConfiguration workingStepConfiguration =
workingFlowContext.getConfigurationContext()
+ .toConnectorConfiguration()
+ .getNamedStepConfiguration(stepName);
+ if (workingStepConfiguration != null) {
+
effectiveProperties.putAll(workingStepConfiguration.configuration().getPropertyValues());
+ }
+
+ for (final Map.Entry<String, ConnectorValueReference> entry :
configurationOverrides.getPropertyValues().entrySet()) {
+ final ConnectorValueReference valueReference = entry.getValue();
+ if (valueReference == null || valueReference instanceof final
StringLiteralValue stringLiteralValue && stringLiteralValue.getValue() == null)
{
+ effectiveProperties.remove(entry.getKey());
+ } else {
+ effectiveProperties.put(entry.getKey(), valueReference);
+ }
+ }
+
+ return new StepConfiguration(effectiveProperties);
+ }
+
private static Map<String, ConnectorPropertyDescriptor>
buildPropertyDescriptorLookup(final ConfigurationStep configurationStep) {
final Map<String, ConnectorPropertyDescriptor> lookup = new
HashMap<>();
for (final ConnectorPropertyGroup propertyGroup :
configurationStep.getPropertyGroups()) {
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
index f96b2e9af75..d729c888e72 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
@@ -775,6 +775,28 @@ public class TestStandardConnectorNode {
assertEquals("The property value is invalid",
failedResult.getExplanation());
}
+ @Test
+ public void
testVerifyConfigurationStepIncludesApplicableDefaultsAndExplicitOverrides()
throws FlowUpdateException {
+ final DefaultValueVerifyingConnector connector = new
DefaultValueVerifyingConnector();
+ final StandardConnectorNode connectorNode =
createConnectorNode(connector);
+
+ connectorNode.transitionStateForUpdating();
+ connectorNode.prepareForUpdate();
+ connectorNode.setConfiguration("settings", new
StepConfiguration(Map.of("Greeting", new StringLiteralValue("Hello"))));
+ final List<ConfigVerificationResult> results =
connectorNode.verifyConfigurationStep(
+ "settings", new StepConfiguration(Map.of("Greeting", new
StringLiteralValue("Welcome"))));
+
+ assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL,
results.getFirst().getOutcome());
+ assertEquals("Welcome", connector.getVerifiedGreeting());
+ assertEquals("1", connector.getVerifiedRepeatCount());
+
+ connectorNode.setConfiguration("settings", new
StepConfiguration(Map.of("Repeat Count", new StringLiteralValue("2"))));
+ connectorNode.verifyConfigurationStep("settings", new
StepConfiguration(Map.of("Greeting", new StringLiteralValue("Hello again"))));
+
+ assertEquals("Hello again", connector.getVerifiedGreeting());
+ assertEquals("2", connector.getVerifiedRepeatCount());
+ }
+
@Test
public void
testVerifyConfigurationStepSkipsSecretReferenceWhenPropertyDependenciesNotMet()
throws FlowUpdateException {
// Use a SecretsManager that fails the test if it is consulted. This
isolates the dependency-skip path: a regression
@@ -1883,6 +1905,27 @@ public class TestStandardConnectorNode {
}
}
+ private static class DefaultValueVerifyingConnector extends
DefaultValueConnector {
+ private String verifiedGreeting;
+ private String verifiedRepeatCount;
+
+ @Override
+ public List<ConfigVerificationResult> verifyConfigurationStep(final
String stepName, final Map<String, String> overrides, final FlowContext
flowContext) {
+ final ConnectorConfigurationContext configurationContext =
flowContext.getConfigurationContext().createWithOverrides(stepName, overrides);
+ verifiedGreeting = configurationContext.getProperty(stepName,
"Greeting").getValue();
+ verifiedRepeatCount = configurationContext.getProperty(stepName,
"Repeat Count").getValue();
+ return List.of();
+ }
+
+ public String getVerifiedGreeting() {
+ return verifiedGreeting;
+ }
+
+ public String getVerifiedRepeatCount() {
+ return verifiedRepeatCount;
+ }
+ }
+
private static class DependentDefaultValueConnector extends
AbstractConnector {
@Override
public VersionedExternalFlow getInitialFlow() {