This is an automated email from the ASF dual-hosted git repository. markap14 pushed a commit to branch NIFI-15258 in repository https://gitbox.apache.org/repos/asf/nifi.git
commit 4c98a8842f50d118af1aa36318af406164a2c56f Author: Mark Payne <[email protected]> AuthorDate: Mon Jan 12 14:30:06 2026 -0500 NIFI-15439: Ensure that Process Groups are accessible from the approp… (#10742) * NIFI-15439: Ensure that Process Groups are accessible from the appropriate endpoint but not accessible elsewhere * NIFI-15439: FlowAnalyzingRegistryClient should use an explicit Connector ID of null when retrieving Process Group from FlowManager --- .../nifi/controller/flow/AbstractFlowManager.java | 16 +++++ .../apache/nifi/groups/StandardProcessGroup.java | 2 +- .../flow/FlowAnalyzingRegistryClientNode.java | 3 +- .../flow/FlowAnalyzingRegistryClientNodeTest.java | 2 +- .../apache/nifi/controller/flow/FlowManager.java | 9 +++ .../org/apache/nifi/controller/FlowController.java | 10 +-- .../nifi/controller/flow/StandardFlowManager.java | 7 +- .../org/apache/nifi/web/dao/impl/ComponentDAO.java | 4 +- .../nifi/web/dao/impl/StandardProcessGroupDAO.java | 4 +- .../org/apache/nifi/audit/TestLabelAuditor.java | 2 +- .../apache/nifi/audit/TestProcessGroupAuditor.java | 6 +- .../apache/nifi/audit/TestProcessorAuditor.java | 2 +- .../web/dao/impl/StandardProcessorDAOTest.java | 2 +- .../web/dao/impl/TestStandardProcessGroupDAO.java | 15 +---- .../tests/system/NestedProcessGroupConnector.java | 75 ++++++++++++++++++++++ .../org.apache.nifi.components.connector.Connector | 1 + .../tests/system/connectors/ConnectorCrudIT.java | 49 ++++++++++++++ .../nifi/toolkit/client/ConnectorClient.java | 6 +- .../toolkit/client/impl/JerseyConnectorClient.java | 18 +++--- 19 files changed, 185 insertions(+), 48 deletions(-) diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/flow/AbstractFlowManager.java b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/flow/AbstractFlowManager.java index a694c5be35..076f2efa99 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/flow/AbstractFlowManager.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/flow/AbstractFlowManager.java @@ -63,6 +63,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -122,6 +123,21 @@ public abstract class AbstractFlowManager implements FlowManager { return allProcessGroups.get(requireNonNull(id)); } + @Override + public ProcessGroup getGroup(final String groupId, final String connectorId) { + final ProcessGroup group = allProcessGroups.get(requireNonNull(groupId)); + if (group == null) { + return null; + } + + // If we found the group, return it only if it has the correct connector ID + if (Objects.equals(group.getConnectorIdentifier().orElse(null), connectorId)) { + return group; + } + + return null; + } + @Override public void onProcessGroupAdded(final ProcessGroup group) { allProcessGroups.put(group.getIdentifier(), group); diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java index 9918eda3a1..3987ea19f9 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java @@ -2112,7 +2112,7 @@ public final class StandardProcessGroup implements ProcessGroup { return this; } - final ProcessGroup group = flowManager.getGroup(id); + final ProcessGroup group = flowManager.getGroup(id, getConnectorIdentifier().orElse(null)); if (group == null) { return null; } diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNode.java b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNode.java index 14d555d013..faeb336efe 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNode.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNode.java @@ -111,7 +111,8 @@ public final class FlowAnalyzingRegistryClientNode implements FlowRegistryClient } private boolean analyzeProcessGroupToRegister(final VersionedProcessGroup snapshot) { - final InstantiatedVersionedProcessGroup nonVersionedProcessGroup = flowMapper.mapNonVersionedProcessGroup(flowManager.getGroup(snapshot.getInstanceIdentifier()), serviceProvider); + final ProcessGroup group = flowManager.getGroup(snapshot.getInstanceIdentifier(), null); + final InstantiatedVersionedProcessGroup nonVersionedProcessGroup = flowMapper.mapNonVersionedProcessGroup(group, serviceProvider); flowAnalyzer.analyzeProcessGroup(nonVersionedProcessGroup); final List<RuleViolation> ruleViolations = ruleViolationsManager.getRuleViolationsForGroup(snapshot.getInstanceIdentifier()).stream() diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNodeTest.java b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNodeTest.java index 5e3f2ce46a..e69a27a05f 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNodeTest.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/registry/flow/FlowAnalyzingRegistryClientNodeTest.java @@ -90,7 +90,7 @@ class FlowAnalyzingRegistryClientNodeTest { @BeforeEach public void setUp() { Mockito.when(versionedProcessGroup.getInstanceIdentifier()).thenReturn(INSTANCE_IDENTIFIER); - Mockito.when(flowManager.getGroup(Mockito.anyString())).thenReturn(processGroup); + Mockito.when(flowManager.getGroup(Mockito.anyString(), Mockito.eq(null))).thenReturn(processGroup); Mockito.when(flowMapper.mapNonVersionedProcessGroup(Mockito.same(processGroup), Mockito.same(serviceProvider))).thenReturn(nonVersionedProcessGroup); Mockito.when(ruleViolation1.getEnforcementPolicy()).thenReturn(EnforcementPolicy.ENFORCE); Mockito.when(ruleViolation2.getEnforcementPolicy()).thenReturn(EnforcementPolicy.ENFORCE); diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/flow/FlowManager.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/flow/FlowManager.java index d756e8531e..c1a363a5ab 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/flow/FlowManager.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/flow/FlowManager.java @@ -165,6 +165,15 @@ public interface FlowManager extends ParameterProviderLookup { */ ProcessGroup getGroup(String id); + /** + * Returns the ProcessGroup with the given ID that is managed by the Connector with the given ID, + * or null if no such ProcessGroup exists. + * @param groupId id of the group + * @param connectorId id of the connector + * @return the ProcessGroup with the given ID or null if none can be found + */ + ProcessGroup getGroup(String groupId, String connectorId); + void onProcessGroupAdded(ProcessGroup group); void onProcessGroupRemoved(ProcessGroup group); diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java index 81a7115ada..1bea151791 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java @@ -52,14 +52,14 @@ import org.apache.nifi.components.ClassLoaderAwarePythonBridge; import org.apache.nifi.components.connector.ConnectorRepository; import org.apache.nifi.components.connector.ConnectorRepositoryInitializationContext; import org.apache.nifi.components.connector.ConnectorRequestReplicator; +import org.apache.nifi.components.connector.ConnectorValidationTrigger; import org.apache.nifi.components.connector.StandardConnectorRepoInitializationContext; import org.apache.nifi.components.connector.StandardConnectorRepository; +import org.apache.nifi.components.connector.StandardConnectorValidationTrigger; import org.apache.nifi.components.connector.secrets.ParameterProviderSecretsManager; import org.apache.nifi.components.connector.secrets.SecretsManager; import org.apache.nifi.components.connector.secrets.SecretsManagerInitializationContext; import org.apache.nifi.components.connector.secrets.StandardSecretsManagerInitializationContext; -import org.apache.nifi.components.connector.ConnectorValidationTrigger; -import org.apache.nifi.components.connector.StandardConnectorValidationTrigger; import org.apache.nifi.components.monitor.LongRunningTaskMonitor; import org.apache.nifi.components.state.StateManagerProvider; import org.apache.nifi.components.state.StateProvider; @@ -229,8 +229,6 @@ import org.apache.nifi.web.revision.RevisionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.management.NotificationEmitter; -import javax.net.ssl.SSLContext; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; @@ -263,6 +261,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Supplier; import java.util.stream.Collectors; +import javax.management.NotificationEmitter; +import javax.net.ssl.SSLContext; import static java.util.Objects.requireNonNull; @@ -2180,7 +2180,7 @@ public class FlowController implements ReportingTaskProvider, FlowAnalysisRulePr * @return the process group or null if not group is found */ private ProcessGroup lookupGroup(final String id) { - final ProcessGroup group = flowManager.getGroup(id); + final ProcessGroup group = flowManager.getGroup(id, null); if (group == null) { throw new IllegalStateException("No Group with ID " + id + " exists"); } diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flow/StandardFlowManager.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flow/StandardFlowManager.java index 96bbd8f4f7..d3874eb5cb 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flow/StandardFlowManager.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/flow/StandardFlowManager.java @@ -306,10 +306,7 @@ public class StandardFlowManager extends AbstractFlowManager implements FlowMana flowController.getReloadComponent(), flowController, nifiProperties, statelessGroupNodeFactory, flowController.getAssetManager(), connectorId); - // We don't want to register the group if it's being created as part of a Connector - if (connectorId == null) { - onProcessGroupAdded(group); - } + onProcessGroupAdded(group); return group; } @@ -750,7 +747,7 @@ public class StandardFlowManager extends AbstractFlowManager implements FlowMana final ExtensionManager extensionManager = flowController.getExtensionManager(); final String managedGroupId = UUID.nameUUIDFromBytes((id + "-root").getBytes(StandardCharsets.UTF_8)).toString(); - final ProcessGroup managedRootGroup = createProcessGroup(managedGroupId); + final ProcessGroup managedRootGroup = createProcessGroup(managedGroupId, id); final String paramContextId = UUID.nameUUIDFromBytes((id + "-parameter-context").getBytes(StandardCharsets.UTF_8)).toString(); final String paramContextName = "Connector " + id + " Parameter Context"; diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/ComponentDAO.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/ComponentDAO.java index 078644a24a..90760cbcd3 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/ComponentDAO.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/ComponentDAO.java @@ -63,8 +63,8 @@ public abstract class ComponentDAO { * @param groupId id * @return group */ - protected ProcessGroup locateProcessGroup(FlowController flowController, String groupId) { - ProcessGroup group = flowController.getFlowManager().getGroup(groupId); + protected ProcessGroup locateProcessGroup(final FlowController flowController, final String groupId) { + ProcessGroup group = flowController.getFlowManager().getGroup(groupId, null); if (group == null) { throw new ResourceNotFoundException(String.format("Unable to locate group with id '%s'.", groupId)); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessGroupDAO.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessGroupDAO.java index f464a7375e..aa7c5bf736 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessGroupDAO.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessGroupDAO.java @@ -120,7 +120,7 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou @Override public boolean hasProcessGroup(String groupId) { - return flowController.getFlowManager().getGroup(groupId) != null; + return flowController.getFlowManager().getGroup(groupId, null) != null; } @Override @@ -411,7 +411,7 @@ public class StandardProcessGroupDAO extends ComponentDAO implements ProcessGrou .map(flowManager::getControllerServiceNode) .collect(Collectors.toList()); - final ProcessGroup group = flowManager.getGroup(groupId); + final ProcessGroup group = flowManager.getGroup(groupId, null); if (group == null) { throw new IllegalArgumentException("Cannot activate Controller Services with IDs " + serviceIds + " because the associated Process Group (id=" + groupId + ") could not be found"); } diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestLabelAuditor.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestLabelAuditor.java index af03389ec3..48605cd64f 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestLabelAuditor.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestLabelAuditor.java @@ -119,7 +119,7 @@ public class TestLabelAuditor { @Test void testCreateLabelAdvice() { final LabelDTO labelDto = getLabelDto(); - when(flowManager.getGroup(eq(GROUP_ID))).thenReturn(processGroup); + when(flowManager.getGroup(eq(GROUP_ID), eq(null))).thenReturn(processGroup); when(flowManager.createLabel(eq(LABEL_ID), eq(LABEL))).thenReturn(new StandardLabel(LABEL_ID, LABEL)); final Label label = labelDao.createLabel(GROUP_ID, labelDto); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessGroupAuditor.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessGroupAuditor.java index 3d5f5bd1ac..b79ef9e344 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessGroupAuditor.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessGroupAuditor.java @@ -176,7 +176,7 @@ public class TestProcessGroupAuditor { when(processGroup.findRemoteGroupPort(REMOTE_GROUP_INPUT_PORT)).thenReturn(remoteGroupInputPort); when(remoteGroupInputPort.getRemoteProcessGroup()).thenReturn(remoteProcessGroup); - when(flowManager.getGroup(eq(PG_1))).thenReturn(processGroup); + when(flowManager.getGroup(eq(PG_1), eq(null))).thenReturn(processGroup); when(flowManager.findConnectable(eq(PROC_1))).thenReturn(processor1); when(flowManager.findConnectable(eq(PROC_2))).thenReturn(processor2); when(flowManager.findConnectable(eq(INPUT_PORT))).thenReturn(inputPort); @@ -286,7 +286,7 @@ public class TestProcessGroupAuditor { when(processGroup.findInputPort(OUTPUT_PORT)).thenReturn(null); when(processGroup.findOutputPort(OUTPUT_PORT)).thenReturn(outputPort); - when(flowManager.getGroup(eq(PG_1))).thenReturn(processGroup); + when(flowManager.getGroup(eq(PG_1), eq(null))).thenReturn(processGroup); when(flowManager.findConnectable(eq(PROC_1))).thenReturn(processor1); when(flowManager.findConnectable(eq(PROC_2))).thenReturn(processor2); when(flowManager.findConnectable(eq(INPUT_PORT))).thenReturn(inputPort); @@ -354,7 +354,7 @@ public class TestProcessGroupAuditor { when(cs.getName()).thenReturn(CS_1); when(processGroup.findControllerService(eq(CS_1), eq(true), eq(true))).thenReturn(cs); - when(flowManager.getGroup(eq(PG_1))).thenReturn(processGroup); + when(flowManager.getGroup(eq(PG_1), eq(null))).thenReturn(processGroup); when(flowManager.getControllerServiceNode(eq(CS_1))).thenReturn(cs); when(flowController.getFlowManager()).thenReturn(flowManager); when(flowController.getControllerServiceProvider()).thenReturn(csProvider); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessorAuditor.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessorAuditor.java index 2b249b362b..99ebc25eae 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessorAuditor.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/audit/TestProcessorAuditor.java @@ -147,7 +147,7 @@ class TestProcessorAuditor { when(flowController.getControllerServiceProvider()).thenReturn(mock(ControllerServiceProvider.class)); when(flowController.getStateManagerProvider()).thenReturn(mockStateManagerProvider); - when(flowManager.getGroup(GROUP_ID)).thenReturn(processGroup); + when(flowManager.getGroup(GROUP_ID, null)).thenReturn(processGroup); when(flowManager.createProcessor(anyString(), anyString(), any())).thenReturn(mockProcessorNode); final Bundle bundle = getBundle(); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardProcessorDAOTest.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardProcessorDAOTest.java index 30c9fdfdc9..1ae61d3dce 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardProcessorDAOTest.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardProcessorDAOTest.java @@ -210,7 +210,7 @@ class StandardProcessorDAOTest { final Bundle bundle = new Bundle(bundleDetails, getClass().getClassLoader()); final List<Bundle> bundles = List.of(bundle); - when(flowManager.getGroup(eq(groupId))).thenReturn(processGroup); + when(flowManager.getGroup(eq(groupId), eq(null))).thenReturn(processGroup); when(flowController.getExtensionManager()).thenReturn(extensionManager); when(flowManager.createProcessor(eq(processorType), eq(id), eq(bundleCoordinate))).thenReturn(processorNode); when(extensionManager.getBundles(eq(processorType))).thenReturn(bundles); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/TestStandardProcessGroupDAO.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/TestStandardProcessGroupDAO.java index 9ca3f0a837..85c55f88f9 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/TestStandardProcessGroupDAO.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/TestStandardProcessGroupDAO.java @@ -59,21 +59,12 @@ public class TestStandardProcessGroupDAO { testSubject = new StandardProcessGroupDAO(); testSubject.setFlowController(flowController); - when(flowController - .getFlowManager() - .getGroup(PARENT_PROCESS_GROUP_ID) - ).thenReturn(parentProcessGroup); - - when(flowController - .getFlowManager() - .getParameterContextManager() - .getParameterContext(PARAMETER_CONTEXT_ID) - ).thenReturn(parameterContext); + when(flowController.getFlowManager().getGroup(PARENT_PROCESS_GROUP_ID, null)).thenReturn(parentProcessGroup); + when(flowController.getFlowManager().getParameterContextManager().getParameterContext(PARAMETER_CONTEXT_ID)).thenReturn(parameterContext); } @Test public void testCreateProcessGroup() { - //GIVEN ParameterContextReferenceEntity parameterContextReferenceEntity = new ParameterContextReferenceEntity(); parameterContextReferenceEntity.setId(PARAMETER_CONTEXT_ID); @@ -84,10 +75,8 @@ public class TestStandardProcessGroupDAO { processGroupDTO.setPosition(new PositionDTO(10.0, 20.0)); processGroupDTO.setParameterContext(parameterContextReferenceEntity); - //WHEN ProcessGroup createdProcessGroup = testSubject.createProcessGroup(PARENT_PROCESS_GROUP_ID, processGroupDTO); - //THEN verify(createdProcessGroup).setParent(parentProcessGroup); verify(createdProcessGroup).setParameterContext(parameterContext); verify(createdProcessGroup).setName(PROCESS_GROUP_NAME); diff --git a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/connectors/tests/system/NestedProcessGroupConnector.java b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/connectors/tests/system/NestedProcessGroupConnector.java new file mode 100644 index 0000000000..e3903a38f1 --- /dev/null +++ b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/java/org/apache/nifi/connectors/tests/system/NestedProcessGroupConnector.java @@ -0,0 +1,75 @@ +/* + * 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.connectors.tests.system; + +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.components.FlowContext; +import org.apache.nifi.flow.VersionedExternalFlow; +import org.apache.nifi.flow.VersionedProcessGroup; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Test Connector that creates a flow with a nested (child) process group. + * Used to verify that child process groups within a connector's managed flow + * can be properly accessed via the connector API. + */ +public class NestedProcessGroupConnector extends AbstractConnector { + + public static final String CHILD_PROCESS_GROUP_ID = "child-process-group-id"; + + private final List<ConfigurationStep> configurationSteps = List.of(); + + @Override + protected void onStepConfigured(final String stepName, final FlowContext workingContext) { + } + + @Override + public VersionedExternalFlow getInitialFlow() { + final VersionedProcessGroup childGroup = new VersionedProcessGroup(); + childGroup.setIdentifier(CHILD_PROCESS_GROUP_ID); + childGroup.setName("Child Process Group"); + + final VersionedProcessGroup rootGroup = new VersionedProcessGroup(); + rootGroup.setName("Nested Flow"); + rootGroup.setProcessGroups(Set.of(childGroup)); + + final VersionedExternalFlow flow = new VersionedExternalFlow(); + flow.setFlowContents(rootGroup); + return flow; + } + + @Override + public List<ConfigVerificationResult> verifyConfigurationStep(final String stepName, final Map<String, String> propertyValueOverrides, final FlowContext flowContext) { + return List.of(); + } + + @Override + public List<ConfigurationStep> getConfigurationSteps() { + return configurationSteps; + } + + @Override + public void applyUpdate(final FlowContext workingFlowContext, final FlowContext activeFlowContext) { + } +} + diff --git a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector index c8e0d0ed64..a54f75d132 100644 --- a/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector +++ b/nifi-system-tests/nifi-system-test-extensions-bundle/nifi-system-test-extensions/src/main/resources/META-INF/services/org.apache.nifi.components.connector.Connector @@ -16,3 +16,4 @@ org.apache.nifi.connectors.tests.system.NopConnector org.apache.nifi.connectors.tests.system.AssetConnector org.apache.nifi.connectors.tests.system.DataQueuingConnector +org.apache.nifi.connectors.tests.system.NestedProcessGroupConnector diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorCrudIT.java b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorCrudIT.java index fb616c6d4b..c1098c4d19 100644 --- a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorCrudIT.java +++ b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorCrudIT.java @@ -17,6 +17,7 @@ package org.apache.nifi.tests.system.connectors; +import jakarta.ws.rs.NotFoundException; import org.apache.nifi.components.ConfigVerificationResult.Outcome; import org.apache.nifi.components.connector.ConnectorState; import org.apache.nifi.tests.system.NiFiSystemIT; @@ -24,18 +25,24 @@ import org.apache.nifi.toolkit.client.NiFiClientException; import org.apache.nifi.web.api.dto.ConfigVerificationResultDTO; import org.apache.nifi.web.api.dto.ConnectorConfigurationDTO; import org.apache.nifi.web.api.dto.ConnectorValueReferenceDTO; +import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO; import org.apache.nifi.web.api.entity.ConnectorEntity; import org.apache.nifi.web.api.entity.ParameterContextsEntity; import org.apache.nifi.web.api.entity.ParameterProviderEntity; +import org.apache.nifi.web.api.entity.ProcessGroupEntity; +import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity; import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class ConnectorCrudIT extends NiFiSystemIT { @@ -162,4 +169,46 @@ public class ConnectorCrudIT extends NiFiSystemIT { // Delete getNifiClient().getConnectorClient().deleteConnector(connector); } + + @Test + public void testProcessGroupAccessibility() throws NiFiClientException, IOException { + final ConnectorEntity connector = getClientUtil().createConnector("NestedProcessGroupConnector"); + assertNotNull(connector); + + final ConnectorEntity updatedConnector = getNifiClient().getConnectorClient().getConnector(connector.getId()); + final String managedProcessGroupId = updatedConnector.getComponent().getManagedProcessGroupId(); + assertNotNull(managedProcessGroupId); + + final ProcessGroupFlowEntity connectorFlowEntity = getNifiClient().getConnectorClient().getFlow(connector.getId(), managedProcessGroupId); + assertNotNull(connectorFlowEntity); + + final ProcessGroupFlowDTO connectorFlow = connectorFlowEntity.getProcessGroupFlow(); + assertNotNull(connectorFlow); + assertEquals(managedProcessGroupId, connectorFlow.getId()); + + try { + getNifiClient().getFlowClient().getProcessGroup(managedProcessGroupId); + fail("Was able to retrieve connector-managed process group via FlowClient"); + } catch (final NiFiClientException e) { + assertInstanceOf(NotFoundException.class, e.getCause()); + } + + final Set<ProcessGroupEntity> childGroups = connectorFlow.getFlow().getProcessGroups(); + assertEquals(1, childGroups.size(), "Expected exactly one child process group"); + + final ProcessGroupEntity childGroup = childGroups.iterator().next(); + final String childGroupId = childGroup.getId(); + assertNotNull(childGroupId); + + final ProcessGroupFlowEntity childFlowEntity = getNifiClient().getConnectorClient().getFlow(connector.getId(), childGroupId); + assertNotNull(childFlowEntity); + assertEquals(childGroupId, childFlowEntity.getProcessGroupFlow().getId()); + + try { + getNifiClient().getFlowClient().getProcessGroup(childGroupId); + fail("Was able to retrieve child process group of connector-managed flow via FlowClient"); + } catch (final NiFiClientException e) { + assertInstanceOf(NotFoundException.class, e.getCause()); + } + } } diff --git a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java index 923604ba5f..1e95222225 100644 --- a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java +++ b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java @@ -234,15 +234,15 @@ public interface ConnectorClient { ProcessGroupFlowEntity getFlow(String connectorId) throws NiFiClientException, IOException; /** - * Gets the flow for the process group managed by a connector. + * Gets the flow for a specific process group within a connector's managed flow. * * @param connectorId the connector ID - * @param uiOnly whether to return only UI-specific fields + * @param processGroupId the process group ID within the connector's managed flow * @return the process group flow entity * @throws NiFiClientException if an error occurs during the request * @throws IOException if an I/O error occurs */ - ProcessGroupFlowEntity getFlow(String connectorId, boolean uiOnly) throws NiFiClientException, IOException; + ProcessGroupFlowEntity getFlow(String connectorId, String processGroupId) throws NiFiClientException, IOException; /** * Gets the status for the process group managed by a connector. diff --git a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java index 8df19b09d5..b5ad5878d5 100644 --- a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java +++ b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java @@ -40,11 +40,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.Objects; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.Objects; /** * Jersey implementation of ConnectorClient. @@ -361,21 +361,21 @@ public class JerseyConnectorClient extends AbstractJerseyClient implements Conne @Override public ProcessGroupFlowEntity getFlow(final String connectorId) throws NiFiClientException, IOException { - return getFlow(connectorId, false); + final ConnectorEntity connector = getConnector(connectorId); + final String managedProcessGroupId = connector.getComponent().getManagedProcessGroupId(); + return getFlow(connectorId, managedProcessGroupId); } @Override - public ProcessGroupFlowEntity getFlow(final String connectorId, final boolean uiOnly) throws NiFiClientException, IOException { + public ProcessGroupFlowEntity getFlow(final String connectorId, final String processGroupId) throws NiFiClientException, IOException { Objects.requireNonNull(connectorId, "Connector ID required"); + Objects.requireNonNull(processGroupId, "Process Group ID required"); return executeAction("Error retrieving connector flow", () -> { WebTarget target = connectorTarget - .path("/flow") - .resolveTemplate("id", connectorId); - - if (uiOnly) { - target = target.queryParam("uiOnly", "true"); - } + .path("/flow/process-groups/{processGroupId}") + .resolveTemplate("id", connectorId) + .resolveTemplate("processGroupId", processGroupId); return getRequestBuilder(target).get(ProcessGroupFlowEntity.class); });
