This is an automated email from the ASF dual-hosted git repository.
kdoran 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 ff27361f9f8 NIFI-15621: Allow Configuration to Validate with
ValidationContext (#10916)
ff27361f9f8 is described below
commit ff27361f9f886825b62fda2b25f3e4da028a0306
Author: Bob Paulin <[email protected]>
AuthorDate: Thu Feb 19 15:34:26 2026 -0600
NIFI-15621: Allow Configuration to Validate with ValidationContext (#10916)
* Currently this is only implemented for processors in schedule periods
* Allows connector to pass Validation Context to be used instead of
current parameter context.
---
.../c2/command/AgentPropertyValidationContext.java | 5 +
.../nifi/mock/connectors/tests/CronScheduleIT.java | 68 ++++
.../mock/connectors/CronScheduleConnector.java | 106 ++++++
.../org.apache.nifi.components.connector.Connector | 3 +-
.../resources/flows/Cron_Schedule_Connector.json | 410 +++++++++++++++++++++
.../nifi/script/impl/ValidationContextAdapter.java | 5 +
.../nifi/controller/StandardProcessorNode.java | 120 +++---
.../parameter/StandardParameterProviderNode.java | 2 +-
.../service/StandardControllerServiceNode.java | 2 +-
.../nifi/processor/StandardValidationContext.java | 10 +
.../flow/StandardFlowRegistryClientNode.java | 3 +-
.../nifi/controller/AbstractComponentNode.java | 5 +-
.../nifi/controller/TestAbstractComponentNode.java | 2 +-
.../ConnectorValidationContextBridge.java | 10 +
.../flowanalysis/StandardFlowAnalysisRuleNode.java | 3 +-
.../reporting/StandardReportingTaskNode.java | 3 +-
.../apache/nifi/util/MockValidationContext.java | 8 +
.../reporting/StatelessReportingTaskNode.java | 3 +-
18 files changed, 697 insertions(+), 71 deletions(-)
diff --git
a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/command/AgentPropertyValidationContext.java
b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/command/AgentPropertyValidationContext.java
index ed0434949cd..7998a92065a 100644
---
a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/command/AgentPropertyValidationContext.java
+++
b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/command/AgentPropertyValidationContext.java
@@ -109,4 +109,9 @@ public class AgentPropertyValidationContext implements
ValidationContext {
public PropertyValue getProperty(PropertyDescriptor descriptor) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String evaluateParameters(final String value) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CronScheduleIT.java
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CronScheduleIT.java
new file mode 100644
index 00000000000..10dea97a432
--- /dev/null
+++
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CronScheduleIT.java
@@ -0,0 +1,68 @@
+/*
+ * 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.mock.connectors.tests;
+
+import org.apache.nifi.components.ConfigVerificationResult;
+import org.apache.nifi.mock.connector.StandardConnectorTestRunner;
+import org.apache.nifi.mock.connector.server.ConnectorConfigVerificationResult;
+import org.apache.nifi.mock.connector.server.ConnectorTestRunner;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+/**
+ * Integration tests that verify CRON expression validation during
configuration verification.
+ * The {@code CronScheduleConnector} maps the "Trigger Schedule" connector
property to a
+ * CRON-driven GenerateFlowFile processor's scheduling period parameter, and
verification
+ * delegates to the processor's validation which checks the CRON expression.
+ */
+public class CronScheduleIT {
+
+ private static final String CONNECTOR_CLASS =
"org.apache.nifi.mock.connectors.CronScheduleConnector";
+
+ @Test
+ public void testValidCronExpression() throws IOException {
+ try (final ConnectorTestRunner runner = createRunner()) {
+ final ConnectorConfigVerificationResult result =
runner.verifyConfiguration("Schedule",
+ Map.of("Trigger Schedule", "0 0 * * * *"));
+ result.assertNoFailures();
+ }
+ }
+
+ @Test
+ public void testInvalidCronExpression() throws IOException {
+ try (final ConnectorTestRunner runner = createRunner()) {
+ final ConnectorConfigVerificationResult result =
runner.verifyConfiguration("Schedule",
+ Map.of("Trigger Schedule", "invalid-cron"));
+ final List<ConfigVerificationResult> failedResults =
result.getFailedResults();
+ assertFalse(failedResults.isEmpty());
+ }
+ }
+
+ private ConnectorTestRunner createRunner() {
+ return new StandardConnectorTestRunner.Builder()
+ .connectorClassName(CONNECTOR_CLASS)
+ .narLibraryDirectory(new File("target/libDir"))
+ .build();
+ }
+}
diff --git
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/java/org/apache/nifi/mock/connectors/CronScheduleConnector.java
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/java/org/apache/nifi/mock/connectors/CronScheduleConnector.java
new file mode 100644
index 00000000000..1e257c245c6
--- /dev/null
+++
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/java/org/apache/nifi/mock/connectors/CronScheduleConnector.java
@@ -0,0 +1,106 @@
+/*
+ * 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.mock.connectors;
+
+import org.apache.nifi.components.ConfigVerificationResult;
+import org.apache.nifi.components.connector.AbstractConnector;
+import org.apache.nifi.components.connector.ConfigurationStep;
+import org.apache.nifi.components.connector.ConnectorConfigurationContext;
+import org.apache.nifi.components.connector.ConnectorPropertyDescriptor;
+import org.apache.nifi.components.connector.ConnectorPropertyGroup;
+import org.apache.nifi.components.connector.FlowUpdateException;
+import org.apache.nifi.components.connector.components.FlowContext;
+import org.apache.nifi.components.connector.components.ProcessorFacade;
+import org.apache.nifi.components.connector.util.VersionedFlowUtils;
+import org.apache.nifi.flow.VersionedExternalFlow;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A test connector that validates CRON scheduling expressions via the
"Trigger Schedule" parameter.
+ * The underlying flow ({@code Cron_Schedule_Connector.json}) contains a
CRON-driven
+ * GenerateFlowFile processor whose scheduling period references the {@code
#{Trigger Schedule}} parameter.
+ * Verification delegates to the processor's validate/verify cycle, which
checks the CRON expression.
+ */
+public class CronScheduleConnector extends AbstractConnector {
+
+ static final String SCHEDULE_STEP_NAME = "Schedule";
+ static final String TRIGGER_SCHEDULE_PARAM = "Trigger Schedule";
+
+ static final ConnectorPropertyDescriptor TRIGGER_SCHEDULE = new
ConnectorPropertyDescriptor.Builder()
+ .name(TRIGGER_SCHEDULE_PARAM)
+ .description("CRON expression for the GenerateFlowFile trigger
schedule")
+ .required(true)
+ .build();
+
+ static final ConnectorPropertyGroup SCHEDULE_GROUP = new
ConnectorPropertyGroup.Builder()
+ .name("Schedule Settings")
+ .addProperty(TRIGGER_SCHEDULE)
+ .build();
+
+ static final ConfigurationStep SCHEDULE_STEP = new
ConfigurationStep.Builder()
+ .name(SCHEDULE_STEP_NAME)
+ .propertyGroups(List.of(SCHEDULE_GROUP))
+ .build();
+
+ @Override
+ public VersionedExternalFlow getInitialFlow() {
+ return
VersionedFlowUtils.loadFlowFromResource("flows/Cron_Schedule_Connector.json");
+ }
+
+ @Override
+ public List<ConfigurationStep> getConfigurationSteps() {
+ return List.of(SCHEDULE_STEP);
+ }
+
+ @Override
+ protected void onStepConfigured(final String stepName, final FlowContext
flowContext) throws FlowUpdateException {
+ if (SCHEDULE_STEP_NAME.equals(stepName)) {
+ final String triggerSchedule =
flowContext.getConfigurationContext()
+ .getProperty(SCHEDULE_STEP_NAME,
TRIGGER_SCHEDULE_PARAM).getValue();
+ final VersionedExternalFlow flow = getInitialFlow();
+ VersionedFlowUtils.setParameterValue(flow, TRIGGER_SCHEDULE_PARAM,
triggerSchedule);
+ getInitializationContext().updateFlow(flowContext, flow);
+ }
+ }
+
+ @Override
+ public void applyUpdate(final FlowContext workingContext, final
FlowContext activeContext) throws FlowUpdateException {
+ }
+
+ @Override
+ public List<ConfigVerificationResult> verifyConfigurationStep(final String
stepName, final Map<String, String> overrides, final FlowContext flowContext) {
+ if (SCHEDULE_STEP_NAME.equals(stepName)) {
+ final ConnectorConfigurationContext configContext =
flowContext.getConfigurationContext().createWithOverrides(stepName, overrides);
+ final String triggerSchedule =
configContext.getProperty(SCHEDULE_STEP_NAME,
TRIGGER_SCHEDULE_PARAM).getValue();
+
+ final VersionedExternalFlow flow = getInitialFlow();
+ VersionedFlowUtils.setParameterValue(flow, TRIGGER_SCHEDULE_PARAM,
triggerSchedule);
+
+ final ProcessorFacade generateFlowFile =
flowContext.getRootGroup().getProcessors().stream()
+ .filter(p ->
p.getDefinition().getType().endsWith("GenerateFlowFile"))
+ .findFirst()
+ .orElseThrow();
+
+ return generateFlowFile.verify(flow, Map.of());
+ }
+
+ return List.of();
+ }
+}
diff --git
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector
index b05e5b86f95..379d9026452 100644
---
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector
+++
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector
@@ -15,4 +15,5 @@
org.apache.nifi.mock.connectors.AllowableValuesConnector
org.apache.nifi.mock.connectors.GenerateAndLog
-org.apache.nifi.mock.connectors.MissingBundleConnector
\ No newline at end of file
+org.apache.nifi.mock.connectors.MissingBundleConnector
+org.apache.nifi.mock.connectors.CronScheduleConnector
\ No newline at end of file
diff --git
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/flows/Cron_Schedule_Connector.json
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/flows/Cron_Schedule_Connector.json
new file mode 100644
index 00000000000..d078d4d6fa8
--- /dev/null
+++
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-test-connectors/src/main/resources/flows/Cron_Schedule_Connector.json
@@ -0,0 +1,410 @@
+{
+ "flowContents": {
+ "identifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c",
+ "instanceIdentifier": "4f8ca484-019c-1000-955f-68c5defeb22b",
+ "name": "Cron_Schedule_Connector",
+ "comments": "",
+ "position": {
+ "x": -1254.0,
+ "y": -437.70139741897583
+ },
+ "processGroups": [],
+ "remoteProcessGroups": [],
+ "processors": [
+ {
+ "identifier": "4d4160b1-736c-3be4-bc3a-84fc6eb4ad2a",
+ "instanceIdentifier": "499f9781-71c5-367f-aa17-5441bff29de9",
+ "name": "UpdateAttribute",
+ "comments": "",
+ "position": {
+ "x": -360.0,
+ "y": 24.0
+ },
+ "type":
"org.apache.nifi.processors.attributes.UpdateAttribute",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-update-attribute-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ },
+ "properties": {
+ "Delete Attributes Expression": null,
+ "Store State": "Do not store state",
+ "Cache Value Lookup Cache Size": "100",
+ "Stateful Variables Initial Value": null
+ },
+ "propertyDescriptors": {
+ "Delete Attributes Expression": {
+ "name": "Delete Attributes Expression",
+ "displayName": "Delete Attributes Expression",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Store State": {
+ "name": "Store State",
+ "displayName": "Store State",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Cache Value Lookup Cache Size": {
+ "name": "Cache Value Lookup Cache Size",
+ "displayName": "Cache Value Lookup Cache Size",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Stateful Variables Initial Value": {
+ "name": "Stateful Variables Initial Value",
+ "displayName": "Stateful Variables Initial Value",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ }
+ },
+ "style": {},
+ "schedulingPeriod": "0 sec",
+ "schedulingStrategy": "TIMER_DRIVEN",
+ "executionNode": "ALL",
+ "penaltyDuration": "30 sec",
+ "yieldDuration": "1 sec",
+ "bulletinLevel": "WARN",
+ "runDurationMillis": 25,
+ "concurrentlySchedulableTaskCount": 1,
+ "autoTerminatedRelationships": [
+ "success"
+ ],
+ "scheduledState": "ENABLED",
+ "retryCount": 10,
+ "retriedRelationships": [],
+ "backoffMechanism": "PENALIZE_FLOWFILE",
+ "maxBackoffPeriod": "10 mins",
+ "componentType": "PROCESSOR",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ },
+ {
+ "identifier": "54ab8572-0e10-39a5-b553-931f9c253023",
+ "instanceIdentifier": "6d6b9cd3-6d31-330a-40f9-185959ad1c78",
+ "name": "GenerateFlowFile",
+ "comments": "",
+ "position": {
+ "x": -360.0,
+ "y": -371.5
+ },
+ "type": "org.apache.nifi.processors.standard.GenerateFlowFile",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-standard-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ },
+ "properties": {
+ "File Size": "0B",
+ "Batch Size": "1",
+ "Unique FlowFiles": "false",
+ "Mime Type": null,
+ "Custom Text": null,
+ "Character Set": "UTF-8",
+ "Data Format": "Text",
+ "key": "test.key"
+ },
+ "propertyDescriptors": {
+ "File Size": {
+ "name": "File Size",
+ "displayName": "File Size",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Batch Size": {
+ "name": "Batch Size",
+ "displayName": "Batch Size",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Unique FlowFiles": {
+ "name": "Unique FlowFiles",
+ "displayName": "Unique FlowFiles",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Mime Type": {
+ "name": "Mime Type",
+ "displayName": "Mime Type",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Custom Text": {
+ "name": "Custom Text",
+ "displayName": "Custom Text",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Character Set": {
+ "name": "Character Set",
+ "displayName": "Character Set",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "Data Format": {
+ "name": "Data Format",
+ "displayName": "Data Format",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "key": {
+ "name": "key",
+ "displayName": "key",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": true
+ }
+ },
+ "style": {},
+ "schedulingPeriod": "#{Trigger Schedule}",
+ "schedulingStrategy": "CRON_DRIVEN",
+ "executionNode": "ALL",
+ "penaltyDuration": "30 sec",
+ "yieldDuration": "1 sec",
+ "bulletinLevel": "WARN",
+ "runDurationMillis": 0,
+ "concurrentlySchedulableTaskCount": 1,
+ "autoTerminatedRelationships": [],
+ "scheduledState": "ENABLED",
+ "retryCount": 10,
+ "retriedRelationships": [],
+ "backoffMechanism": "PENALIZE_FLOWFILE",
+ "maxBackoffPeriod": "10 mins",
+ "componentType": "PROCESSOR",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ },
+ {
+ "identifier": "34c1ac1b-1f21-3fd6-a734-726d5b142b7a",
+ "instanceIdentifier": "4f8d0670-019c-1000-1ac6-c81ef75a70d0",
+ "name": "LookupAttribute",
+ "comments": "",
+ "position": {
+ "x": -360.0,
+ "y": -168.0
+ },
+ "type": "org.apache.nifi.processors.standard.LookupAttribute",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-standard-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ },
+ "properties": {
+ "Lookup Service": "b013f870-aee8-3cc4-b022-ac385ded928d",
+ "test.attribute": "${key}",
+ "Include Empty Values": "true"
+ },
+ "propertyDescriptors": {
+ "Lookup Service": {
+ "name": "Lookup Service",
+ "displayName": "Lookup Service",
+ "identifiesControllerService": true,
+ "sensitive": false,
+ "dynamic": false
+ },
+ "test.attribute": {
+ "name": "test.attribute",
+ "displayName": "test.attribute",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": true
+ },
+ "Include Empty Values": {
+ "name": "Include Empty Values",
+ "displayName": "Include Empty Values",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": false
+ }
+ },
+ "style": {},
+ "schedulingPeriod": "0 sec",
+ "schedulingStrategy": "TIMER_DRIVEN",
+ "executionNode": "ALL",
+ "penaltyDuration": "30 sec",
+ "yieldDuration": "1 sec",
+ "bulletinLevel": "WARN",
+ "runDurationMillis": 0,
+ "concurrentlySchedulableTaskCount": 1,
+ "autoTerminatedRelationships": [
+ "failure"
+ ],
+ "scheduledState": "ENABLED",
+ "retryCount": 10,
+ "retriedRelationships": [],
+ "backoffMechanism": "PENALIZE_FLOWFILE",
+ "maxBackoffPeriod": "10 mins",
+ "componentType": "PROCESSOR",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ }
+ ],
+ "inputPorts": [],
+ "outputPorts": [],
+ "connections": [
+ {
+ "identifier": "893ad2c9-4a07-3447-b772-6b7149cfd6c1",
+ "instanceIdentifier": "5b9c96a4-7982-3746-2937-45511fb20c96",
+ "name": "",
+ "source": {
+ "id": "54ab8572-0e10-39a5-b553-931f9c253023",
+ "type": "PROCESSOR",
+ "groupId": "1800c04e-f9b9-3293-bfc7-b35f43e0706c",
+ "name": "GenerateFlowFile",
+ "comments": "",
+ "instanceIdentifier":
"6d6b9cd3-6d31-330a-40f9-185959ad1c78"
+ },
+ "destination": {
+ "id": "34c1ac1b-1f21-3fd6-a734-726d5b142b7a",
+ "type": "PROCESSOR",
+ "groupId": "1800c04e-f9b9-3293-bfc7-b35f43e0706c",
+ "name": "LookupAttribute",
+ "comments": "",
+ "instanceIdentifier":
"4f8d0670-019c-1000-1ac6-c81ef75a70d0"
+ },
+ "labelIndex": 0,
+ "zIndex": 1,
+ "selectedRelationships": [
+ "success"
+ ],
+ "backPressureObjectThreshold": 10000,
+ "backPressureDataSizeThreshold": "1 GB",
+ "flowFileExpiration": "0 sec",
+ "prioritizers": [],
+ "bends": [],
+ "loadBalanceStrategy": "DO_NOT_LOAD_BALANCE",
+ "partitioningAttribute": "",
+ "loadBalanceCompression": "DO_NOT_COMPRESS",
+ "componentType": "CONNECTION",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ },
+ {
+ "identifier": "f63459de-cf1f-3773-8f93-405518e085e4",
+ "instanceIdentifier": "4f93c5e2-019c-1000-2bea-06d8d611d5f6",
+ "name": "",
+ "source": {
+ "id": "34c1ac1b-1f21-3fd6-a734-726d5b142b7a",
+ "type": "PROCESSOR",
+ "groupId": "1800c04e-f9b9-3293-bfc7-b35f43e0706c",
+ "name": "LookupAttribute",
+ "comments": "",
+ "instanceIdentifier":
"4f8d0670-019c-1000-1ac6-c81ef75a70d0"
+ },
+ "destination": {
+ "id": "4d4160b1-736c-3be4-bc3a-84fc6eb4ad2a",
+ "type": "PROCESSOR",
+ "groupId": "1800c04e-f9b9-3293-bfc7-b35f43e0706c",
+ "name": "UpdateAttribute",
+ "comments": "",
+ "instanceIdentifier":
"499f9781-71c5-367f-aa17-5441bff29de9"
+ },
+ "labelIndex": 0,
+ "zIndex": 2,
+ "selectedRelationships": [
+ "matched",
+ "unmatched"
+ ],
+ "backPressureObjectThreshold": 10000,
+ "backPressureDataSizeThreshold": "1 GB",
+ "flowFileExpiration": "0 sec",
+ "prioritizers": [],
+ "bends": [],
+ "loadBalanceStrategy": "DO_NOT_LOAD_BALANCE",
+ "partitioningAttribute": "",
+ "loadBalanceCompression": "DO_NOT_COMPRESS",
+ "componentType": "CONNECTION",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ }
+ ],
+ "labels": [],
+ "funnels": [],
+ "controllerServices": [
+ {
+ "identifier": "b013f870-aee8-3cc4-b022-ac385ded928d",
+ "instanceIdentifier": "4f8d53d4-019c-1000-d376-abfaa091dc37",
+ "name": "SimpleKeyValueLookupService",
+ "comments": "",
+ "type": "org.apache.nifi.lookup.SimpleKeyValueLookupService",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-lookup-services-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ },
+ "properties": {
+ "test.key": "Test Value"
+ },
+ "propertyDescriptors": {
+ "test.key": {
+ "name": "test.key",
+ "displayName": "test.key",
+ "identifiesControllerService": false,
+ "sensitive": false,
+ "dynamic": true
+ }
+ },
+ "controllerServiceApis": [
+ {
+ "type": "org.apache.nifi.lookup.StringLookupService",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-standard-services-api-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ }
+ },
+ {
+ "type": "org.apache.nifi.lookup.LookupService",
+ "bundle": {
+ "group": "org.apache.nifi",
+ "artifact": "nifi-standard-services-api-nar",
+ "version": "2026.1.20.21-SNAPSHOT"
+ }
+ }
+ ],
+ "scheduledState": "DISABLED",
+ "bulletinLevel": "WARN",
+ "componentType": "CONTROLLER_SERVICE",
+ "groupIdentifier": "1800c04e-f9b9-3293-bfc7-b35f43e0706c"
+ }
+ ],
+ "parameterContextName": "Generate Parameters",
+ "defaultFlowFileExpiration": "0 sec",
+ "defaultBackPressureObjectThreshold": 10000,
+ "defaultBackPressureDataSizeThreshold": "1 GB",
+ "scheduledState": "ENABLED",
+ "executionEngine": "INHERITED",
+ "maxConcurrentTasks": 1,
+ "statelessFlowTimeout": "1 min",
+ "flowFileConcurrency": "UNBOUNDED",
+ "flowFileOutboundPolicy": "STREAM_WHEN_AVAILABLE",
+ "componentType": "PROCESS_GROUP"
+ },
+ "externalControllerServices": {},
+ "parameterContexts": {
+ "Generate Parameters": {
+ "name": "Generate Parameters",
+ "parameters": [
+ {
+ "name": "Trigger Schedule",
+ "description": "",
+ "sensitive": false,
+ "provided": false,
+ "value": ""
+ }
+ ],
+ "inheritedParameterContexts": [],
+ "description": "",
+ "componentType": "PARAMETER_CONTEXT"
+ }
+ },
+ "flowEncodingVersion": "1.0",
+ "parameterProviders": {},
+ "latest": false
+}
\ No newline at end of file
diff --git
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/impl/ValidationContextAdapter.java
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/impl/ValidationContextAdapter.java
index d78d0134782..8951412fc00 100644
---
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/impl/ValidationContextAdapter.java
+++
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/impl/ValidationContextAdapter.java
@@ -115,4 +115,9 @@ public abstract class ValidationContextAdapter implements
ValidationContext {
public boolean isDependencySatisfied(final PropertyDescriptor
propertyDescriptor, final Function<String, PropertyDescriptor>
propertyDescriptorLookup) {
return
innerValidationContext.isDependencySatisfied(propertyDescriptor,
propertyDescriptorLookup);
}
+
+ @Override
+ public String evaluateParameters(final String value) {
+ return innerValidationContext.evaluateParameters(value);
+ }
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
index 69bef45ed71..f739bc11fc6 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
@@ -1140,89 +1140,87 @@ public class StandardProcessorNode extends
ProcessorNode implements Connectable
}
@Override
- public List<ValidationResult> validateConfig() {
+ public List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
final List<ValidationResult> results = new ArrayList<>();
- final ParameterContext parameterContext = getParameterContext();
-
- if (parameterContext == null && !this.parameterReferences.isEmpty()) {
- results.add(new ValidationResult.Builder()
- .subject(RUN_SCHEDULE)
- .input("Parameter Context")
- .valid(false)
- .explanation("Processor configuration references one or
more Parameters but no Parameter Context is currently set on the Process
Group.")
- .build());
- } else {
- for (final ParameterReference paramRef : parameterReferences) {
- final Optional<Parameter> parameterRef =
parameterContext.getParameter(paramRef.getParameterName());
- if (!parameterRef.isPresent()) {
- results.add(new ValidationResult.Builder()
- .subject(RUN_SCHEDULE)
- .input(paramRef.getParameterName())
- .valid(false)
- .explanation("Processor configuration references
Parameter '" + paramRef.getParameterName() +
- "' but the currently selected Parameter
Context does not have a Parameter with that name")
- .build());
- } else {
- final ParameterDescriptor parameterDescriptor =
parameterRef.get().getDescriptor();
- if (parameterDescriptor.isSensitive()) {
- results.add(new ValidationResult.Builder()
- .subject(RUN_SCHEDULE)
- .input(parameterDescriptor.getName())
- .valid(false)
- .explanation("Processor configuration cannot
reference sensitive parameters")
- .build());
- }
- }
- }
- final String schedulingPeriod = getSchedulingPeriod();
- final String evaluatedSchedulingPeriod =
evaluateParameters(schedulingPeriod);
+ for (final ParameterReference paramRef : parameterReferences) {
+ final String paramName = paramRef.getParameterName();
- if (evaluatedSchedulingPeriod != null) {
- switch (schedulingStrategy) {
- case CRON_DRIVEN: {
- try {
- CronExpression.parse(evaluatedSchedulingPeriod);
- } catch (final Exception e) {
+ if (!validationContext.isParameterDefined(paramName)) {
+ results.add(new ValidationResult.Builder()
+ .subject(RUN_SCHEDULE)
+ .input(paramName)
+ .valid(false)
+ .explanation("Processor configuration references
Parameter '" + paramName +
+ "' but the currently selected Parameter
Context does not have a Parameter with that name")
+ .build());
+ } else {
+ final ParameterContext parameterContext =
getParameterContext();
+ if (parameterContext != null) {
+ final Optional<Parameter> parameterFromContext =
parameterContext.getParameter(paramName);
+ if (parameterFromContext.isPresent()) {
+ final ParameterDescriptor parameterDescriptor =
parameterFromContext.get().getDescriptor();
+ if (parameterDescriptor.isSensitive()) {
results.add(new ValidationResult.Builder()
.subject(RUN_SCHEDULE)
- .input(schedulingPeriod)
+ .input(parameterDescriptor.getName())
.valid(false)
- .explanation("Scheduling Period is not a
valid cron expression")
+ .explanation("Processor configuration
cannot reference sensitive parameters")
.build());
}
}
- break;
- case TIMER_DRIVEN: {
- try {
- final long schedulingNanos =
FormatUtils.getTimeDuration(Objects.requireNonNull(evaluatedSchedulingPeriod),
- TimeUnit.NANOSECONDS);
-
- if (schedulingNanos < 0) {
- results.add(new ValidationResult.Builder()
- .subject(RUN_SCHEDULE)
- .input(schedulingPeriod)
- .valid(false)
- .explanation("Scheduling Period must
be positive")
- .build());
- }
+ }
+ }
+ }
-
this.schedulingNanos.set(Math.max(MINIMUM_SCHEDULING_NANOS, schedulingNanos));
+ final String schedulingPeriod = getSchedulingPeriod();
+ final String evaluatedSchedulingPeriod =
validationContext.evaluateParameters(schedulingPeriod);
- } catch (final Exception e) {
+ if (evaluatedSchedulingPeriod != null) {
+ switch (schedulingStrategy) {
+ case CRON_DRIVEN: {
+ try {
+ CronExpression.parse(evaluatedSchedulingPeriod);
+ } catch (final Exception e) {
+ results.add(new ValidationResult.Builder()
+ .subject(RUN_SCHEDULE)
+ .input(schedulingPeriod)
+ .valid(false)
+ .explanation("Scheduling Period is not a valid
cron expression")
+ .build());
+ }
+ }
+ break;
+ case TIMER_DRIVEN: {
+ try {
+ final long schedulingNanos =
FormatUtils.getTimeDuration(Objects.requireNonNull(evaluatedSchedulingPeriod),
+ TimeUnit.NANOSECONDS);
+
+ if (schedulingNanos < 0) {
results.add(new ValidationResult.Builder()
.subject(RUN_SCHEDULE)
.input(schedulingPeriod)
.valid(false)
- .explanation("Scheduling Period is not a
valid time duration")
+ .explanation("Scheduling Period must be
positive")
.build());
}
+
+
this.schedulingNanos.set(Math.max(MINIMUM_SCHEDULING_NANOS, schedulingNanos));
+
+ } catch (final Exception e) {
+ results.add(new ValidationResult.Builder()
+ .subject(RUN_SCHEDULE)
+ .input(schedulingPeriod)
+ .valid(false)
+ .explanation("Scheduling Period is not a valid
time duration")
+ .build());
}
- break;
}
+ break;
}
}
+
return results;
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/parameter/StandardParameterProviderNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/parameter/StandardParameterProviderNode.java
index 6b70934396f..256fa991a53 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/parameter/StandardParameterProviderNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/parameter/StandardParameterProviderNode.java
@@ -266,7 +266,7 @@ public class StandardParameterProviderNode extends
AbstractComponentNode impleme
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}
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 1c06833451e..47ac9dedd6a 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
@@ -619,7 +619,7 @@ public class StandardControllerServiceNode extends
AbstractComponentNode impleme
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
index f82b8eb24ba..9ee15d3eff1 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
@@ -36,9 +36,12 @@ import
org.apache.nifi.controller.service.ControllerServiceProvider;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.expression.ExpressionLanguageCompiler;
import org.apache.nifi.groups.ProcessGroup;
+import org.apache.nifi.parameter.ExpressionLanguageAgnosticParameterParser;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterLookup;
+import org.apache.nifi.parameter.ParameterParser;
import org.apache.nifi.parameter.ParameterReference;
+import org.apache.nifi.parameter.ParameterTokenList;
import java.util.Collection;
import java.util.Collections;
@@ -242,6 +245,13 @@ public class StandardValidationContext implements
ValidationContext {
return validateConnections;
}
+ @Override
+ public String evaluateParameters(final String value) {
+ final ParameterParser parameterParser = new
ExpressionLanguageAgnosticParameterParser();
+ final ParameterTokenList parameterTokenList =
parameterParser.parseTokens(value);
+ return parameterTokenList.substitute(parameterLookup);
+ }
+
@Override
public String toString() {
return "StandardValidationContext[componentId=" + componentId + ",
properties=" + properties + "]";
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/StandardFlowRegistryClientNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/StandardFlowRegistryClientNode.java
index 9eb895fcec1..e8e936df270 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/StandardFlowRegistryClientNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/StandardFlowRegistryClientNode.java
@@ -28,6 +28,7 @@ import org.apache.nifi.components.ConfigVerificationResult;
import org.apache.nifi.components.ConfigVerificationResult.Outcome;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
+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;
@@ -118,7 +119,7 @@ public final class StandardFlowRegistryClientNode extends
AbstractComponentNode
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
index 612547ab019..88a41522600 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractComponentNode.java
@@ -932,7 +932,7 @@ public abstract class AbstractComponentNode implements
ComponentNode {
}
final List<ValidationResult> invalidParameterResults =
validateParameterReferences(validationContext);
- invalidParameterResults.addAll(validateConfig());
+ invalidParameterResults.addAll(validateConfig(validationContext));
if (!invalidParameterResults.isEmpty()) {
// At this point, we are not able to properly resolve all
property values, so we will not attempt to perform
@@ -993,11 +993,12 @@ public abstract class AbstractComponentNode implements
ComponentNode {
* Validates the current configuration, returning ValidationResults for any
* invalid configuration parameter.
*
+ * @param validationContext the ValidationContext to use for parameter
lookup
* @return Collection of validation result objects for any invalid findings
* only. If the collection is empty then the component is valid.
Should guarantee
* non-null
*/
- protected abstract List<ValidationResult> validateConfig();
+ protected abstract List<ValidationResult> validateConfig(ValidationContext
validationContext);
private List<ValidationResult> validateParameterReferences(final
ValidationContext validationContext) {
final List<ValidationResult> results = new ArrayList<>();
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/controller/TestAbstractComponentNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/controller/TestAbstractComponentNode.java
index ed27ec59375..08be7562705 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/controller/TestAbstractComponentNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/controller/TestAbstractComponentNode.java
@@ -536,7 +536,7 @@ public class TestAbstractComponentNode {
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final
ValidationContext validationContext) {
return Collections.emptyList();
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/ConnectorValidationContextBridge.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/ConnectorValidationContextBridge.java
index 27992b2f4f8..6f867925be7 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/ConnectorValidationContextBridge.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/ConnectorValidationContextBridge.java
@@ -25,8 +25,11 @@ import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.documentation.init.EmptyControllerServiceLookup;
import org.apache.nifi.expression.ExpressionLanguageCompiler;
+import org.apache.nifi.parameter.ExpressionLanguageAgnosticParameterParser;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterLookup;
+import org.apache.nifi.parameter.ParameterParser;
+import org.apache.nifi.parameter.ParameterTokenList;
import java.util.Collection;
import java.util.Collections;
@@ -133,4 +136,11 @@ public class ConnectorValidationContextBridge implements
ValidationContext {
public Map<String, String> getAllProperties() {
return Collections.unmodifiableMap(rawValues);
}
+
+ @Override
+ public String evaluateParameters(final String value) {
+ final ParameterParser parameterParser = new
ExpressionLanguageAgnosticParameterParser();
+ final ParameterTokenList parameterTokenList =
parameterParser.parseTokens(value);
+ return parameterTokenList.substitute(parameterLookup);
+ }
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flowanalysis/StandardFlowAnalysisRuleNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flowanalysis/StandardFlowAnalysisRuleNode.java
index 110ba3fa061..7c2d9a4d213 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flowanalysis/StandardFlowAnalysisRuleNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flowanalysis/StandardFlowAnalysisRuleNode.java
@@ -22,6 +22,7 @@ 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.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.validation.ValidationTrigger;
import org.apache.nifi.controller.FlowAnalysisRuleNode;
@@ -98,7 +99,7 @@ public class StandardFlowAnalysisRuleNode extends
AbstractFlowAnalysisRuleNode i
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
index dfaf6347309..055a1d246eb 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
@@ -22,6 +22,7 @@ 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.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.validation.ValidationTrigger;
import org.apache.nifi.controller.FlowController;
@@ -91,7 +92,7 @@ public class StandardReportingTaskNode extends
AbstractReportingTaskNode impleme
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}
diff --git
a/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
b/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
index 91541c9b500..df6b8a61d48 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
@@ -31,6 +31,7 @@ import
org.apache.nifi.parameter.ExpressionLanguageAwareParameterParser;
import org.apache.nifi.parameter.ParameterLookup;
import org.apache.nifi.parameter.ParameterParser;
import org.apache.nifi.parameter.ParameterReference;
+import org.apache.nifi.parameter.ParameterTokenList;
import java.util.Collection;
import java.util.Collections;
@@ -220,6 +221,13 @@ public class MockValidationContext extends
MockControllerServiceLookup implement
return contextParameters.containsKey(parameterName) &&
contextParameters.get(parameterName) != null;
}
+ @Override
+ public String evaluateParameters(final String value) {
+ final ParameterParser parameterParser = new
ExpressionLanguageAgnosticParameterParser();
+ final ParameterTokenList parameterTokenList =
parameterParser.parseTokens(value);
+ return parameterTokenList.substitute(parameterLookup);
+ }
+
private String getEffectiveValue(final PropertyDescriptor descriptor) {
final String configuredValue = context.getProperties().get(descriptor);
return getEffectiveValue(descriptor, configuredValue);
diff --git
a/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/reporting/StatelessReportingTaskNode.java
b/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/reporting/StatelessReportingTaskNode.java
index 2528c76d606..e72d6972778 100644
---
a/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/reporting/StatelessReportingTaskNode.java
+++
b/nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/controller/reporting/StatelessReportingTaskNode.java
@@ -19,6 +19,7 @@ package org.apache.nifi.controller.reporting;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.validation.ValidationTrigger;
import org.apache.nifi.controller.LoggableComponent;
@@ -50,7 +51,7 @@ public class StatelessReportingTaskNode extends
AbstractReportingTaskNode implem
}
@Override
- protected List<ValidationResult> validateConfig() {
+ protected List<ValidationResult> validateConfig(final ValidationContext
validationContext) {
return Collections.emptyList();
}