tpalfy commented on code in PR #7191:
URL: https://github.com/apache/nifi/pull/7191#discussion_r1186102316


##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/flowanalysis/AbstractFlowAnalysisRuleNode.java:
##########
@@ -0,0 +1,369 @@
+/*
+ * 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.flowanalysis;
+
+import org.apache.nifi.annotation.lifecycle.OnDisabled;
+import org.apache.nifi.annotation.lifecycle.OnEnabled;
+import org.apache.nifi.bundle.Bundle;
+import org.apache.nifi.bundle.BundleCoordinate;
+import org.apache.nifi.components.ConfigVerificationResult;
+import org.apache.nifi.components.ConfigurableComponent;
+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.FlowAnalysisRuleNode;
+import org.apache.nifi.controller.LoggableComponent;
+import org.apache.nifi.controller.ReloadComponent;
+import org.apache.nifi.controller.TerminationAwareLogger;
+import org.apache.nifi.controller.ValidationContextFactory;
+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.flowanalysis.FlowAnalysisRule;
+import org.apache.nifi.flowanalysis.FlowAnalysisRuleState;
+import org.apache.nifi.flowanalysis.EnforcementPolicy;
+import org.apache.nifi.flowanalysis.VerifiableFlowAnalysisRule;
+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.ParameterLookup;
+import org.apache.nifi.processor.SimpleProcessLogger;
+import org.apache.nifi.registry.ComponentVariableRegistry;
+import org.apache.nifi.util.CharacterFilterUtils;
+import org.apache.nifi.util.FormatUtils;
+import org.apache.nifi.util.ReflectionUtils;
+import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
+import org.apache.nifi.validation.RuleViolationsManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+public abstract class AbstractFlowAnalysisRuleNode extends 
AbstractComponentNode implements FlowAnalysisRuleNode {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(AbstractFlowAnalysisRuleNode.class);
+
+    private final AtomicReference<FlowAnalysisRuleDetails> flowAnalysisRuleRef;
+    private final ControllerServiceLookup serviceLookup;
+    private final RuleViolationsManager ruleViolationsManager;
+
+    private volatile String comment;
+    private EnforcementPolicy enforcementPolicy;
+
+    private volatile FlowAnalysisRuleState state = 
FlowAnalysisRuleState.DISABLED;
+
+    public AbstractFlowAnalysisRuleNode(final 
LoggableComponent<FlowAnalysisRule> flowAnalysisRule, final String id,
+                                        final ControllerServiceProvider 
controllerServiceProvider,
+                                        final ValidationContextFactory 
validationContextFactory,
+                                        final RuleViolationsManager 
ruleViolationsManager,
+                                        final ComponentVariableRegistry 
variableRegistry,
+                                        final ReloadComponent reloadComponent, 
final ExtensionManager extensionManager, final ValidationTrigger 
validationTrigger) {
+
+        this(flowAnalysisRule, id, controllerServiceProvider, 
validationContextFactory, ruleViolationsManager,
+                flowAnalysisRule.getComponent().getClass().getSimpleName(), 
flowAnalysisRule.getComponent().getClass().getCanonicalName(),
+                variableRegistry, reloadComponent, extensionManager, 
validationTrigger, false);
+    }
+
+
+    public AbstractFlowAnalysisRuleNode(final 
LoggableComponent<FlowAnalysisRule> flowAnalysisRule, final String id, final 
ControllerServiceProvider controllerServiceProvider,
+                                        final ValidationContextFactory 
validationContextFactory, final RuleViolationsManager ruleViolationsManager,
+                                        final String componentType, final 
String componentCanonicalClass, final ComponentVariableRegistry 
variableRegistry,
+                                        final ReloadComponent reloadComponent, 
final ExtensionManager extensionManager, final ValidationTrigger 
validationTrigger,
+                                        final boolean isExtensionMissing) {
+
+        super(id, validationContextFactory, controllerServiceProvider, 
componentType, componentCanonicalClass, variableRegistry, reloadComponent,
+                extensionManager, validationTrigger, isExtensionMissing);
+        this.flowAnalysisRuleRef = new AtomicReference<>(new 
FlowAnalysisRuleDetails(flowAnalysisRule));
+        this.serviceLookup = controllerServiceProvider;
+        this.ruleViolationsManager = ruleViolationsManager;
+        this.enforcementPolicy = EnforcementPolicy.WARN;
+    }
+
+    @Override
+    public EnforcementPolicy getEnforcementPolicy() {
+        return enforcementPolicy;
+    }
+
+    @Override
+    public void setEnforcementPolicy(EnforcementPolicy enforcementPolicy) {
+        this.enforcementPolicy = enforcementPolicy;
+    }
+
+    @Override
+    public ConfigurableComponent getComponent() {
+        return flowAnalysisRuleRef.get().getFlowAnalysisRule();
+    }
+
+    @Override
+    public BundleCoordinate getBundleCoordinate() {
+        return flowAnalysisRuleRef.get().getBundleCoordinate();
+    }
+
+    @Override
+    public TerminationAwareLogger getLogger() {
+        return flowAnalysisRuleRef.get().getComponentLog();
+    }
+
+    @Override
+    public FlowAnalysisRule getFlowAnalysisRule() {
+        return flowAnalysisRuleRef.get().getFlowAnalysisRule();
+    }
+
+    @Override
+    public void setFlowAnalysisRule(final LoggableComponent<FlowAnalysisRule> 
flowAnalysisRule) {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot modify Flow Analysis Rule 
configuration while it is enabled");
+        }
+        this.flowAnalysisRuleRef.set(new 
FlowAnalysisRuleDetails(flowAnalysisRule));
+    }
+
+    @Override
+    public void reload(final Set<URL> additionalUrls) throws 
FlowAnalysisRuleInstantiationException {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot reload Flow Analysis Rule 
while it is enabled");
+        }
+        String additionalResourcesFingerprint = 
ClassLoaderUtils.generateAdditionalUrlsFingerprint(additionalUrls, 
determineClasloaderIsolationKey());
+        setAdditionalResourcesFingerprint(additionalResourcesFingerprint);
+        getReloadComponent().reload(this, getCanonicalClassName(), 
getBundleCoordinate(), additionalUrls);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return FlowAnalysisRuleState.ENABLED.equals(state);
+    }
+
+    @Override
+    public boolean isValidationNecessary() {
+        return !isEnabled() || getValidationStatus() != ValidationStatus.VALID;
+    }
+
+    @Override
+    public ConfigurationContext getConfigurationContext() {
+        return new StandardConfigurationContext(this, serviceLookup, null, 
getVariableRegistry());
+    }
+
+    @Override
+    public void verifyModifiable() throws IllegalStateException {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot modify Flow Analysis Rule 
while it is enabled");
+        }
+    }
+
+    @Override
+    public FlowAnalysisRuleState getState() {
+        return state;
+    }
+
+    @Override
+    public String getComments() {
+        return comment;
+    }
+
+    @Override
+    public void setComments(final String comment) {
+        this.comment = 
CharacterFilterUtils.filterInvalidXmlCharacters(comment);
+    }
+
+    @Override
+    public void verifyCanDelete() {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot delete " + 
getFlowAnalysisRule().getIdentifier() + " because it is enabled");
+        }
+    }
+
+    @Override
+    public void verifyCanDisable() {
+        if (!isEnabled()) {
+            throw new IllegalStateException("Cannot disable " + 
getFlowAnalysisRule().getIdentifier() + " because it is already disabled");
+        }
+    }
+
+    @Override
+    public void verifyCanEnable() {
+        if (getValidationStatus() == ValidationStatus.INVALID) {
+            throw new IllegalStateException("Cannot enable " + 
getFlowAnalysisRule().getIdentifier() + " because it is in INVALID status");
+        }
+
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot enable " + 
getFlowAnalysisRule().getIdentifier() + " because it is not disabled");
+        }
+    }
+
+    @Override
+    public void verifyCanEnable(final Set<ControllerServiceNode> 
ignoredServices) {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot enable " + 
getFlowAnalysisRule().getIdentifier() + " because it is not disabled");
+        }
+
+        final Collection<ValidationResult> validationResults = 
getValidationErrors(ignoredServices);
+        if (!validationResults.isEmpty()) {
+            throw new IllegalStateException(this + " cannot be enabled because 
it is not currently valid");
+        }
+    }
+
+    @Override
+    public void verifyCanUpdate() {
+        if (isEnabled()) {
+            throw new IllegalStateException("Cannot update " + 
getFlowAnalysisRule().getIdentifier() + " because it is currently enabled");
+        }
+    }
+
+    @Override
+    public void verifyCanClearState() {
+        verifyCanUpdate();
+    }
+
+    @Override
+    public String getProcessGroupIdentifier() {
+        return null;
+    }
+
+    @Override
+    public ParameterLookup getParameterLookup() {
+        return ParameterLookup.EMPTY;
+    }
+
+    @Override
+    public String toString() {
+        FlowAnalysisRule flowAnalysisRule = 
flowAnalysisRuleRef.get().getFlowAnalysisRule();
+        try (final NarCloseable narCloseable = 
NarCloseable.withComponentNarLoader(getExtensionManager(), 
flowAnalysisRule.getClass(), flowAnalysisRule.getIdentifier())) {
+            return getFlowAnalysisRule().toString();
+        }
+    }
+
+    @Override
+    public void enable() {
+        verifyCanEnable();
+        setState(FlowAnalysisRuleState.ENABLED, OnEnabled.class);
+    }
+
+    @Override
+    public void disable() {
+        verifyCanDisable();
+        setState(FlowAnalysisRuleState.DISABLED, OnDisabled.class);
+
+        ruleViolationsManager.removeRuleViolationsForRule(getIdentifier());
+        ruleViolationsManager.cleanUp();
+    }
+
+    private void setState(FlowAnalysisRuleState newState, Class<? extends 
Annotation> annotation) {
+        final ConfigurationContext configContext = new 
StandardConfigurationContext(this, this.serviceLookup, null, 
getVariableRegistry());
+
+        try (final NarCloseable nc = 
NarCloseable.withComponentNarLoader(getExtensionManager(), 
getFlowAnalysisRule().getClass(), getIdentifier())) {
+            ReflectionUtils.invokeMethodsWithAnnotation(annotation, 
getFlowAnalysisRule(), configContext);
+
+            this.state = newState;
+
+            LOG.debug("Successfully {} {}", newState.toString().toLowerCase(), 
this);

Review Comment:
   I followed the pattern seen in `StandardControllerServiceNode` for this (a 
flow analysis rule is more similar to controller services in this regard):
   ```java
   public class StandardControllerServiceNode//...
   //...
       private void invokeDisable(ConfigurationContext configContext) {
   //...
               LOG.debug("Successfully disabled {}", this);
   //...
       public CompletableFuture<Void> enable(final ScheduledExecutorService 
scheduler, final long administrativeYieldMillis) {
                               LOG.info("Successfully enabled {}", service);
   ...
   ```



-- 
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