This is an automated email from the ASF dual-hosted git repository. markap14 pushed a commit to branch NIFI-15258 in repository https://gitbox.apache.org/repos/asf/nifi-api.git
commit 3e46ab96b680669d731f904e663f5dcb51d90726 Author: Mark Payne <[email protected]> AuthorDate: Fri Dec 12 18:00:53 2025 -0500 NIFI-15312: Moved SecretsProvider / SecretsManager to framework instead of api; added description to Secret and updated ParameterProvider to allow more specific fetching of parameters; cleaned up Connector validation logic (#29) --- .../components/connector/AbstractConnector.java | 72 ++++++++++------------ .../connector/ConnectorPropertyDescriptor.java | 19 ++++++ .../apache/nifi/components/connector/Secret.java | 2 + .../nifi/components/connector/SecretProvider.java | 33 ---------- .../nifi/components/connector/SecretsManager.java | 33 ---------- .../apache/nifi/parameter/ParameterProvider.java | 55 +++++++++++++++++ 6 files changed, 109 insertions(+), 105 deletions(-) diff --git a/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java b/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java index 4cfac54..6db3acc 100644 --- a/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java +++ b/src/main/java/org/apache/nifi/components/connector/AbstractConnector.java @@ -283,25 +283,41 @@ public abstract class AbstractConnector implements Connector { } @Override - public List<ValidationResult> validate(final FlowContext context, final ConnectorValidationContext validationContext) { - final List<ValidationResult> validationResults = new ArrayList<>(); - validate(context, context.getRootGroup(), validationContext, validationResults); - return validationResults; - } + public List<ValidationResult> validate(final FlowContext flowContext, final ConnectorValidationContext validationContext) { + final ConnectorConfigurationContext configContext = flowContext.getConfigurationContext(); + final List<ValidationResult> results = new ArrayList<>(); + final List<ConfigurationStep> configurationSteps = getConfigurationSteps(flowContext); - private void validate(final FlowContext context, final ProcessGroupFacade group, final ConnectorValidationContext validationContext, final List<ValidationResult> validationResults) { - final List<ValidationResult> connectorPropertiesResults = validate(context, context.getConfigurationContext(), validationContext); - if (!connectorPropertiesResults.isEmpty()) { - connectorPropertiesResults.stream() - .filter(result -> !result.isValid()) - .forEach(validationResults::add); + for (final ConfigurationStep configurationStep : configurationSteps) { + results.addAll(validateConfigurationStep(configurationStep, configContext, validationContext)); + } - // If any invalid results on the connector configuration itself, do not proceed with further validation of components - if (!validationResults.isEmpty()) { - return; + // only run customValidate if regular validation is successful. This allows Processor developers to not have to check + // if values are null or invalid so that they can focus only on the interaction between the properties, etc. + if (results.isEmpty()) { + final Collection<ValidationResult> customResults = customValidate(configContext); + if (customResults != null) { + for (final ValidationResult result : customResults) { + if (!result.isValid()) { + results.add(result); + } + } } } + return results; + } + + + protected List<ValidationResult> validateComponents(final FlowContext context, final ProcessGroupFacade group, final ConnectorValidationContext validationContext) { + final List<ValidationResult> validationResults = new ArrayList<>(); + validateComponents(context, group, validationContext, validationResults); + return validationResults; + } + + private void validateComponents(final FlowContext context, final ProcessGroupFacade group, final ConnectorValidationContext validationContext, + final List<ValidationResult> validationResults) { + for (final ProcessorFacade processor : group.getProcessors()) { final List<ValidationResult> processorResults = processor.validate(); for (final ValidationResult result : processorResults) { @@ -339,7 +355,7 @@ public abstract class AbstractConnector implements Connector { } for (final ProcessGroupFacade childGroup : group.getProcessGroups()) { - validate(context, childGroup, validationContext, validationResults); + validateComponents(context, childGroup, validationContext, validationResults); } } @@ -425,33 +441,11 @@ public abstract class AbstractConnector implements Connector { } } - private List<ValidationResult> validate(final FlowContext workingContext, final ConnectorConfigurationContext context, final ConnectorValidationContext validationContext) { - final List<ValidationResult> results = new ArrayList<>(); - final List<ConfigurationStep> configurationSteps = getConfigurationSteps(workingContext); - - for (final ConfigurationStep configurationStep : configurationSteps) { - results.addAll(validateConfigurationStep(configurationStep, context, validationContext)); - } - - // only run customValidate if regular validation is successful. This allows Processor developers to not have to check - // if values are null or invalid so that they can focus only on the interaction between the properties, etc. - if (results.isEmpty()) { - final Collection<ValidationResult> customResults = customValidate(context); - if (customResults != null) { - for (final ValidationResult result : customResults) { - if (!result.isValid()) { - results.add(result); - } - } - } - } - - return results; - } @Override public List<ValidationResult> validateConfigurationStep(final ConfigurationStep configurationStep, final ConnectorConfigurationContext configurationContext, - final ConnectorValidationContext validationContext) { + final ConnectorValidationContext validationContext) { + final String stepName = configurationStep.getName(); final List<ValidationResult> results = new ArrayList<>(); diff --git a/src/main/java/org/apache/nifi/components/connector/ConnectorPropertyDescriptor.java b/src/main/java/org/apache/nifi/components/connector/ConnectorPropertyDescriptor.java index f765d11..209039b 100644 --- a/src/main/java/org/apache/nifi/components/connector/ConnectorPropertyDescriptor.java +++ b/src/main/java/org/apache/nifi/components/connector/ConnectorPropertyDescriptor.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -210,6 +211,24 @@ public final class ConnectorPropertyDescriptor { .build(); } + @Override + public boolean equals(final Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + final ConnectorPropertyDescriptor that = (ConnectorPropertyDescriptor) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hashCode(name); + } + + @Override + public String toString() { + return "ConnectorPropertyDescriptor[name=" + name + "]"; + } public static final class Builder { private String name; diff --git a/src/main/java/org/apache/nifi/components/connector/Secret.java b/src/main/java/org/apache/nifi/components/connector/Secret.java index 4d6e8c5..5b50ea4 100644 --- a/src/main/java/org/apache/nifi/components/connector/Secret.java +++ b/src/main/java/org/apache/nifi/components/connector/Secret.java @@ -25,6 +25,8 @@ public interface Secret { String getName(); + String getDescription(); + String getValue(); } diff --git a/src/main/java/org/apache/nifi/components/connector/SecretProvider.java b/src/main/java/org/apache/nifi/components/connector/SecretProvider.java deleted file mode 100644 index 22849a5..0000000 --- a/src/main/java/org/apache/nifi/components/connector/SecretProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.components.connector; - -import java.io.IOException; -import java.util.List; - -public interface SecretProvider { - - String getProviderId(); - - String getProviderName(); - - List<Secret> getAllSecrets() throws IOException; - - List<Secret> getSecrets(List<String> fullyQualifiedSecretNames) throws IOException; - -} diff --git a/src/main/java/org/apache/nifi/components/connector/SecretsManager.java b/src/main/java/org/apache/nifi/components/connector/SecretsManager.java deleted file mode 100644 index 564b717..0000000 --- a/src/main/java/org/apache/nifi/components/connector/SecretsManager.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.components.connector; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -public interface SecretsManager { - - Optional<Secret> getSecret(SecretReference secretReference) throws IOException; - - List<Secret> getAllSecrets() throws IOException; - - Set<SecretProvider> getSecretProviders(); - -} diff --git a/src/main/java/org/apache/nifi/parameter/ParameterProvider.java b/src/main/java/org/apache/nifi/parameter/ParameterProvider.java index f97d529..a2f3dd0 100644 --- a/src/main/java/org/apache/nifi/parameter/ParameterProvider.java +++ b/src/main/java/org/apache/nifi/parameter/ParameterProvider.java @@ -23,7 +23,10 @@ import org.apache.nifi.migration.PropertyConfiguration; import org.apache.nifi.reporting.InitializationException; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Defines a provider that is responsible for fetching from an external source Parameters with @@ -102,4 +105,56 @@ public interface ParameterProvider extends ConfigurableComponent { */ default void migrateProperties(PropertyConfiguration config) { } + + /** + * Fetches named groups of parameters from an external source, filtering to only include the specified parameter names. + * It is up to the implementation to determine how a fully qualified parameter name maps to a group and parameter name + * and to optimize the fetching accordingly. The default implementation fetches all parameters and filters them, assuming + * that the fully qualified parameter name is of the form "GroupName.ParameterName". + * + * @param context The <code>ConfigurationContext</code>for the provider + * @param fullyQualifiedParameterNames the fully qualified names of the parameters to fetch + * @return A list of fetched Parameter groups containing only the specified parameters + * @throws IOException if there is an I/O problem while fetching the Parameters + */ + default List<ParameterGroup> fetchParameters(ConfigurationContext context, List<String> fullyQualifiedParameterNames) throws IOException { + final List<ParameterGroup> allGroups = fetchParameters(context); + final List<ParameterGroup> filteredGroups = new ArrayList<>(); + + for (final ParameterGroup group : allGroups) { + // Determine which parameter names are desired from this group + final List<String> desiredParameterNames = new ArrayList<>(); + final String prefix = group.getGroupName() + "."; + for (final String fullyQualifiedParameterName : fullyQualifiedParameterNames) { + if (fullyQualifiedParameterName.startsWith(prefix)) { + final String secretName = fullyQualifiedParameterName.substring(prefix.length()); + desiredParameterNames.add(secretName); + } + } + + // If no parameters are desired from this group, skip it + if (desiredParameterNames.isEmpty()) { + continue; + } + + // Create a HashSet for quick lookup + final Set<String> parameterNameSet = new HashSet<>(desiredParameterNames); + final List<Parameter> filteredParameters = new ArrayList<>(); + for (final Parameter parameter : group.getParameters()) { + if (!parameterNameSet.contains(parameter.getDescriptor().getName())) { + continue; + } + + filteredParameters.add(parameter); + } + + // If we found any desired parameters, add them to the result + if (!filteredParameters.isEmpty()) { + filteredGroups.add(new ParameterGroup(group.getGroupName(), filteredParameters)); + } + } + + // Return the filtered groups + return filteredGroups; + } }
