exceptionfactory commented on code in PR #5369:
URL: https://github.com/apache/nifi/pull/5369#discussion_r957459294


##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/parameter/StandardParameterProviderNode.java:
##########
@@ -0,0 +1,609 @@
+/*
+ * 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.parameter;
+
+import org.apache.nifi.annotation.behavior.Restricted;
+import org.apache.nifi.annotation.documentation.DeprecationNotice;
+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.Bundle;
+import org.apache.nifi.bundle.BundleCoordinate;
+import org.apache.nifi.components.ClassloaderIsolationKeyProvider;
+import org.apache.nifi.components.ConfigVerificationResult;
+import org.apache.nifi.components.ConfigVerificationResult.Outcome;
+import org.apache.nifi.components.ConfigurableComponent;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.components.validation.ValidationStatus;
+import org.apache.nifi.components.validation.ValidationTrigger;
+import org.apache.nifi.controller.AbstractComponentNode;
+import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.controller.LoggableComponent;
+import org.apache.nifi.controller.ParameterProviderNode;
+import org.apache.nifi.controller.ParametersApplication;
+import org.apache.nifi.controller.ReloadComponent;
+import org.apache.nifi.controller.TerminationAwareLogger;
+import org.apache.nifi.controller.ValidationContextFactory;
+import org.apache.nifi.controller.service.ControllerServiceProvider;
+import org.apache.nifi.controller.service.StandardConfigurationContext;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.InstanceClassLoader;
+import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.parameter.Parameter;
+import org.apache.nifi.parameter.ParameterContext;
+import org.apache.nifi.parameter.ParameterDescriptor;
+import org.apache.nifi.parameter.ParameterGroup;
+import org.apache.nifi.parameter.ParameterGroupConfiguration;
+import org.apache.nifi.parameter.ParameterLookup;
+import org.apache.nifi.parameter.ParameterProvider;
+import org.apache.nifi.parameter.ParameterSensitivity;
+import org.apache.nifi.parameter.VerifiableParameterProvider;
+import org.apache.nifi.registry.ComponentVariableRegistry;
+import org.apache.nifi.util.CharacterFilterUtils;
+import org.apache.nifi.util.FormatUtils;
+import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
+
+import java.io.IOException;
+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.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class StandardParameterProviderNode extends AbstractComponentNode 
implements ParameterProviderNode {
+
+    private static final Pattern PARAMETER_NAME_PATTERN = 
Pattern.compile("^[a-zA-Z0-9-_. ]+$");
+
+    private final AtomicReference<ParameterProviderDetails> 
parameterProviderRef;
+    private final ControllerServiceLookup serviceLookup;
+
+    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
+    private final Lock readLock = rwLock.readLock();
+    private final Lock writeLock = rwLock.writeLock();
+
+    private final Set<ParameterContext> referencingParameterContexts;
+
+    private final List<ParameterGroup> fetchedParameterGroups = new 
ArrayList<>();
+
+    private volatile String comment;
+
+    private final Authorizable parentAuthorizable;
+
+    public StandardParameterProviderNode(final 
LoggableComponent<ParameterProvider> parameterProvider, final String id, final 
Authorizable parentAuthorizable,
+                                         final ControllerServiceProvider 
controllerServiceProvider, final ValidationContextFactory 
validationContextFactory,
+                                         final ComponentVariableRegistry 
variableRegistry, final ReloadComponent reloadComponent, final ExtensionManager 
extensionManager,
+                                         final ValidationTrigger 
validationTrigger) {
+
+        this(parameterProvider, id, parentAuthorizable, 
controllerServiceProvider, validationContextFactory,
+                parameterProvider.getComponent().getClass().getSimpleName(), 
parameterProvider.getComponent().getClass().getCanonicalName(),
+                variableRegistry, reloadComponent, extensionManager, 
validationTrigger, false);
+    }
+
+    public StandardParameterProviderNode(final 
LoggableComponent<ParameterProvider> parameterProvider, final String id, final 
Authorizable parentAuthorizable,
+                                         final ControllerServiceProvider 
controllerServiceProvider, final ValidationContextFactory 
validationContextFactory,
+                                         final String componentType, final 
String canonicalClassName, final ComponentVariableRegistry variableRegistry,
+                                         final ReloadComponent 
reloadComponent, final ExtensionManager extensionManager, final 
ValidationTrigger validationTrigger, final boolean isExtensionMissing) {
+        super(id, validationContextFactory, controllerServiceProvider, 
componentType, canonicalClassName, variableRegistry, reloadComponent,
+                extensionManager, validationTrigger, isExtensionMissing);
+        this.parameterProviderRef = new AtomicReference<>(new 
ParameterProviderDetails(parameterProvider));
+        this.serviceLookup = controllerServiceProvider;
+        this.referencingParameterContexts = new HashSet<>();
+        this.parentAuthorizable = parentAuthorizable;
+    }
+
+    @Override
+    public Authorizable getParentAuthorizable() {
+        return parentAuthorizable;
+    }
+
+    @Override
+    public Resource getResource() {
+        return 
ResourceFactory.getComponentResource(ResourceType.ParameterProvider, 
getIdentifier(), getName());
+    }
+
+    @Override
+    public boolean isRestricted() {
+        return 
getParameterProvider().getClass().isAnnotationPresent(Restricted.class);
+    }
+
+    @Override
+    public Class<?> getComponentClass() {
+        return getParameterProvider().getClass();
+    }
+
+    @Override
+    public boolean isDeprecated() {
+        return 
getParameterProvider().getClass().isAnnotationPresent(DeprecationNotice.class);
+    }
+
+    @Override
+    protected ParameterContext getParameterContext() {
+        return null;
+    }
+    @Override
+    public ConfigurableComponent getComponent() {
+        return parameterProviderRef.get().getParameterProvider();
+    }
+
+    @Override
+    public BundleCoordinate getBundleCoordinate() {
+        return parameterProviderRef.get().getBundleCoordinate();
+    }
+
+    @Override
+    public TerminationAwareLogger getLogger() {
+        return parameterProviderRef.get().getComponentLog();
+    }
+
+    @Override
+    public ParameterProvider getParameterProvider() {
+        return parameterProviderRef.get().getParameterProvider();
+    }
+
+    @Override
+    public void setParameterProvider(final 
LoggableComponent<ParameterProvider> parameterProvider) {
+        this.parameterProviderRef.set(new 
ParameterProviderDetails(parameterProvider));
+    }
+
+    @Override
+    public void reload(final Set<URL> additionalUrls) throws 
ParameterProviderInstantiationException {
+        final String additionalResourcesFingerprint = 
ClassLoaderUtils.generateAdditionalUrlsFingerprint(additionalUrls, 
determineClasloaderIsolationKey());
+        setAdditionalResourcesFingerprint(additionalResourcesFingerprint);
+        getReloadComponent().reload(this, getCanonicalClassName(), 
getBundleCoordinate(), additionalUrls);
+    }
+
+    @Override
+    public boolean isValidationNecessary() {
+        return true;
+    }
+
+    @Override
+    public ConfigurationContext getConfigurationContext() {
+        return new StandardConfigurationContext(this, serviceLookup, null, 
getVariableRegistry());
+    }
+
+    @Override
+    public void verifyModifiable() throws IllegalStateException {
+
+    }
+
+    @Override
+    public String getComments() {
+        return comment;
+    }
+
+    @Override
+    public void setComments(final String comment) {
+        this.comment = 
CharacterFilterUtils.filterInvalidXmlCharacters(comment);
+    }
+
+    @Override
+    public void verifyCanClearState() {
+
+    }
+
+    @Override
+    public String toString() {
+        return "ParameterProvider[id=" + getIdentifier() + "]";
+    }
+
+    @Override
+    public String getProcessGroupIdentifier() {
+        return null;
+    }
+
+    @Override
+    public ParameterLookup getParameterLookup() {
+        return ParameterLookup.EMPTY;
+    }
+
+    @Override
+    public Set<ParameterContext> getReferences() {
+        readLock.lock();
+        try {
+            return Collections.unmodifiableSet(referencingParameterContexts);
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    public void addReference(final ParameterContext reference) {
+        writeLock.lock();
+        try {
+            referencingParameterContexts.add(reference);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    public void removeReference(final ParameterContext reference) {
+        writeLock.lock();
+        try {
+            referencingParameterContexts.remove(reference);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    @Override
+    protected List<ValidationResult> validateConfig() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void verifyCanFetchParameters() {
+        final ValidationStatus validationStatus = performValidation();
+        if (validationStatus != ValidationStatus.VALID) {
+            throw new IllegalStateException(String.format("Parameter Provider 
[%s] cannot fetch parameters while validation state is %s",
+                    getIdentifier(), validationStatus));
+        }
+    }
+
+    @Override
+    public void fetchParameters() {
+        final ParameterProvider parameterProvider = 
parameterProviderRef.get().getParameterProvider();
+        final ConfigurationContext configurationContext = 
getConfigurationContext();
+        List<ParameterGroup> fetchedParameterGroups;
+        try (final NarCloseable narCloseable = 
NarCloseable.withComponentNarLoader(getExtensionManager(), 
parameterProvider.getClass(), parameterProvider.getIdentifier())) {
+            fetchedParameterGroups = 
parameterProvider.fetchParameters(configurationContext);
+        } catch (final IOException e) {
+            throw new RuntimeException(String.format("Error fetching 
parameters for Parameter Provider [%s]", getName()), e);
+        }
+
+        if (fetchedParameterGroups == null || 
fetchedParameterGroups.isEmpty()) {
+            return;
+        }
+
+        final Set<String> parameterGroupNames = new HashSet<>();
+
+        writeLock.lock();
+        try {
+            this.fetchedParameterGroups.clear();
+            for (final ParameterGroup group : fetchedParameterGroups) {
+                final String groupName = group.getGroupName();
+                if (parameterGroupNames.contains(groupName)) {
+                    throw new IllegalStateException(String.format("Parameter 
group [%s] is provided twice, which is not allowed", groupName));
+                }
+                final Collection<Parameter> parameters = group.getParameters();
+
+                if (parameters == null) {
+                    continue;
+                }
+                final List<Parameter> validParameters = new ArrayList<>();
+                final Set<String> parameterNames = new HashSet<>();
+                for (final Parameter parameter : parameters) {
+                    final ParameterDescriptor descriptor = 
parameter.getDescriptor();
+                    if (descriptor == null) {
+                        throw new IllegalStateException("All fetched 
parameters require a ParameterDescriptor");
+                    }
+                    final String parameterName = descriptor.getName();
+                    if (parameterNames.contains(parameterName)) {
+                        throw new 
IllegalStateException(String.format("Parameter [%s] is provided in group [%s] 
twice, which is not allowed",
+                                parameterName, groupName));
+                    }
+
+                    if (parameter.getValue() == null) {
+                        getLogger().warn("Skipping parameter [{}], which is 
missing a value", new Object[] {parameterName});

Review Comment:
   On closer inspection, it looks like `TerminationAwareLogger` should be 
adjusted to implement the variable arguments methods explicitly, to support 
compilation without the array wrapper. That can be addressed in a separate PR, 
so this can remain as-is for now. Thanks for taking a closer look!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to