This is an automated email from the ASF dual-hosted git repository.
bbende pushed a commit to branch NIFI-15258
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/NIFI-15258 by this push:
new 3e395f80a3 NIFI-15557: Allow Connectors to enable a Controller Service
using overridden property values (#10862)
3e395f80a3 is described below
commit 3e395f80a35945d4ca1d1f6db65b3f59f958d0ba
Author: Mark Payne <[email protected]>
AuthorDate: Thu Feb 5 12:44:30 2026 -0500
NIFI-15557: Allow Connectors to enable a Controller Service using
overridden property values (#10862)
---
.../service/StandardControllerServiceNode.java | 31 +++++++--
.../apache/nifi/controller/ProcessScheduler.java | 11 +++
.../controller/service/ControllerServiceNode.java | 14 ++++
.../StandaloneControllerServiceFacade.java | 2 +-
.../StandaloneControllerServiceLifecycle.java | 17 ++++-
.../scheduling/StandardProcessScheduler.java | 16 ++++-
.../TestSocketLoadBalancedFlowFileQueue.java | 6 +-
.../TestWriteAheadFlowFileRepository.java | 2 +-
.../scheduling/TestStandardProcessScheduler.java | 81 ++++++++++++++++++++++
.../AuthorizingControllerServiceLifecycle.java | 7 ++
.../scheduling/StatelessProcessScheduler.java | 6 ++
11 files changed, 181 insertions(+), 12 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
index 6bcc7a2c4d..9cb3876678 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
@@ -631,6 +631,13 @@ public class StandardControllerServiceNode extends
AbstractComponentNode impleme
*/
@Override
public CompletableFuture<Void> enable(final ScheduledExecutorService
scheduler, final long administrativeYieldMillis, final boolean
completeExceptionallyOnFailure) {
+ return enable(scheduler, administrativeYieldMillis,
completeExceptionallyOnFailure, null);
+ }
+
+ @Override
+ public CompletableFuture<Void> enable(final ScheduledExecutorService
scheduler, final long administrativeYieldMillis, final boolean
completeExceptionallyOnFailure,
+ final ConfigurationContext providedConfigurationContext) {
+
final CompletableFuture<Void> future = new CompletableFuture<>();
if
(!stateTransition.transitionToEnabling(ControllerServiceState.DISABLED,
future)) {
@@ -649,7 +656,9 @@ public class StandardControllerServiceNode extends
AbstractComponentNode impleme
scheduler.execute(new Runnable() {
@Override
public void run() {
- final ConfigurationContext configContext = new
StandardConfigurationContext(serviceNode, controllerServiceProvider, null);
+ final ConfigurationContext configContext =
providedConfigurationContext == null
+ ? new StandardConfigurationContext(serviceNode,
controllerServiceProvider, null)
+ : providedConfigurationContext;
if (!isActive()) {
LOG.warn("Enabling {} stopped: no active status",
serviceNode);
@@ -658,9 +667,17 @@ public class StandardControllerServiceNode extends
AbstractComponentNode impleme
return;
}
- // Perform Validation and evaluate status before continuing
- performValidation();
- final ValidationState validationState = getValidationState();
+ // Perform validation - if a ConfigurationContext was
provided, validate against its properties
+ final ValidationState validationState;
+ if (providedConfigurationContext == null) {
+ performValidation();
+ validationState = getValidationState();
+ } else {
+ final Map<String, String> properties =
providedConfigurationContext.getAllProperties();
+ final ValidationContext validationContext =
createValidationContext(properties, getAnnotationData(), getParameterLookup(),
true);
+ validationState = performValidation(validationContext);
+ }
+
final ValidationStatus validationStatus =
validationState.getStatus();
if (validationStatus == ValidationStatus.VALID) {
LOG.debug("Enabling {} proceeding after performing
validation", serviceNode);
@@ -761,6 +778,12 @@ public class StandardControllerServiceNode extends
AbstractComponentNode impleme
}
final CompletableFuture<Void> future = new CompletableFuture<>();
+ // If already disabled, complete immediately
+ if (getState() == ControllerServiceState.DISABLED) {
+ future.complete(null);
+ return future;
+ }
+
final boolean transitioned =
this.stateTransition.transitionToDisabling(ControllerServiceState.ENABLING,
future);
if (transitioned) {
// If we transitioned from ENABLING to DISABLING, we need to
immediately complete the disable
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessScheduler.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessScheduler.java
index 94ca3da1b1..ebef0a18c2 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessScheduler.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessScheduler.java
@@ -252,6 +252,17 @@ public interface ProcessScheduler {
*/
CompletableFuture<Void> enableControllerService(ControllerServiceNode
service);
+ /**
+ * Enables the Controller Service using the provided ConfigurationContext
instead of deriving
+ * the context from the service's current configuration. This allows
enabling a service with
+ * temporary/override property values.
+ *
+ * @param service the controller service to enable
+ * @param configurationContext the configuration context to use when
enabling the service
+ * @return a CompletableFuture that completes when the service has been
enabled
+ */
+ CompletableFuture<Void> enableControllerService(ControllerServiceNode
service, ConfigurationContext configurationContext);
+
/**
* Disables all of the given Controller Services in the order provided by
the List
* @param services the controller services to disable
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceNode.java
index 16b8b7e8d3..1cd8ede66f 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceNode.java
@@ -114,6 +114,20 @@ public interface ControllerServiceNode extends
ComponentNode, VersionedComponent
*/
CompletableFuture<Void> enable(ScheduledExecutorService scheduler, long
administrativeYieldMillis, boolean completeExceptionallyOnFailure);
+ /**
+ * Enables this service using the provided ConfigurationContext, calling
any method annotated with @OnEnabled and updating the state of the service.
+ * This allows enabling a service with temporary/override property values
without modifying the service's configuration.
+ *
+ * @param scheduler implementation of {@link ScheduledExecutorService}
used to initiate service enabling task as well as its retries
+ * @param administrativeYieldMillis the amount of milliseconds to wait for
administrative yield
+ * @param completeExceptionallyOnFailure if the Controller Service cannot
be enabled because it is invalid or throws an Exception from the @OnEnabled
lifecycle method,
+ * dictates whether the
CompletableFuture should be completed exceptionally or not
+ * @param configurationContext the ConfigurationContext to use when
enabling the service, or null to use the default
+ *
+ * @return a CompletableFuture that can be used to wait for the service to
finish enabling
+ */
+ CompletableFuture<Void> enable(ScheduledExecutorService scheduler, long
administrativeYieldMillis, boolean completeExceptionallyOnFailure,
ConfigurationContext configurationContext);
+
/**
* Will disable this service. Disabling of the service typically means
* invoking it's operation that is annotated with @OnDisabled.
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceFacade.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceFacade.java
index 59cbb92516..ff507e4fab 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceFacade.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceFacade.java
@@ -73,7 +73,7 @@ public class StandaloneControllerServiceFacade implements
ControllerServiceFacad
this.extensionManager = extensionManager;
this.assetManager = assetManager;
- this.lifecycle = new
StandaloneControllerServiceLifecycle(controllerServiceNode, processScheduler);
+ this.lifecycle = new
StandaloneControllerServiceLifecycle(controllerServiceNode, processScheduler,
componentContextProvider, parameterContext);
}
@Override
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceLifecycle.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceLifecycle.java
index de16abd8c4..c8016ce67a 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceLifecycle.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/facades/standalone/StandaloneControllerServiceLifecycle.java
@@ -20,18 +20,27 @@ package
org.apache.nifi.components.connector.facades.standalone;
import
org.apache.nifi.components.connector.components.ControllerServiceLifecycle;
import org.apache.nifi.components.connector.components.ControllerServiceState;
import org.apache.nifi.components.validation.ValidationStatus;
+import org.apache.nifi.controller.ConfigurationContext;
import org.apache.nifi.controller.ProcessScheduler;
import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.parameter.ParameterContext;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class StandaloneControllerServiceLifecycle implements
ControllerServiceLifecycle {
private final ControllerServiceNode controllerServiceNode;
private final ProcessScheduler processScheduler;
+ private final ComponentContextProvider componentContextProvider;
+ private final ParameterContext parameterContext;
+
+ public StandaloneControllerServiceLifecycle(final ControllerServiceNode
controllerServiceNode, final ProcessScheduler scheduler,
+ final ComponentContextProvider componentContextProvider, final
ParameterContext parameterContext) {
- public StandaloneControllerServiceLifecycle(final ControllerServiceNode
controllerServiceNode, final ProcessScheduler scheduler) {
this.controllerServiceNode = controllerServiceNode;
this.processScheduler = scheduler;
+ this.componentContextProvider = componentContextProvider;
+ this.parameterContext = parameterContext;
}
@Override
@@ -55,6 +64,12 @@ public class StandaloneControllerServiceLifecycle implements
ControllerServiceLi
return processScheduler.enableControllerService(controllerServiceNode);
}
+ @Override
+ public CompletableFuture<Void> enable(final Map<String, String>
propertyValueOverrides) {
+ final ConfigurationContext configurationContext =
componentContextProvider.createConfigurationContext(controllerServiceNode,
propertyValueOverrides, parameterContext);
+ return processScheduler.enableControllerService(controllerServiceNode,
configurationContext);
+ }
+
@Override
public CompletableFuture<Void> disable() {
return
processScheduler.disableControllerService(controllerServiceNode);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/StandardProcessScheduler.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/StandardProcessScheduler.java
index 740498adb6..4c30f67312 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/StandardProcessScheduler.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/StandardProcessScheduler.java
@@ -882,7 +882,18 @@ public final class StandardProcessScheduler implements
ProcessScheduler {
return enableControllerService(service, true);
}
+ @Override
+ public CompletableFuture<Void> enableControllerService(final
ControllerServiceNode service, final ConfigurationContext configurationContext)
{
+ return enableControllerService(service, true, configurationContext);
+ }
+
private CompletableFuture<Void> enableControllerService(final
ControllerServiceNode service, final boolean completeFutureExceptionally) {
+ return enableControllerService(service, completeFutureExceptionally,
null);
+ }
+
+ private CompletableFuture<Void> enableControllerService(final
ControllerServiceNode service, final boolean completeFutureExceptionally,
+ final ConfigurationContext configurationContext) {
+
if (service.isActive()) {
LOG.debug("{} is already active, so not enabling it again",
service);
return CompletableFuture.completedFuture(null);
@@ -897,10 +908,11 @@ public final class StandardProcessScheduler implements
ProcessScheduler {
for (final ControllerServiceNode dependentService : dependentServices)
{
// Enable Controller Service but if it fails, do not complete the
future Exceptionally. This allows us to wait up until the
// timeout for the service to enable, even if it needs to retry in
order to do so.
- futures.add(enableControllerService(dependentService,
completeFutureExceptionally));
+ // Note: dependent services always use their own configuration,
not the provided configurationContext
+ futures.add(enableControllerService(dependentService,
completeFutureExceptionally, null));
}
- futures.add(service.enable(this.componentLifeCycleThreadPool,
this.administrativeYieldMillis, completeFutureExceptionally));
+ futures.add(service.enable(this.componentLifeCycleThreadPool,
this.administrativeYieldMillis, completeFutureExceptionally,
configurationContext));
return CompletableFuture.allOf(futures.toArray(new
CompletableFuture[0]));
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/queue/clustered/TestSocketLoadBalancedFlowFileQueue.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/queue/clustered/TestSocketLoadBalancedFlowFileQueue.java
index d4f0ea83fe..21fd885a03 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/queue/clustered/TestSocketLoadBalancedFlowFileQueue.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/queue/clustered/TestSocketLoadBalancedFlowFileQueue.java
@@ -21,6 +21,7 @@ import
org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.ClusterTopologyEventListener;
import org.apache.nifi.cluster.coordination.node.NodeConnectionState;
import org.apache.nifi.cluster.protocol.NodeIdentifier;
+import org.apache.nifi.components.connector.DropFlowFileSummary;
import org.apache.nifi.connectable.Connection;
import org.apache.nifi.controller.MockFlowFileRecord;
import org.apache.nifi.controller.MockSwapManager;
@@ -30,7 +31,6 @@ import
org.apache.nifi.controller.queue.clustered.client.async.AsyncLoadBalanceC
import
org.apache.nifi.controller.queue.clustered.partition.FlowFilePartitioner;
import org.apache.nifi.controller.queue.clustered.partition.QueuePartition;
import
org.apache.nifi.controller.queue.clustered.partition.RoundRobinPartitioner;
-import org.apache.nifi.components.connector.DropFlowFileSummary;
import org.apache.nifi.controller.repository.ContentRepository;
import org.apache.nifi.controller.repository.FlowFileRecord;
import org.apache.nifi.controller.repository.FlowFileRepository;
@@ -39,11 +39,11 @@ import
org.apache.nifi.controller.repository.RepositoryRecordType;
import org.apache.nifi.controller.repository.SwapSummary;
import org.apache.nifi.controller.status.FlowFileAvailability;
import org.apache.nifi.events.EventReporter;
+import org.apache.nifi.flowfile.FlowFilePrioritizer;
import org.apache.nifi.provenance.ProvenanceEventRecord;
+import org.apache.nifi.provenance.ProvenanceEventRepository;
import org.apache.nifi.provenance.ProvenanceEventType;
import org.apache.nifi.provenance.StandardProvenanceEventRecord;
-import org.apache.nifi.flowfile.FlowFilePrioritizer;
-import org.apache.nifi.provenance.ProvenanceEventRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/repository/TestWriteAheadFlowFileRepository.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/repository/TestWriteAheadFlowFileRepository.java
index 9444cd1a6c..3d79cf4fa5 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/repository/TestWriteAheadFlowFileRepository.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/repository/TestWriteAheadFlowFileRepository.java
@@ -20,7 +20,6 @@ import
org.apache.nifi.components.connector.DropFlowFileSummary;
import org.apache.nifi.connectable.Connectable;
import org.apache.nifi.connectable.Connection;
import org.apache.nifi.controller.MockFlowFileRecord;
-import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.controller.queue.DropFlowFileStatus;
import org.apache.nifi.controller.queue.FlowFileQueue;
import org.apache.nifi.controller.queue.FlowFileQueueSize;
@@ -41,6 +40,7 @@ import
org.apache.nifi.controller.repository.claim.StandardResourceClaimManager;
import org.apache.nifi.controller.status.FlowFileAvailability;
import org.apache.nifi.controller.swap.StandardSwapContents;
import org.apache.nifi.controller.swap.StandardSwapSummary;
+import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.flowfile.FlowFilePrioritizer;
import org.apache.nifi.processor.FlowFileFilter;
import org.apache.nifi.util.MockFlowFile;
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
index 3b154d1a59..18cd327d01 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
@@ -47,6 +47,7 @@ import
org.apache.nifi.controller.scheduling.processors.FailOnScheduledProcessor
import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.controller.service.ControllerServiceProvider;
import org.apache.nifi.controller.service.ControllerServiceState;
+import org.apache.nifi.controller.service.StandardConfigurationContext;
import org.apache.nifi.controller.service.StandardControllerServiceProvider;
import org.apache.nifi.controller.service.mock.MockProcessGroup;
import org.apache.nifi.engine.FlowEngine;
@@ -63,6 +64,7 @@ import org.apache.nifi.processor.Processor;
import org.apache.nifi.processor.StandardProcessorInitializationContext;
import org.apache.nifi.processor.StandardValidationContextFactory;
import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.reporting.AbstractReportingTask;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.reporting.ReportingContext;
@@ -87,6 +89,7 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
@@ -94,6 +97,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -488,6 +492,51 @@ public class TestStandardProcessScheduler {
assertEquals(0, ts.disableInvocationCount());
}
+ @Test
+ @Timeout(10)
+ public void testEnableControllerServiceWithConfigurationContext() throws
Exception {
+ final ControllerServiceNode serviceNode =
flowManager.createControllerService(PropertyTrackingService.class.getName(),
+ "property-tracking-service",
systemBundle.getBundleDetails().getCoordinate(), null, false, true, null);
+
+ rootGroup.addControllerService(serviceNode);
+
serviceNode.setProperties(Map.of(PropertyTrackingService.TRACKING_PROPERTY.getName(),
"original-value"));
+ serviceNode.performValidation();
+
+ final ConfigurationContext overrideContext = new
StandardConfigurationContext(
+ serviceNode,
Map.of(PropertyTrackingService.TRACKING_PROPERTY.getName(),
"overridden-value"), null,
+ rootGroup.getParameterContext(), serviceProvider, null);
+
+ final CompletableFuture<Void> future =
scheduler.enableControllerService(serviceNode, overrideContext);
+ future.get(5, TimeUnit.SECONDS);
+
+ final PropertyTrackingService service = (PropertyTrackingService)
serviceNode.getControllerServiceImplementation();
+ assertEquals(1, service.enableInvocationCount());
+ assertEquals("overridden-value", service.getEnabledPropertyValue());
+ assertEquals(ControllerServiceState.ENABLED, serviceNode.getState());
+ }
+
+ @Test
+ @Timeout(10)
+ public void
testEnableControllerServiceWithConfigurationContextUsesOverriddenProperties()
throws ExecutionException, InterruptedException, TimeoutException {
+ final ControllerServiceNode serviceNode =
flowManager.createControllerService(PropertyTrackingService.class.getName(),
+ "property-tracking-service-2",
systemBundle.getBundleDetails().getCoordinate(), null, false, true, null);
+
+ rootGroup.addControllerService(serviceNode);
+ serviceNode.performValidation();
+
+ final ConfigurationContext validOverrideContext = new
StandardConfigurationContext(
+ serviceNode,
Map.of(PropertyTrackingService.TRACKING_PROPERTY.getName(), "override-value"),
null,
+ rootGroup.getParameterContext(), serviceProvider, null);
+
+ final CompletableFuture<Void> future =
scheduler.enableControllerService(serviceNode, validOverrideContext);
+ future.get(5, TimeUnit.SECONDS);
+
+ final PropertyTrackingService service = (PropertyTrackingService)
serviceNode.getControllerServiceImplementation();
+ assertEquals(1, service.enableInvocationCount());
+ assertEquals("override-value", service.getEnabledPropertyValue());
+ assertEquals(ControllerServiceState.ENABLED, serviceNode.getState());
+ }
+
// Test that if processor throws Exception in @OnScheduled, it keeps
getting scheduled
@Test
@Timeout(10)
@@ -619,6 +668,38 @@ public class TestStandardProcessScheduler {
}
}
+ public static class PropertyTrackingService extends
AbstractControllerService {
+ public static final PropertyDescriptor TRACKING_PROPERTY = new
PropertyDescriptor.Builder()
+ .name("Tracking Property")
+ .description("A property for tracking what value was used during
enabling")
+ .required(false)
+ .defaultValue("default-value")
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .build();
+
+ private volatile String enabledPropertyValue;
+ private final AtomicInteger enableCounter = new AtomicInteger();
+
+ @Override
+ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+ return List.of(TRACKING_PROPERTY);
+ }
+
+ @OnEnabled
+ public void enable(final ConfigurationContext context) {
+ this.enabledPropertyValue =
context.getProperty(TRACKING_PROPERTY).getValue();
+ this.enableCounter.incrementAndGet();
+ }
+
+ public String getEnabledPropertyValue() {
+ return enabledPropertyValue;
+ }
+
+ public int enableInvocationCount() {
+ return enableCounter.get();
+ }
+ }
+
private StandardProcessScheduler createScheduler() {
return new StandardProcessScheduler(new FlowEngine(1, "Unit Test",
true), Mockito.mock(FlowController.class),
stateMgrProvider, nifiProperties, new
StandardLifecycleStateManager());
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/connector/authorization/AuthorizingControllerServiceLifecycle.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/connector/authorization/AuthorizingControllerServiceLifecycle.java
index 838632fdfb..9c4332a45a 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/connector/authorization/AuthorizingControllerServiceLifecycle.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/connector/authorization/AuthorizingControllerServiceLifecycle.java
@@ -19,6 +19,7 @@ package org.apache.nifi.web.connector.authorization;
import
org.apache.nifi.components.connector.components.ControllerServiceLifecycle;
import org.apache.nifi.components.connector.components.ControllerServiceState;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
/**
@@ -47,6 +48,12 @@ public class AuthorizingControllerServiceLifecycle
implements ControllerServiceL
return delegate.enable();
}
+ @Override
+ public CompletableFuture<Void> enable(final Map<String, String>
propertyValueOverrides) {
+ authContext.authorizeWrite();
+ return delegate.enable(propertyValueOverrides);
+ }
+
@Override
public CompletableFuture<Void> disable() {
authContext.authorizeWrite();
diff --git
a/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/scheduling/StatelessProcessScheduler.java
b/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/scheduling/StatelessProcessScheduler.java
index 72c026083b..802bbcb1ed 100644
---
a/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/scheduling/StatelessProcessScheduler.java
+++
b/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/scheduling/StatelessProcessScheduler.java
@@ -329,6 +329,12 @@ public class StatelessProcessScheduler implements
ProcessScheduler {
return service.enable(componentLifeCycleThreadPool,
ADMINISTRATIVE_YIELD_MILLIS, true);
}
+ @Override
+ public CompletableFuture<Void> enableControllerService(final
ControllerServiceNode service, final ConfigurationContext configurationContext)
{
+ logger.info("Enabling {}", service);
+ return service.enable(componentLifeCycleThreadPool,
ADMINISTRATIVE_YIELD_MILLIS, true, configurationContext);
+ }
+
@Override
public CompletableFuture<Void> disableControllerService(final
ControllerServiceNode service) {
logger.info("Disabling {}", service);