diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMerger.java b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMerger.java index a56c89989b4e..bbc7a248f128 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMerger.java +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMerger.java @@ -62,6 +62,7 @@ public static void merge(final ParameterContextEntity target, final Map entityMap) { final Map mergedBoundGroups = new HashMap<>(); final Map> affectedComponentsByParameterName = new HashMap<>(); + final Set parameterNamesWithReferencingComponents = new HashSet<>(); final Set unwritableParameters = new HashSet<>(); for (final Map.Entry entry : entityMap.entrySet()) { @@ -94,14 +95,17 @@ public static void merge(final ParameterContextDTO target, final Map affectedComponentsById = affectedComponentsByParameterName.computeIfAbsent(parameterDto.getName(), key -> new HashMap<>()); - for (final AffectedComponentEntity referencingComponent : parameterDto.getReferencingComponents()) { - AffectedComponentEntity mergedAffectedComponent = affectedComponentsById.get(referencingComponent.getId()); - if (mergedAffectedComponent == null) { - affectedComponentsById.put(referencingComponent.getId(), referencingComponent); - continue; - } + if (parameterDto.getReferencingComponents() != null) { + parameterNamesWithReferencingComponents.add(parameterDto.getName()); + for (final AffectedComponentEntity referencingComponent : parameterDto.getReferencingComponents()) { + AffectedComponentEntity mergedAffectedComponent = affectedComponentsById.get(referencingComponent.getId()); + if (mergedAffectedComponent == null) { + affectedComponentsById.put(referencingComponent.getId(), referencingComponent); + continue; + } - merge(mergedAffectedComponent, referencingComponent); + merge(mergedAffectedComponent, referencingComponent); + } } } } @@ -117,8 +121,12 @@ public static void merge(final ParameterContextDTO target, final Map componentMap = affectedComponentsByParameterName.get(parameterDto.getName()); - parameterDto.setReferencingComponents(new HashSet<>(componentMap.values())); + // Only overwrite referencing components if at least one node actually reported them; otherwise leave the DTO's + // existing value (null) as-is, since null indicates the caller asked to exclude referencing components. + if (parameterNamesWithReferencingComponents.contains(parameterDto.getName())) { + final Map componentMap = affectedComponentsByParameterName.get(parameterDto.getName()); + parameterDto.setReferencingComponents(new HashSet<>(componentMap.values())); + } } } diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMergerTest.java b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMergerTest.java new file mode 100644 index 000000000000..115a498f85e4 --- /dev/null +++ b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/ParameterContextMergerTest.java @@ -0,0 +1,93 @@ +/* + * 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.cluster.coordination.http.endpoints; + +import org.apache.nifi.cluster.protocol.NodeIdentifier; +import org.apache.nifi.web.api.dto.ParameterContextDTO; +import org.apache.nifi.web.api.dto.ParameterDTO; +import org.apache.nifi.web.api.entity.AffectedComponentEntity; +import org.apache.nifi.web.api.entity.ParameterEntity; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +class ParameterContextMergerTest { + + @Test + void testMergePreservesNullReferencingComponentsWhenExcludedByEveryNode() { + final Map entityMap = new HashMap<>(); + entityMap.put(getNodeIdentifier("node1", 8000), createParameterContextDto("param1", null)); + entityMap.put(getNodeIdentifier("node2", 8010), createParameterContextDto("param1", null)); + + final ParameterContextDTO target = createParameterContextDto("param1", null); + + ParameterContextMerger.merge(target, entityMap); + + final ParameterDTO mergedParameter = target.getParameters().iterator().next().getParameter(); + assertNull(mergedParameter.getReferencingComponents(), + "Referencing components should remain null when every node excluded them from its response, rather than being coerced into an empty collection"); + } + + @Test + void testMergeCombinesReferencingComponentsAcrossNodesWhenIncluded() { + final Map entityMap = new HashMap<>(); + entityMap.put(getNodeIdentifier("node1", 8000), createParameterContextDto("param1", Set.of(createAffectedComponent("component1")))); + entityMap.put(getNodeIdentifier("node2", 8010), createParameterContextDto("param1", Set.of(createAffectedComponent("component2")))); + + final ParameterContextDTO target = createParameterContextDto("param1", Set.of()); + + ParameterContextMerger.merge(target, entityMap); + + final ParameterDTO mergedParameter = target.getParameters().iterator().next().getParameter(); + assertNotNull(mergedParameter.getReferencingComponents()); + assertEquals(2, mergedParameter.getReferencingComponents().size()); + } + + private ParameterContextDTO createParameterContextDto(final String parameterName, final Set referencingComponents) { + final ParameterDTO parameterDto = new ParameterDTO(); + parameterDto.setName(parameterName); + parameterDto.setReferencingComponents(referencingComponents); + + final ParameterEntity parameterEntity = new ParameterEntity(); + parameterEntity.setParameter(parameterDto); + parameterEntity.setCanWrite(true); + + final ParameterContextDTO contextDto = new ParameterContextDTO(); + contextDto.setId("context1"); + contextDto.setParameters(new HashSet<>(Set.of(parameterEntity))); + contextDto.setBoundProcessGroups(new HashSet<>()); + + return contextDto; + } + + private AffectedComponentEntity createAffectedComponent(final String id) { + final AffectedComponentEntity entity = new AffectedComponentEntity(); + entity.setId(id); + return entity; + } + + private NodeIdentifier getNodeIdentifier(final String id, final int port) { + return new NodeIdentifier(id, "localhost", port, "localhost", port + 1, "localhost", port + 2, port + 3, true); + } +} diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java index 2313b34f977c..ecbfcf3d9726 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java @@ -294,11 +294,12 @@ Set getConnectorControllerServices(String connectorId, * Returns the parameter context bound to the specified process group within the connector's hierarchy. Sensitive parameter values are masked * by the underlying DTO factory. * - * @param connectorId the connector id - * @param processGroupId the process group id within the connector's hierarchy + * @param connectorId the connector id + * @param processGroupId the process group id within the connector's hierarchy + * @param includeReferences whether to include parameters' referencing components * @return the parameter context entity with effective parameters (inherited included), or {@code null} if the process group has no bound parameter context */ - ParameterContextEntity getConnectorParameterContext(String connectorId, String processGroupId); + ParameterContextEntity getConnectorParameterContext(String connectorId, String processGroupId, boolean includeReferences); void verifyCanVerifyConnectorConfigurationStep(String connectorId, String configurationStepName); @@ -1407,9 +1408,10 @@ Set getControllerServiceTypes(final String serviceType, final /** * Returns the Set of all Parameter Context Entities for the current user + * @param includeReferences whether to include parameters' referencing components * @return the Set of all Parameter Context Entities for the current user */ - Set getParameterContexts(); + Set getParameterContexts(boolean includeReferences); /** * Returns the Parameter Context with the given name @@ -1425,33 +1427,39 @@ Set getControllerServiceTypes(final String serviceType, final * @param parameterContextId the ID of the Parameter Context * @param includeInheritedParameters Whether to include inherited parameters (and thus overridden values) * @param user the user on whose behalf the Parameter Context is being retrieved + * @param includeReferences whether to include parameters' referencing components * @return the ParameterContextEntity */ - ParameterContextEntity getParameterContext(String parameterContextId, boolean includeInheritedParameters, NiFiUser user); + ParameterContextEntity getParameterContext(String parameterContextId, boolean includeInheritedParameters, NiFiUser user, boolean includeReferences); /** * Creates a new Parameter Context - * @param revision the revision for the newly created Parameter Context - * @param parameterContext the Parameter Context + * + * @param revision the revision for the newly created Parameter Context + * @param parameterContext the Parameter Context + * @param includeReferences whether to include parameters' referencing components * @return a ParameterContextEntity representing the newly created ParameterContext */ - ParameterContextEntity createParameterContext(Revision revision, ParameterContextDTO parameterContext); + ParameterContextEntity createParameterContext(Revision revision, ParameterContextDTO parameterContext, boolean includeReferences); /** * Updates the Parameter Context * @param revision the current revision of the Parameter Context * @param parameterContext the updated version of the ParameterContext + * @param includeReferences whether to include parameters' referencing components * @return the updated Parameter Context Entity */ - ParameterContextEntity updateParameterContext(Revision revision, ParameterContextDTO parameterContext); + ParameterContextEntity updateParameterContext(Revision revision, ParameterContextDTO parameterContext, boolean includeReferences); /** * Deletes the Parameter Context - * @param revision the revision of the Parameter Context + * + * @param revision the revision of the Parameter Context * @param parameterContextId the ID of the Parameter Context + * @param includeReferences whether to include parameters' referencing components * @return a Parameter Context Entity that represents the Parameter Context that was deleted */ - ParameterContextEntity deleteParameterContext(Revision revision, String parameterContextId); + ParameterContextEntity deleteParameterContext(Revision revision, String parameterContextId, boolean includeReferences); /** * Performs validation of all components that make use of the Parameter Context with the same ID as the given DTO, but validating against the Parameters @@ -2736,12 +2744,16 @@ ControllerServiceReferencingComponentsEntity updateControllerServiceReferencingC /** * Returns a list of ParameterContext entities representing updates needed in order to apply the fetched * parameters from the parameter provider to the referencing parameter contexts - * @param parameterProviderId parameter provider id + * + * @param parameterProviderId parameter provider id * @param parameterGroupConfigurations Configuration for each fetched Parameter Group. Any parameters not found in this set will not be included in the update. + * @param includeReferences whether to include parameters' referencing components * @return The list of ParameterContextEntity objects representing required updates to referencing * parameter contexts */ - List getParameterContextUpdatesForAppliedParameters(String parameterProviderId, Collection parameterGroupConfigurations); + List getParameterContextUpdatesForAppliedParameters(String parameterProviderId, + Collection parameterGroupConfigurations, + boolean includeReferences); /** * Gets the references for specified parameter provider. diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index 6688dd48152a..74aa6f54986f 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -1382,13 +1382,13 @@ public void verifyUpdateParameterContext(final ParameterContextDTO parameterCont } @Override - public ParameterContextEntity updateParameterContext(final Revision revision, final ParameterContextDTO parameterContextDto) { + public ParameterContextEntity updateParameterContext(final Revision revision, final ParameterContextDTO parameterContextDto, final boolean includeReferences) { // get the component, ensure we have access to it, and perform the update request final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextDto.getId()); final RevisionUpdate snapshot = updateComponent(revision, parameterContext, () -> parameterContextDAO.updateParameterContext(parameterContextDto), - context -> dtoFactory.createParameterContextDto(context, revisionManager, false, parameterContextDAO)); + context -> dtoFactory.createParameterContextDto(context, revisionManager, false, parameterContextDAO, includeReferences)); final PermissionsDTO permissions = dtoFactory.createPermissionsDto(parameterContext); final RevisionDTO revisionDto = dtoFactory.createRevisionDTO(snapshot.getLastModification()); @@ -1397,17 +1397,17 @@ public ParameterContextEntity updateParameterContext(final Revision revision, fi } @Override - public ParameterContextEntity getParameterContext(final String parameterContextId, final boolean includeInheritedParameters, final NiFiUser user) { + public ParameterContextEntity getParameterContext(final String parameterContextId, final boolean includeInheritedParameters, final NiFiUser user, final boolean includeReferences) { final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextId); - return createParameterContextEntity(parameterContext, includeInheritedParameters, user, parameterContextDAO); + return createParameterContextEntity(parameterContext, includeInheritedParameters, user, parameterContextDAO, includeReferences); } @Override - public Set getParameterContexts() { + public Set getParameterContexts(final boolean includeReferences) { final NiFiUser user = NiFiUserUtils.getNiFiUser(); final Set entities = parameterContextDAO.getParameterContexts().stream() - .map(context -> createParameterContextEntity(context, false, user, parameterContextDAO)) + .map(context -> createParameterContextEntity(context, false, user, parameterContextDAO, includeReferences)) .collect(Collectors.toSet()); return entities; @@ -1436,11 +1436,11 @@ public ParameterContext getParameterContextByName(final String parameterContextN } private ParameterContextEntity createParameterContextEntity(final ParameterContext parameterContext, final boolean includeInheritedParameters, final NiFiUser user, - final ParameterContextLookup parameterContextLookup) { + final ParameterContextLookup parameterContextLookup, final boolean includeReferences) { final PermissionsDTO permissions = dtoFactory.createPermissionsDto(parameterContext, user); final RevisionDTO revisionDto = dtoFactory.createRevisionDTO(revisionManager.getRevision(parameterContext.getIdentifier())); final ParameterContextDTO parameterContextDto = dtoFactory.createParameterContextDto(parameterContext, revisionManager, includeInheritedParameters, - parameterContextLookup); + parameterContextLookup, includeReferences); final ParameterContextEntity entity = entityFactory.createParameterContextEntity(parameterContextDto, revisionDto, permissions); return entity; } @@ -1542,7 +1542,7 @@ private Asset getAsset(final String assetId) { } @Override - public ParameterContextEntity createParameterContext(final Revision revision, final ParameterContextDTO parameterContextDto) { + public ParameterContextEntity createParameterContext(final Revision revision, final ParameterContextDTO parameterContextDto, final boolean includeReferences) { final NiFiUser user = NiFiUserUtils.getNiFiUser(); // request claim for component to be created... revision already verified (version == 0) @@ -1557,7 +1557,7 @@ public ParameterContextEntity createParameterContext(final Revision revision, fi controllerFacade.save(); final ParameterContextDTO dto = dtoFactory.createParameterContextDto(parameterContext, revisionManager, false, - parameterContextDAO); + parameterContextDAO, includeReferences); final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity()); return new StandardRevisionUpdate<>(dto, lastMod); }); @@ -1574,7 +1574,7 @@ public void verifyDeleteParameterContext(final String parameterContextId) { } @Override - public ParameterContextEntity deleteParameterContext(final Revision revision, final String parameterContextId) { + public ParameterContextEntity deleteParameterContext(final Revision revision, final String parameterContextId, final boolean includeReferences) { final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextId); final PermissionsDTO permissions = dtoFactory.createPermissionsDto(parameterContext); final ParameterContextDTO snapshot = deleteComponent( @@ -1582,7 +1582,7 @@ public ParameterContextEntity deleteParameterContext(final Revision revision, fi parameterContext.getResource(), () -> parameterContextDAO.deleteParameterContext(parameterContextId), true, - dtoFactory.createParameterContextDto(parameterContext, revisionManager, false, parameterContextDAO)); + dtoFactory.createParameterContextDto(parameterContext, revisionManager, false, parameterContextDAO, includeReferences)); return entityFactory.createParameterContextEntity(snapshot, null, permissions); @@ -4138,7 +4138,7 @@ public Set getConnectorControllerServices(final String } @Override - public ParameterContextEntity getConnectorParameterContext(final String connectorId, final String processGroupId) { + public ParameterContextEntity getConnectorParameterContext(final String connectorId, final String processGroupId, final boolean includeReferences) { final ConnectorNode connectorNode = connectorDAO.getConnector(connectorId, ConnectorSyncMode.LOCAL_ONLY); final ProcessGroup managedProcessGroup = connectorNode.getActiveFlowContext().getManagedProcessGroup(); final ProcessGroup targetProcessGroup = managedProcessGroup.findProcessGroup(processGroupId); @@ -4155,7 +4155,7 @@ public ParameterContextEntity getConnectorParameterContext(final String connecto // global flow's ParameterContextManager, so a DAO-backed lookup would fail to resolve inherited parameters. // The DTO factory walks the in-memory inheritance graph reachable from the supplied context to resolve // parameter source contexts for connector-managed flows, making an empty lookup safe here. - return createParameterContextEntity(parameterContext, true, NiFiUserUtils.getNiFiUser(), ParameterContextLookup.EMPTY); + return createParameterContextEntity(parameterContext, true, NiFiUserUtils.getNiFiUser(), ParameterContextLookup.EMPTY, includeReferences); } @Override @@ -4431,7 +4431,9 @@ public ParameterProviderEntity fetchParameters(final String parameterProviderId) } @Override - public List getParameterContextUpdatesForAppliedParameters(final String parameterProviderId, final Collection parameterGroupConfigurations) { + public List getParameterContextUpdatesForAppliedParameters(final String parameterProviderId, + final Collection parameterGroupConfigurations, + final boolean includeReferences) { final NiFiUser user = NiFiUserUtils.getNiFiUser(); final Map parameterGroupConfigurationMap = parameterGroupConfigurations.stream() .collect(Collectors.toMap(ParameterGroupConfiguration::getParameterContextName, Function.identity())); @@ -4442,7 +4444,7 @@ public List getParameterContextUpdatesForAppliedParamete .map(parametersApplication -> { final ParameterContext parameterContext = parametersApplication.getParameterContext(); final ParameterGroupConfiguration parameterGroupConfiguration = parameterGroupConfigurationMap.get(parameterContext.getName()); - final ParameterContextEntity entity = createParameterContextEntity(parameterContext, false, user, parameterContextDAO); + final ParameterContextEntity entity = createParameterContextEntity(parameterContext, false, user, parameterContextDAO, includeReferences); final ParameterProviderConfigurationDTO parameterProviderConfiguration = entity.getComponent().getParameterProviderConfiguration().getComponent(); parameterProviderConfiguration.setSynchronized(parameterGroupConfiguration.isSynchronized()); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java index 81f16ad70578..95b894fd357b 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java @@ -121,6 +121,7 @@ public abstract class ApplicationResource { public static final String VERSION = "version"; public static final String CLIENT_ID = "clientId"; public static final String DISCONNECTED_NODE_ACKNOWLEDGED = "disconnectedNodeAcknowledged"; + public static final String INCLUDE_REFERENCING_COMPONENTS = "includeReferencingComponents"; protected static final String NON_GUARANTEED_ENDPOINT = "Note: This endpoint is subject to change as NiFi and it's REST API evolve."; diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java index 7836582db82a..2523590c7d7d 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java @@ -2061,7 +2061,7 @@ public Response getControllerServicesFromConnectorProcessGroup( @QueryParam("includeDescendantGroups") @DefaultValue("false") final boolean includeDescendantGroups, @Parameter(description = "Whether or not to include services' referencing components in the response") - @QueryParam("includeReferencingComponents") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (isReplicateRequest()) { @@ -2123,7 +2123,9 @@ public Response getParameterContextForConnectorProcessGroup( @Parameter(description = "The connector id.", required = true) @PathParam("connectorId") final String connectorId, @Parameter(description = "The process group id.", required = true) - @PathParam("processGroupId") final String processGroupId) { + @PathParam("processGroupId") final String processGroupId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (isReplicateRequest()) { return replicate(HttpMethod.GET); @@ -2135,7 +2137,7 @@ public Response getParameterContextForConnectorProcessGroup( connector.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()); }); - final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId); + final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId, includeReferences); if (entity == null) { return Response.noContent().build(); } diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java index 753c6c66a97d..dea734dc0236 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java @@ -648,7 +648,7 @@ public Response getFlowMetrics( ) public Response getControllerServicesFromController( @Parameter(description = "Whether or not to include services' referencing components in the response") - @QueryParam("includeReferencingComponents") @DefaultValue("true") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") boolean includeReferences, @QueryParam("uiOnly") @DefaultValue("false") final boolean uiOnly) { @@ -711,7 +711,7 @@ public Response getControllerServicesFromGroup( @QueryParam("includeDescendantGroups") @DefaultValue("false") final boolean includeDescendantGroups, @Parameter(description = "Whether or not to include services' referencing components in the response") - @QueryParam("includeReferencingComponents") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences, @QueryParam("uiOnly") @DefaultValue("false") final boolean uiOnly) { @@ -3839,14 +3839,16 @@ public Response getConnectionStatusHistory( @SecurityRequirement(name = "Read - /parameter-contexts/{id} for each Parameter Context") } ) - public Response getParameterContexts() { + public Response getParameterContexts( + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { authorizeFlow(); if (isReplicateRequest()) { return replicate(HttpMethod.GET); } - final Set parameterContexts = serviceFacade.getParameterContexts(); + final Set parameterContexts = serviceFacade.getParameterContexts(includeReferences); parameterContexts.forEach(entity -> entity.setUri(generateResourceUri("parameter-contexts", entity.getId()))); final ParameterContextsEntity entity = new ParameterContextsEntity(); diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java index 87e5ac45384b..e871709493ef 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java @@ -247,7 +247,9 @@ public Response getParameterContext( description = "Whether or not to include inherited parameters from other parameter contexts, and therefore also overridden values. " + "If true, the result will be the 'effective' parameter context." ) @QueryParam("includeInheritedParameters") - @DefaultValue("false") final boolean includeInheritedParameters) { + @DefaultValue("false") final boolean includeInheritedParameters, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { // authorize access authorizeReadParameterContext(parameterContextId); @@ -256,7 +258,7 @@ public Response getParameterContext( } // get the specified parameter context - final ParameterContextEntity entity = serviceFacade.getParameterContext(parameterContextId, includeInheritedParameters, NiFiUserUtils.getNiFiUser()); + final ParameterContextEntity entity = serviceFacade.getParameterContext(parameterContextId, includeInheritedParameters, NiFiUserUtils.getNiFiUser(), includeReferences); entity.setUri(generateResourceUri("parameter-contexts", entity.getId())); // generate the response @@ -282,7 +284,9 @@ public Response getParameterContext( } ) public Response createParameterContext( - @Parameter(description = "The Parameter Context.", required = true) final ParameterContextEntity requestEntity) { + @Parameter(description = "The Parameter Context.", required = true) final ParameterContextEntity requestEntity, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (requestEntity == null || requestEntity.getComponent() == null) { throw new IllegalArgumentException("Parameter Context must be specified"); @@ -318,7 +322,7 @@ public Response createParameterContext( entity.getComponent().setId(contextId); final Revision revision = getRevision(entity.getRevision(), contextId); - final ParameterContextEntity contextEntity = serviceFacade.createParameterContext(revision, entity.getComponent()); + final ParameterContextEntity contextEntity = serviceFacade.createParameterContext(revision, entity.getComponent(), includeReferences); // generate a 201 created response final String uri = generateResourceUri("parameter-contexts", contextEntity.getId()); @@ -355,7 +359,9 @@ public Response createParameterContext( ) public Response updateParameterContext( @PathParam("id") String contextId, - @Parameter(description = "The updated Parameter Context", required = true) final ParameterContextEntity requestEntity) { + @Parameter(description = "The updated Parameter Context", required = true) final ParameterContextEntity requestEntity, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { // Validate request if (requestEntity.getId() == null) { @@ -396,7 +402,7 @@ public Response updateParameterContext( lookup -> authorizeReadWriteParameterContextWithComponents(lookup, contextId, requestEntity, affectedComponents, user), () -> serviceFacade.verifyUpdateParameterContext(updateDto, true), (rev, entity) -> { - final ParameterContextEntity updatedEntity = serviceFacade.updateParameterContext(rev, entity.getComponent()); + final ParameterContextEntity updatedEntity = serviceFacade.updateParameterContext(rev, entity.getComponent(), includeReferences); updatedEntity.setUri(generateResourceUri("parameter-contexts", entity.getId())); return generateOkResponse(updatedEntity).build(); @@ -459,7 +465,7 @@ public Response createAsset( // Get the context or throw ResourceNotFoundException final NiFiUser user = NiFiUserUtils.getNiFiUser(); - final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(contextId, false, user); + final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(contextId, false, user, false); final Set affectedComponents = serviceFacade.getComponentsAffectedByParameterContextUpdate(Collections.singletonList(contextEntity.getComponent())); final Optional previousAsset = assetManager.getAssets(contextId).stream().filter(asset -> asset.getName().equals(sanitizedAssetName)).findAny(); @@ -654,7 +660,7 @@ public Response deleteAsset( // Get the context or throw ResourceNotFoundException final NiFiUser user = NiFiUserUtils.getNiFiUser(); - final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, false, user); + final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, false, user, false); final AssetDTO assetDTO = new AssetDTO(); assetDTO.setId(assetId); @@ -712,7 +718,9 @@ public Response deleteAsset( ) public Response submitParameterContextUpdate( @PathParam("contextId") final String contextId, - @Parameter(description = "The updated version of the parameter context.", required = true) final ParameterContextEntity requestEntity) { + @Parameter(description = "The updated version of the parameter context.", required = true) final ParameterContextEntity requestEntity, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (requestEntity == null) { throw new IllegalArgumentException("Parameter Context must be specified."); @@ -774,7 +782,7 @@ public Response submitParameterContextUpdate( // Verify Request serviceFacade.verifyUpdateParameterContext(contextDto, false); }, - this::submitUpdateRequest + (rev, wrapper) -> submitUpdateRequest(rev, wrapper, includeReferences) ); } @@ -913,11 +921,13 @@ public Response getParameterContextUpdate( @Parameter(description = "The ID of the Parameter Context") @PathParam("contextId") final String contextId, @Parameter(description = "The ID of the Update Request") - @PathParam("requestId") final String updateRequestId) { + @PathParam("requestId") final String updateRequestId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { authorizeReadParameterContext(contextId); - return retrieveUpdateRequest("update-requests", contextId, updateRequestId); + return retrieveUpdateRequest("update-requests", contextId, updateRequestId, includeReferences); } @DELETE @@ -949,10 +959,12 @@ public Response deleteUpdateRequest( @Parameter(description = "The ID of the ParameterContext") @PathParam("contextId") final String contextId, @Parameter(description = "The ID of the Update Request") - @PathParam("requestId") final String updateRequestId) { + @PathParam("requestId") final String updateRequestId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { authorizeReadParameterContext(contextId); - return deleteUpdateRequest("update-requests", contextId, updateRequestId, disconnectedNodeAcknowledged.booleanValue()); + return deleteUpdateRequest("update-requests", contextId, updateRequestId, disconnectedNodeAcknowledged.booleanValue(), includeReferences); } @DELETE @@ -992,7 +1004,9 @@ public Response deleteParameterContext( @QueryParam(DISCONNECTED_NODE_ACKNOWLEDGED) @DefaultValue("false") final Boolean disconnectedNodeAcknowledged, @Parameter(description = "The Parameter Context ID.") - @PathParam("id") final String parameterContextId) { + @PathParam("id") final String parameterContextId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (isReplicateRequest()) { return replicate(HttpMethod.DELETE); @@ -1009,7 +1023,7 @@ public Response deleteParameterContext( authorizeReadWriteParameterContext(parameterContextId); final NiFiUser user = NiFiUserUtils.getNiFiUser(); - final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, false, user); + final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, false, user, false); for (final ProcessGroupEntity boundGroupEntity : contextEntity.getComponent().getBoundProcessGroups()) { final String groupId = boundGroupEntity.getId(); final Authorizable groupAuthorizable = lookup.getProcessGroup(groupId).getAuthorizable(); @@ -1020,7 +1034,7 @@ public Response deleteParameterContext( () -> serviceFacade.verifyDeleteParameterContext(parameterContextId), (revision, groupEntity) -> { // disconnect from version control - final ParameterContextEntity entity = serviceFacade.deleteParameterContext(revision, parameterContextId); + final ParameterContextEntity entity = serviceFacade.deleteParameterContext(revision, parameterContextId, includeReferences); // generate the response return generateOkResponse(entity).build(); @@ -1094,7 +1108,7 @@ public Response submitValidationRequest( } private void authorizeReferencingComponents(final String parameterContextId, final AuthorizableLookup lookup, final NiFiUser user) { - final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, false, NiFiUserUtils.getNiFiUser()); + final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, false, NiFiUserUtils.getNiFiUser(), true); for (final ParameterEntity parameterEntity : context.getComponent().getParameters()) { final ParameterDTO dto = parameterEntity.getParameter(); @@ -1234,7 +1248,7 @@ private ComponentValidationResultsEntity validateComponents(final ParameterConte return resultsEntity; } - private Response submitUpdateRequest(final Revision requestRevision, final InitiateChangeParameterContextRequestWrapper requestWrapper) { + private Response submitUpdateRequest(final Revision requestRevision, final InitiateChangeParameterContextRequestWrapper requestWrapper, final boolean includeReferences) { // Create an asynchronous request that will occur in the background, because this request may // result in stopping components, which can take an indeterminate amount of time. final String requestId = UUID.randomUUID().toString(); @@ -1265,7 +1279,7 @@ private Response submitUpdateRequest(final Revision requestRevision, final Initi updateRequestManager.submitRequest("update-requests", requestId, request, updateTask); // Generate the response. - final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(request, "update-requests", contextId, requestId); + final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(request, "update-requests", contextId, requestId, includeReferences); return generateOkResponse(updateRequestEntity).build(); } @@ -1332,7 +1346,7 @@ private ParameterContextValidationRequestEntity createValidationRequestEntity(fi return entity; } - private Response retrieveUpdateRequest(final String requestType, final String contextId, final String requestId) { + private Response retrieveUpdateRequest(final String requestType, final String contextId, final String requestId, final boolean includeReferences) { if (requestId == null) { throw new IllegalArgumentException("Request ID must be specified."); } @@ -1341,11 +1355,12 @@ private Response retrieveUpdateRequest(final String requestType, final String co // request manager will ensure that the current is the user that submitted this request final AsynchronousWebRequest, List> asyncRequest = updateRequestManager.getRequest(requestType, requestId, user); - final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(asyncRequest, requestType, contextId, requestId); + final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(asyncRequest, requestType, contextId, requestId, includeReferences); return generateOkResponse(updateRequestEntity).build(); } - private Response deleteUpdateRequest(final String requestType, final String contextId, final String requestId, final boolean disconnectedNodeAcknowledged) { + private Response deleteUpdateRequest(final String requestType, final String contextId, final String requestId, final boolean disconnectedNodeAcknowledged, + final boolean includeReferences) { if (requestId == null) { throw new IllegalArgumentException("Request ID must be specified."); } @@ -1366,12 +1381,12 @@ private Response deleteUpdateRequest(final String requestType, final String cont asyncRequest.cancel(); } - final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(asyncRequest, requestType, contextId, requestId); + final ParameterContextUpdateRequestEntity updateRequestEntity = createUpdateRequestEntity(asyncRequest, requestType, contextId, requestId, includeReferences); return generateOkResponse(updateRequestEntity).build(); } private ParameterContextUpdateRequestEntity createUpdateRequestEntity(final AsynchronousWebRequest, List> asyncRequest, - final String requestType, final String contextId, final String requestId) { + final String requestType, final String contextId, final String requestId, final boolean includeReferences) { final List initialRequestList = asyncRequest.getRequest(); // Safe because this is from the request, not the response final ParameterContextEntity initialEntity = initialRequestList.get(0); @@ -1404,7 +1419,7 @@ private ParameterContextUpdateRequestEntity createUpdateRequestEntity(final Asyn updateRequestDto.setReferencingComponents(new HashSet<>(affectedComponents.values())); // Populate the Affected Components - final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(asyncRequest.getComponentId(), false, NiFiUserUtils.getNiFiUser()); + final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(asyncRequest.getComponentId(), false, NiFiUserUtils.getNiFiUser(), includeReferences); final ParameterContextUpdateRequestEntity updateRequestEntity = new ParameterContextUpdateRequestEntity(); // If the request is complete, include the new representation of the Parameter Context along with its new Revision. Otherwise, do not include the information, since it is 'stale' diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java index 418ab7325bc0..0e471ad9d9d0 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java @@ -785,7 +785,9 @@ public Response fetchParameters( @Parameter( description = "The parameter fetch request.", required = true - ) final ParameterProviderParameterFetchEntity fetchParametersEntity) { + ) final ParameterProviderParameterFetchEntity fetchParametersEntity, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (fetchParametersEntity.getId() == null) { throw new IllegalArgumentException("The ID of the Parameter Provider must be specified"); @@ -815,7 +817,7 @@ public Response fetchParameters( final Collection referencingParameterContextDtos = new HashSet<>(); references.forEach(referencingEntity -> { final String parameterContextId = referencingEntity.getComponent().getId(); - final ParameterContextEntity parameterContextEntity = serviceFacade.getParameterContext(parameterContextId, true, user); + final ParameterContextEntity parameterContextEntity = serviceFacade.getParameterContext(parameterContextId, true, user, true); parameterContextEntity.getComponent().getParameters().stream() .filter(dto -> Boolean.TRUE.equals(dto.getParameter().getProvided())) .forEach(p -> referencingComponents.addAll(p.getParameter().getReferencingComponents())); @@ -854,7 +856,8 @@ public Response fetchParameters( parameterGroupConfigurations.add(new ParameterGroupConfiguration(group.getGroupName(), group.getParameterContextName(), updatedSensitivities, group.isSynchronized())); }); - final List parameterContextUpdates = serviceFacade.getParameterContextUpdatesForAppliedParameters(parameterProviderId, parameterGroupConfigurations); + final List parameterContextUpdates = + serviceFacade.getParameterContextUpdatesForAppliedParameters(parameterProviderId, parameterGroupConfigurations, includeReferences); final Set removedParameters = parameterContextUpdates.stream() .flatMap(context -> context.getComponent().getParameters().stream()) @@ -867,7 +870,7 @@ public Response fetchParameters( if (!affectedComponents.isEmpty()) { entity.getComponent().setAffectedComponents(affectedComponents); } - final Set parameterStatus = getParameterStatus(entity, parameterContextUpdates, removedParameters, user); + final Set parameterStatus = getParameterStatus(entity, parameterContextUpdates, removedParameters, user, includeReferences); if (!parameterStatus.isEmpty()) { entity.getComponent().setParameterStatus(parameterStatus); } @@ -879,7 +882,7 @@ public Response fetchParameters( } private void authorizeReferencingComponents(final String parameterContextId, final AuthorizableLookup lookup, final NiFiUser user) { - final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, false, NiFiUserUtils.getNiFiUser()); + final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, false, NiFiUserUtils.getNiFiUser(), true); for (final ParameterEntity parameterEntity : context.getComponent().getParameters()) { final ParameterDTO dto = parameterEntity.getParameter(); @@ -922,7 +925,9 @@ private void authorizeReferencingComponents(final String parameterContextId, fin public Response submitApplyParameters( @Parameter(description = "The ID of the Parameter Provider") @PathParam("providerId") final String parameterProviderId, - @Parameter(description = "The apply parameters request.", required = true) final ParameterProviderParameterApplicationEntity requestEntity) { + @Parameter(description = "The apply parameters request.", required = true) final ParameterProviderParameterApplicationEntity requestEntity, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { if (requestEntity == null) { throw new IllegalArgumentException("Apply Parameters Request must be specified."); @@ -967,14 +972,14 @@ public Response submitApplyParameters( .forEach(parameterGroupConfiguration -> { final ParameterContextEntity newParameterContext = getNewParameterContextEntity(parameterProviderId, parameterGroupConfiguration); try { - performParameterContextCreate(user, getAbsolutePath(), replicateRequest, newParameterContext); + performParameterContextCreate(user, getAbsolutePath(), replicateRequest, newParameterContext, includeReferences); } catch (final LifecycleManagementException e) { throw new RuntimeException("Failed to create Parameter Context " + parameterGroupConfiguration.getGroupName(), e); } }); // Get a list of parameter context entities representing changes needed in order to apply the fetched parameters - final List parameterContextUpdates = serviceFacade.getParameterContextUpdatesForAppliedParameters(parameterProviderId, parameterGroupConfigurations); + final List parameterContextUpdates = serviceFacade.getParameterContextUpdatesForAppliedParameters(parameterProviderId, parameterGroupConfigurations, includeReferences); final Set affectedComponents = getAffectedComponentEntities(parameterContextUpdates); logger.debug("Received Apply Request for Parameter Provider: {}; the following {} components will be affected: {}", requestEntity, affectedComponents.size(), affectedComponents); @@ -1005,7 +1010,7 @@ public Response submitApplyParameters( // Verify Request serviceFacade.verifyCanApplyParameters(parameterProviderId, parameterGroupConfigurations); }, - this::submitApplyRequest + (rev, wrapper) -> submitApplyRequest(rev, wrapper, includeReferences) ); } @@ -1017,7 +1022,7 @@ private Set getAffectedComponentEntities(final List getParameterStatus(final ParameterProviderEntity parameterProvider, final List parameterContextUpdates, - final Set removedParameters, final NiFiUser niFiUser) { + final Set removedParameters, final NiFiUser niFiUser, final boolean includeReferences) { final Set parameterStatus = new HashSet<>(); if (parameterProvider.getComponent() == null || parameterProvider.getComponent().getReferencingParameterContexts() == null) { return parameterStatus; @@ -1034,7 +1039,7 @@ private Set getParameterStatus(final ParameterProviderEntity for (final ParameterProviderReferencingComponentEntity reference : parameterProvider.getComponent().getReferencingParameterContexts()) { final String parameterContextId = reference.getComponent().getId(); - final ParameterContextEntity parameterContext = serviceFacade.getParameterContext(parameterContextId, false, niFiUser); + final ParameterContextEntity parameterContext = serviceFacade.getParameterContext(parameterContextId, false, niFiUser, includeReferences); if (parameterContext.getComponent() == null) { continue; } @@ -1108,11 +1113,13 @@ private Set getParameterStatus(final ParameterProviderEntity ) public Response getParameterProviderApplyParametersRequest( @Parameter(description = "The ID of the Parameter Provider") @PathParam("providerId") final String parameterProviderId, - @Parameter(description = "The ID of the Apply Parameters Request") @PathParam("requestId") final String applyParametersRequestId) { + @Parameter(description = "The ID of the Apply Parameters Request") @PathParam("requestId") final String applyParametersRequestId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { authorizeReadParameterProvider(parameterProviderId); - return retrieveApplyParametersRequest("apply-parameters-requests", parameterProviderId, applyParametersRequestId); + return retrieveApplyParametersRequest("apply-parameters-requests", parameterProviderId, applyParametersRequestId, includeReferences); } @DELETE @@ -1142,10 +1149,12 @@ public Response deleteApplyParametersRequest( ) @QueryParam(DISCONNECTED_NODE_ACKNOWLEDGED) @DefaultValue("false") final Boolean disconnectedNodeAcknowledged, @Parameter(description = "The ID of the Parameter Provider") @PathParam("providerId") final String parameterProviderId, - @Parameter(description = "The ID of the Apply Parameters Request") @PathParam("requestId") final String applyParametersRequestId) { + @Parameter(description = "The ID of the Apply Parameters Request") @PathParam("requestId") final String applyParametersRequestId, + @Parameter(description = "Whether or not to include parameters' referencing components in the response") + @QueryParam(INCLUDE_REFERENCING_COMPONENTS) @DefaultValue("true") final boolean includeReferences) { authorizeReadParameterProvider(parameterProviderId); - return deleteApplyParametersRequest("apply-parameters-requests", parameterProviderId, applyParametersRequestId, disconnectedNodeAcknowledged.booleanValue()); + return deleteApplyParametersRequest("apply-parameters-requests", parameterProviderId, applyParametersRequestId, disconnectedNodeAcknowledged.booleanValue(), includeReferences); } @POST @@ -1424,7 +1433,7 @@ private VerifyConfigRequestEntity createVerifyParameterProviderConfigRequestEnti return entity; } - private Response retrieveApplyParametersRequest(final String requestType, final String parameterProviderId, final String requestId) { + private Response retrieveApplyParametersRequest(final String requestType, final String parameterProviderId, final String requestId, final boolean includeReferences) { if (requestId == null) { throw new IllegalArgumentException("Request ID must be specified."); } @@ -1433,11 +1442,13 @@ private Response retrieveApplyParametersRequest(final String requestType, final // request manager will ensure that the current is the user that submitted this request final AsynchronousWebRequest, List> asyncRequest = updateRequestManager.getRequest(requestType, requestId, user); - final ParameterProviderApplyParametersRequestEntity applyParametersRequestEntity = createApplyParametersRequestEntity(asyncRequest, requestType, parameterProviderId, requestId); + final ParameterProviderApplyParametersRequestEntity applyParametersRequestEntity = + createApplyParametersRequestEntity(asyncRequest, requestType, parameterProviderId, requestId, includeReferences); return generateOkResponse(applyParametersRequestEntity).build(); } - private Response deleteApplyParametersRequest(final String requestType, final String parameterProviderId, final String requestId, final boolean disconnectedNodeAcknowledged) { + private Response deleteApplyParametersRequest(final String requestType, final String parameterProviderId, final String requestId, final boolean disconnectedNodeAcknowledged, + final boolean includeReferences) { if (requestId == null) { throw new IllegalArgumentException("Request ID must be specified."); } @@ -1458,12 +1469,14 @@ private Response deleteApplyParametersRequest(final String requestType, final St asyncRequest.cancel(); } - final ParameterProviderApplyParametersRequestEntity applyParametersRequestEntity = createApplyParametersRequestEntity(asyncRequest, requestType, parameterProviderId, requestId); + final ParameterProviderApplyParametersRequestEntity applyParametersRequestEntity = + createApplyParametersRequestEntity(asyncRequest, requestType, parameterProviderId, requestId, includeReferences); return generateOkResponse(applyParametersRequestEntity).build(); } private ParameterProviderApplyParametersRequestEntity createApplyParametersRequestEntity(final AsynchronousWebRequest, List> asyncRequest, - final String requestType, final String parameterProviderId, final String requestId) { + final String requestType, final String parameterProviderId, final String requestId, + final boolean includeReferences) { final ParameterProviderApplyParametersRequestEntity applyParametersRequestEntity = new ParameterProviderApplyParametersRequestEntity(); final ParameterProviderApplyParametersRequestDTO applyParametersRequestDTO = new ParameterProviderApplyParametersRequestDTO(); applyParametersRequestDTO.setComplete(asyncRequest.isComplete()); @@ -1495,7 +1508,12 @@ private ParameterProviderApplyParametersRequestEntity createApplyParametersReque // The AffectedComponentEntity itself does not evaluate equality based on component information. As a result, we want to de-dupe the entities based on their identifiers. final Map affectedComponents = new HashMap<>(); for (final ParameterEntity entity : parameterContextEntity.getComponent().getParameters()) { - for (final AffectedComponentEntity affectedComponentEntity : entity.getParameter().getReferencingComponents()) { + final Set referencingComponents = entity.getParameter().getReferencingComponents(); + if (referencingComponents == null) { + continue; + } + + for (final AffectedComponentEntity affectedComponentEntity : referencingComponents) { final AffectedComponentEntity updatedAffectedComponentEntity = serviceFacade.getUpdatedAffectedComponentEntity(affectedComponentEntity); final String affectedComponentEntityId = affectedComponentEntity.getId(); @@ -1505,7 +1523,7 @@ private ParameterProviderApplyParametersRequestEntity createApplyParametersReque } // Populate the Affected Components - final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextEntity.getId(), false, NiFiUserUtils.getNiFiUser()); + final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextEntity.getId(), false, NiFiUserUtils.getNiFiUser(), includeReferences); final ParameterContextUpdateEntity parameterContextUpdate = new ParameterContextUpdateEntity(); parameterContextUpdate.setReferencingComponents(new HashSet<>(affectedComponents.values())); @@ -1583,7 +1601,7 @@ private ParameterContextEntity getNewParameterContextEntity(final String paramet return parameterContextEntity; } - private Response submitApplyRequest(final Revision requestRevision, final InitiateParameterProviderApplyParametersRequestWrapper requestWrapper) { + private Response submitApplyRequest(final Revision requestRevision, final InitiateParameterProviderApplyParametersRequestWrapper requestWrapper, final boolean includeReferences) { // Create an asynchronous request that will occur in the background, because this request may // result in stopping components, which can take an indeterminate amount of time. final String requestId = UUID.randomUUID().toString(); @@ -1614,12 +1632,12 @@ private Response submitApplyRequest(final Revision requestRevision, final Initia // Generate the response. final ParameterProviderApplyParametersRequestEntity applicationRequestEntity = createApplyParametersRequestEntity( - request, "apply-parameters-requests", parameterProviderId, requestId); + request, "apply-parameters-requests", parameterProviderId, requestId, includeReferences); return generateOkResponse(applicationRequestEntity).build(); } private ParameterContextEntity performParameterContextCreate(final NiFiUser user, final URI exampleUri, final boolean replicateRequest, - final ParameterContextEntity parameterContext) throws LifecycleManagementException { + final ParameterContextEntity parameterContext, final boolean includeReferences) throws LifecycleManagementException { if (replicateRequest) { final URI updateUri; @@ -1644,14 +1662,14 @@ private ParameterContextEntity performParameterContextCreate(final NiFiUser user } final String parameterContextId = ParameterUpdateManager.getResponseEntity(clusterResponse, ParameterContextEntity.class).getId(); - return serviceFacade.getParameterContext(parameterContextId, false, user); + return serviceFacade.getParameterContext(parameterContextId, false, user, includeReferences); } else { serviceFacade.verifyCreateParameterContext(parameterContext.getComponent()); final String contextId = generateUuid(); parameterContext.getComponent().setId(contextId); final Revision revision = getRevision(parameterContext.getRevision(), contextId); - return serviceFacade.createParameterContext(revision, parameterContext.getComponent()); + return serviceFacade.createParameterContext(revision, parameterContext.getComponent(), includeReferences); } } diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java index 77c43f836d32..587c75041788 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java @@ -1086,7 +1086,7 @@ public Response createProcessGroup( // Step 4: Replace parameter contexts if necessary if (ParameterContextHandlingStrategy.REPLACE.equals(parameterContextHandlingStrategy)) { - parameterContextReplacer.replaceParameterContexts(flowSnapshot, serviceFacade.getParameterContexts()); + parameterContextReplacer.replaceParameterContexts(flowSnapshot, serviceFacade.getParameterContexts(false)); } // Step 5: Resolve Bundle info diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java index 9fe3af8f41ee..b97396aec017 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java @@ -1504,7 +1504,7 @@ public PortDTO createPortDto(final Port port) { } public ParameterContextDTO createParameterContextDto(final ParameterContext parameterContext, final RevisionManager revisionManager, - final boolean includeInheritedParameters, final ParameterContextLookup parameterContextLookup) { + final boolean includeInheritedParameters, final ParameterContextLookup parameterContextLookup, final boolean includeReferences) { final ParameterContextDTO dto = new ParameterContextDTO(); dto.setId(parameterContext.getIdentifier()); dto.setName(parameterContext.getName()); @@ -1524,7 +1524,7 @@ public ParameterContextDTO createParameterContextDto(final ParameterContext para final Map parameters = includeInheritedParameters ? parameterContext.getRawEffectiveParameters() : parameterContext.getParameters(); for (final Parameter parameter : parameters.values()) { - parameterEntities.add(createParameterEntity(parameterContext, parameter, revisionManager, parameterContextLookup)); + parameterEntities.add(createParameterEntity(parameterContext, parameter, revisionManager, parameterContextLookup, includeReferences)); } final List parameterContextRefs = new ArrayList<>(); @@ -1584,19 +1584,26 @@ public AssetReferenceDTO createAssetReferenceDto(final Asset asset) { } public ParameterEntity createParameterEntity(final ParameterContext parameterContext, final Parameter parameter, final RevisionManager revisionManager, - final ParameterContextLookup parameterContextLookup) { - final ParameterDTO dto = createParameterDto(parameterContext, parameter, revisionManager, parameterContextLookup); + final ParameterContextLookup parameterContextLookup) { + return createParameterEntity(parameterContext, parameter, revisionManager, parameterContextLookup, true); + } + + public ParameterEntity createParameterEntity(final ParameterContext parameterContext, final Parameter parameter, final RevisionManager revisionManager, + final ParameterContextLookup parameterContextLookup, final boolean includeReferences) { + final ParameterDTO dto = createParameterDto(parameterContext, parameter, revisionManager, parameterContextLookup, includeReferences); final ParameterEntity entity = new ParameterEntity(); entity.setParameter(dto); - final boolean canWrite = isWritable(dto.getReferencingComponents()); - entity.setCanWrite(canWrite); + // canWrite depends on the permissions of every component referencing this parameter, so it must always be determined, + // even when includeReferences is false and the full AffectedComponentEntity set is not built for the response. + final Set referencingComponents = getReferencingComponents(parameterContext, parameter.getDescriptor()); + entity.setCanWrite(isWritable(referencingComponents)); return entity; } public ParameterDTO createParameterDto(final ParameterContext parameterContext, final Parameter parameter, - final RevisionManager revisionManager, final ParameterContextLookup parameterContextLookup) { + final RevisionManager revisionManager, final ParameterContextLookup parameterContextLookup, final boolean includeReferences) { final ParameterDescriptor descriptor = parameter.getDescriptor(); final ParameterDTO dto = new ParameterDTO(); @@ -1610,14 +1617,11 @@ public ParameterDTO createParameterDto(final ParameterContext parameterContext, final List assets = parameter.getReferencedAssets(); dto.setReferencedAssets(assets == null ? List.of() : parameter.getReferencedAssets().stream().map(this::createAssetReferenceDto).toList()); - final ParameterReferenceManager parameterReferenceManager = parameterContext.getParameterReferenceManager(); - - final Set referencingComponents = new HashSet<>(); - referencingComponents.addAll(parameterReferenceManager.getProcessorsReferencing(parameterContext, descriptor.getName())); - referencingComponents.addAll(parameterReferenceManager.getControllerServicesReferencing(parameterContext, descriptor.getName())); - - final Set referencingComponentEntities = createAffectedComponentEntities(referencingComponents, revisionManager); - dto.setReferencingComponents(referencingComponentEntities); + if (includeReferences) { + final Set referencingComponents = getReferencingComponents(parameterContext, descriptor); + final Set referencingComponentEntities = createAffectedComponentEntities(referencingComponents, revisionManager); + dto.setReferencingComponents(referencingComponentEntities); + } final ParameterContext containingParameterContext = resolveContainingParameterContext(parameterContext, parameter, parameterContextLookup); @@ -3243,10 +3247,19 @@ private List createBulletins(final ComponentNode componentNode) { return bulletins; } - private boolean isWritable(final Collection affectedComponentEntities) { - for (final AffectedComponentEntity affectedComponent : affectedComponentEntities) { - final PermissionsDTO permissions = affectedComponent.getPermissions(); - if (!permissions.getCanRead() || !permissions.getCanWrite()) { + private Set getReferencingComponents(final ParameterContext parameterContext, final ParameterDescriptor descriptor) { + final ParameterReferenceManager parameterReferenceManager = parameterContext.getParameterReferenceManager(); + + final Set referencingComponents = new HashSet<>(); + referencingComponents.addAll(parameterReferenceManager.getProcessorsReferencing(parameterContext, descriptor.getName())); + referencingComponents.addAll(parameterReferenceManager.getControllerServicesReferencing(parameterContext, descriptor.getName())); + return referencingComponents; + } + + private boolean isWritable(final Set referencingComponents) { + final NiFiUser user = NiFiUserUtils.getNiFiUser(); + for (final ComponentNode referencingComponent : referencingComponents) { + if (!referencingComponent.isAuthorized(authorizer, RequestAction.READ, user) || !referencingComponent.isAuthorized(authorizer, RequestAction.WRITE, user)) { return false; } } diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java index ea915377e956..e2bc29b60e94 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/ParameterUpdateManager.java @@ -233,10 +233,10 @@ private ParameterContextEntity performParameterContextUpdate(final AsynchronousW throw new LifecycleManagementException("Failed to update Flow on all nodes in cluster due to " + explanation); } - return serviceFacade.getParameterContext(updatedContext.getId(), false, user); + return serviceFacade.getParameterContext(updatedContext.getId(), false, user, false); } else { serviceFacade.verifyUpdateParameterContext(updatedContext.getComponent(), true); - return serviceFacade.updateParameterContext(revision, updatedContext.getComponent()); + return serviceFacade.updateParameterContext(revision, updatedContext.getComponent(), false); } } diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/StandardNiFiServiceFacadeTest.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/StandardNiFiServiceFacadeTest.java index e73cdf17023e..61192cc060b4 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/StandardNiFiServiceFacadeTest.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/StandardNiFiServiceFacadeTest.java @@ -2384,19 +2384,19 @@ public void testGetConnectorParameterContextReturnsEntityWhenContextBound() { final ParameterContextDTO parameterContextDto = new ParameterContextDTO(); parameterContextDto.setId(parameterContextId); parameterContextDto.setName("context-name"); - when(dtoFactory.createParameterContextDto(eq(parameterContext), eq(revisionManager), eq(true), any(ParameterContextLookup.class))) + when(dtoFactory.createParameterContextDto(eq(parameterContext), eq(revisionManager), eq(true), any(ParameterContextLookup.class), eq(true))) .thenReturn(parameterContextDto); when(dtoFactory.createPermissionsDto(eq(parameterContext), any())).thenReturn(null); when(dtoFactory.createRevisionDTO(any(Revision.class))).thenReturn(new RevisionDTO()); when(revisionManager.getRevision(parameterContextId)).thenReturn(new Revision(1L, null, parameterContextId)); - final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId); + final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId, true); assertNotNull(entity); assertEquals(parameterContextId, entity.getId()); final ArgumentCaptor lookupCaptor = ArgumentCaptor.forClass(ParameterContextLookup.class); - verify(dtoFactory).createParameterContextDto(eq(parameterContext), eq(revisionManager), eq(true), lookupCaptor.capture()); + verify(dtoFactory).createParameterContextDto(eq(parameterContext), eq(revisionManager), eq(true), lookupCaptor.capture(), eq(true)); assertNotNull(lookupCaptor.getValue()); assertNull(lookupCaptor.getValue().getParameterContext("any-id")); assertFalse(lookupCaptor.getValue().hasParameterContext("any-id")); @@ -2423,7 +2423,7 @@ public void testGetConnectorParameterContextReturnsNullWhenNoBoundContext() { when(managedProcessGroup.findProcessGroup(processGroupId)).thenReturn(targetProcessGroup); when(targetProcessGroup.getParameterContext()).thenReturn(null); - final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId); + final ParameterContextEntity entity = serviceFacade.getConnectorParameterContext(connectorId, processGroupId, true); assertNull(entity); verifyNoInteractions(dtoFactory); @@ -2446,7 +2446,7 @@ public void testGetConnectorParameterContextThrowsWhenProcessGroupNotFound() { when(flowContext.getManagedProcessGroup()).thenReturn(managedProcessGroup); when(managedProcessGroup.findProcessGroup(processGroupId)).thenReturn(null); - assertThrows(ResourceNotFoundException.class, () -> serviceFacade.getConnectorParameterContext(connectorId, processGroupId)); + assertThrows(ResourceNotFoundException.class, () -> serviceFacade.getConnectorParameterContext(connectorId, processGroupId, true)); } private StandardNiFiServiceFacade createBranchTestFacade(final ProcessGroupDAO branchProcessGroupDAO, final FlowRegistryDAO flowRegistryDAO, diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java index b09de3509bed..280bc3761430 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java @@ -597,27 +597,27 @@ public void testGetControllerServicesFromConnectorProcessGroupNotAuthorized() { @Test public void testGetParameterContextForConnectorProcessGroup() { final ParameterContextEntity responseEntity = createParameterContextEntity(); - when(serviceFacade.getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID)).thenReturn(responseEntity); + when(serviceFacade.getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID, true)).thenReturn(responseEntity); - try (Response response = connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID)) { + try (Response response = connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID, true)) { assertEquals(200, response.getStatus()); assertEquals(responseEntity, response.getEntity()); } verify(serviceFacade).authorizeAccess(any(AuthorizeAccess.class)); - verify(serviceFacade).getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID); + verify(serviceFacade).getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID, true); } @Test public void testGetParameterContextForConnectorProcessGroupReturnsNoContentWhenUnbound() { - when(serviceFacade.getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID)).thenReturn(null); + when(serviceFacade.getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID, true)).thenReturn(null); - try (Response response = connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID)) { + try (Response response = connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID, true)) { assertEquals(204, response.getStatus()); } verify(serviceFacade).authorizeAccess(any(AuthorizeAccess.class)); - verify(serviceFacade).getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID); + verify(serviceFacade).getConnectorParameterContext(CONNECTOR_ID, PROCESS_GROUP_ID, true); } @Test @@ -625,10 +625,10 @@ public void testGetParameterContextForConnectorProcessGroupNotAuthorized() { doThrow(AccessDeniedException.class).when(serviceFacade).authorizeAccess(any(AuthorizeAccess.class)); assertThrows(AccessDeniedException.class, () -> - connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID)); + connectorResource.getParameterContextForConnectorProcessGroup(CONNECTOR_ID, PROCESS_GROUP_ID, true)); verify(serviceFacade).authorizeAccess(any(AuthorizeAccess.class)); - verify(serviceFacade, never()).getConnectorParameterContext(anyString(), anyString()); + verify(serviceFacade, never()).getConnectorParameterContext(anyString(), anyString(), eq(true)); } @Test diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/dto/DtoFactoryTest.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/dto/DtoFactoryTest.java index b8d84fb4d6bf..7c4e26efcf4e 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/dto/DtoFactoryTest.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/dto/DtoFactoryTest.java @@ -27,6 +27,8 @@ import org.apache.nifi.connectable.ConnectableType; import org.apache.nifi.connectable.Connection; import org.apache.nifi.controller.ControllerService; +import org.apache.nifi.controller.ProcessorNode; +import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.controller.queue.FlowFileQueue; import org.apache.nifi.controller.queue.LoadBalanceCompression; import org.apache.nifi.controller.queue.LoadBalanceStrategy; @@ -50,9 +52,14 @@ import org.apache.nifi.registry.flow.FlowRegistryClientNode; import org.apache.nifi.registry.flow.diff.DifferenceType; import org.apache.nifi.registry.flow.diff.FlowDifference; +import org.apache.nifi.reporting.Bulletin; +import org.apache.nifi.util.MockBulletinRepository; +import org.apache.nifi.web.Revision; import org.apache.nifi.web.api.entity.AllowableValueEntity; +import org.apache.nifi.web.api.entity.ComponentEntity; import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity; import org.apache.nifi.web.revision.RevisionManager; +import org.jspecify.annotations.NonNull; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -776,7 +783,7 @@ void testCreateParameterDtoResolvesSourceContextWhenParameterContextIdIsNull() { final ParameterContextLookup lookup = mock(ParameterContextLookup.class); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup, true); assertEquals("param-name", dto.getName()); assertEquals("param-value", dto.getValue()); @@ -803,7 +810,7 @@ void testCreateParameterDtoResolvesSourceContextWhenParameterContextIdMatchesCur final ParameterContextLookup lookup = mock(ParameterContextLookup.class); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup, true); assertFalse(dto.getInherited()); assertEquals(contextId, dto.getParameterContext().getId()); @@ -828,7 +835,7 @@ void testCreateParameterDtoResolvesSourceContextFromInheritedGraph() { final ParameterContextLookup lookup = mock(ParameterContextLookup.class); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup, true); assertTrue(dto.getInherited()); assertEquals(parentId, dto.getParameterContext().getId()); @@ -855,7 +862,7 @@ void testCreateParameterDtoResolvesSourceContextFromTransitiveInheritedGraph() { final ParameterContextLookup lookup = mock(ParameterContextLookup.class); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup, true); assertTrue(dto.getInherited()); assertEquals(grandparentId, dto.getParameterContext().getId()); @@ -881,7 +888,7 @@ void testCreateParameterDtoFallsBackToLookupWhenSourceNotReachableInGraph() { when(lookup.getParameterContext(externalId)).thenReturn(externalContext); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), lookup, true); assertTrue(dto.getInherited()); assertEquals(externalId, dto.getParameterContext().getId()); @@ -903,7 +910,7 @@ void testCreateParameterDtoFallsBackToCurrentContextWhenSourceNotReachableInGrap .build(); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), ParameterContextLookup.EMPTY); + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), ParameterContextLookup.EMPTY, true); assertFalse(dto.getInherited()); assertEquals(contextId, dto.getParameterContext().getId()); @@ -928,7 +935,7 @@ void testCreateParameterDtoResolvesSourceContextFromDiamondInheritanceGraph() { .build(); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(contextA, parameter, mock(RevisionManager.class), ParameterContextLookup.EMPTY); + final ParameterDTO dto = dtoFactory.createParameterDto(contextA, parameter, mock(RevisionManager.class), ParameterContextLookup.EMPTY, true); assertTrue(dto.getInherited()); assertEquals(contextDId, dto.getParameterContext().getId()); @@ -958,7 +965,7 @@ void testCreateParameterDtoInheritanceGraphHandlesCycles() { when(lookup.getParameterContext(missingId)).thenReturn(fallbackContext); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup); + final ParameterDTO dto = dtoFactory.createParameterDto(childContext, parameter, mock(RevisionManager.class), lookup, true); assertTrue(dto.getInherited()); assertEquals(missingId, dto.getParameterContext().getId()); @@ -978,12 +985,68 @@ void testCreateParameterDtoSensitiveValueIsMasked() { .build(); final DtoFactory dtoFactory = newDtoFactoryForParameters(); - final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), mock(ParameterContextLookup.class)); + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, mock(RevisionManager.class), mock(ParameterContextLookup.class), true); assertTrue(dto.getSensitive()); assertEquals(DtoFactory.SENSITIVE_VALUE_MASK, dto.getValue()); } + + + @Test + void testCreateParameterDtoReferencesIncluded() { + final String processorId = "processor-1"; + final String controllerId = "controller-1"; + + final ParameterDTO dto = getDtoForParameterWithReferences(processorId, controllerId, true); + + Set referencedIdSet = dto.getReferencingComponents().stream().map(ComponentEntity::getId).collect(Collectors.toSet()); + assertEquals(Set.of(processorId, controllerId), referencedIdSet); + } + + @Test + void testCreateParameterDtoReferencesExcluded() { + final String processorId = "processor-1"; + final String controllerId = "controller-1"; + + final ParameterDTO dto = getDtoForParameterWithReferences(processorId, controllerId, false); + + assertNull(dto.getReferencingComponents()); + } + + private static @NonNull ParameterDTO getDtoForParameterWithReferences(String processorId, String controllerId, boolean includeReferences) { + final String contextId = "context-1"; + ProcessorNode referencingProcessor = mock(ProcessorNode.class); + when(referencingProcessor.getIdentifier()).thenReturn(processorId); + when(referencingProcessor.getDesiredState()).thenReturn(ScheduledState.RUNNING); + ControllerServiceNode referencingControllerService = mock(ControllerServiceNode.class); + when(referencingControllerService.getIdentifier()).thenReturn(controllerId); + when(referencingControllerService.getState()).thenReturn(ControllerServiceState.ENABLED); + RevisionManager revisionManager = mock(RevisionManager.class); + when(revisionManager.getRevision(eq(processorId))).thenReturn(new Revision(0L, "client-1", processorId)); + when(revisionManager.getRevision(eq(controllerId))).thenReturn(new Revision(0L, "client-1", controllerId)); + + final ParameterContext parameterContext = createMockParameterContextWithRefs(contextId, "context-1-name", + Collections.emptyList(), Set.of(referencingControllerService), Set.of(referencingProcessor)); + + final Parameter parameter = new Parameter.Builder() + .name("my-param") + .value("my-value") + .sensitive(false) + .build(); + + final DtoFactory dtoFactory = newDtoFactoryForParameters(); + dtoFactory.setBulletinRepository(new MockBulletinRepository() { + @Override + public List findBulletinsForSource(String sourceId, String groupId) { + return List.of(); + } + }); + + final ParameterDTO dto = dtoFactory.createParameterDto(parameterContext, parameter, revisionManager, mock(ParameterContextLookup.class), includeReferences); + return dto; + } + private static DtoFactory newDtoFactoryForParameters() { final DtoFactory dtoFactory = new DtoFactory(); dtoFactory.setEntityFactory(new EntityFactory()); @@ -997,9 +1060,29 @@ private static ParameterContext createMockParameterContext(final String id, fina return context; } + private static ParameterContext createMockParameterContextWithRefs(final String id, final String name, final List inherited, + Set controllerRefs, Set processorRefs) { + final ParameterContext context = mock(ParameterContext.class); + configureBaseParameterContextWithRefs(context, id, name, controllerRefs, processorRefs); + when(context.getInheritedParameterContexts()).thenReturn(inherited); + return context; + } + + private static void configureBaseParameterContext(final ParameterContext context, final String id, final String name) { when(context.getIdentifier()).thenReturn(id); when(context.getName()).thenReturn(name); when(context.getParameterReferenceManager()).thenReturn(ParameterReferenceManager.EMPTY); } + + private static void configureBaseParameterContextWithRefs(final ParameterContext context, final String id, final String name, + Set controllerRefs, Set processorRefs) { + when(context.getIdentifier()).thenReturn(id); + when(context.getName()).thenReturn(name); + ParameterReferenceManager parameterReferenceManager = mock(ParameterReferenceManager.class); + when(parameterReferenceManager.getProcessGroupsBound(any(ParameterContext.class))).thenReturn(Set.of()); + when(parameterReferenceManager.getControllerServicesReferencing(any(ParameterContext.class), anyString())).thenReturn(controllerRefs); + when(parameterReferenceManager.getProcessorsReferencing(any(ParameterContext.class), anyString())).thenReturn(processorRefs); + when(context.getParameterReferenceManager()).thenReturn(parameterReferenceManager); + } } diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/service/connector.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/service/connector.service.ts index 2c8dcb56744f..40028f236d4e 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/service/connector.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/service/connector.service.ts @@ -134,12 +134,13 @@ export class ConnectorService { getConnectorParameterContext( connectorId: string, - processGroupId: string + processGroupId: string, + includeReferencingComponents: boolean ): Observable { return this.httpClient .get( `${ConnectorService.API}/connectors/${connectorId}/flow/process-groups/${processGroupId}/parameter-context`, - { observe: 'response' } + { observe: 'response', params: { includeReferencingComponents } } ) .pipe(map((response) => (response.status === 204 ? null : response.body))); } diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.spec.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.spec.ts index 3c6567eccbf5..d531dbfa43b2 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.spec.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.spec.ts @@ -1452,7 +1452,11 @@ describe('ConnectorCanvasEffects', () => { const result = await firstValueFrom(effects.loadConnectorParameterContext$); - expect(mockConnectorService.getConnectorParameterContext).toHaveBeenCalledWith('connector-123', 'pg-abc'); + expect(mockConnectorService.getConnectorParameterContext).toHaveBeenCalledWith( + 'connector-123', + 'pg-abc', + false + ); expect(result).toEqual(loadConnectorParameterContextSuccess({ parameterContext })); }); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.ts index f75e4481e4d1..b481986553f4 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.ts @@ -264,21 +264,23 @@ export class ConnectorCanvasEffects { this.actions$.pipe( ofType(ConnectorCanvasActions.loadConnectorParameterContext), switchMap((action) => - this.connectorService.getConnectorParameterContext(action.connectorId, action.processGroupId).pipe( - map((parameterContext) => - ConnectorCanvasActions.loadConnectorParameterContextSuccess({ parameterContext }) - ), - catchError((error) => - of( - ConnectorCanvasActions.loadConnectorParameterContextFailure({ - errorContext: { - errors: [this.errorHelper.getErrorString(error)], - context: action.errorContext - } - }) + this.connectorService + .getConnectorParameterContext(action.connectorId, action.processGroupId, false) + .pipe( + map((parameterContext) => + ConnectorCanvasActions.loadConnectorParameterContextSuccess({ parameterContext }) + ), + catchError((error) => + of( + ConnectorCanvasActions.loadConnectorParameterContextFailure({ + errorContext: { + errors: [this.errorHelper.getErrorString(error)], + context: action.errorContext + } + }) + ) ) ) - ) ) ) ); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter-helper.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter-helper.service.ts index c34034ec3e06..47277bbd43b4 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter-helper.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter-helper.service.ts @@ -59,7 +59,7 @@ export class ParameterHelperService { parameterContextId: string ): (name: string, sensitive: boolean, value: string | null) => Observable { return (name: string, sensitive: boolean, value: string | null) => { - return this.parameterContextService.getParameterContext(parameterContextId, false).pipe( + return this.parameterContextService.getParameterContext(parameterContextId, false, false).pipe( catchError((errorResponse: HttpErrorResponse) => { this.store.dispatch( ErrorActions.snackBarError({ error: this.errorHelper.getErrorString(errorResponse) }) diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter.service.ts index d92dc8acf6c9..290dae9bd2be 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/parameter.service.ts @@ -28,31 +28,50 @@ export class ParameterService { private static readonly API: string = '../nifi-api'; - getParameterContext(id: string, includeInheritedParameters: boolean): Observable { + getParameterContext( + id: string, + includeInheritedParameters: boolean, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.get(`${ParameterService.API}/parameter-contexts/${id}`, { params: { - includeInheritedParameters + includeInheritedParameters, + includeReferencingComponents } }); } - submitParameterContextUpdate(configureParameterContext: SubmitParameterContextUpdate): Observable { + submitParameterContextUpdate( + configureParameterContext: SubmitParameterContextUpdate, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.post( `${ParameterService.API}/parameter-contexts/${configureParameterContext.id}/update-requests`, - configureParameterContext.payload + configureParameterContext.payload, + { params: { includeReferencingComponents } } ); } - pollParameterContextUpdate(parameterContextId: string, requestId: string): Observable { + pollParameterContextUpdate( + parameterContextId: string, + requestId: string, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.get( - `${ParameterService.API}/parameter-contexts/${parameterContextId}/update-requests/${requestId}` + `${ParameterService.API}/parameter-contexts/${parameterContextId}/update-requests/${requestId}`, + { params: { includeReferencingComponents } } ); } - deleteParameterContextUpdate(parameterContextId: string, requestId: string): Observable { + deleteParameterContextUpdate( + parameterContextId: string, + requestId: string, + includeReferencingComponents: boolean + ): Observable { const params = new HttpParams({ fromObject: { - disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() + disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(), + includeReferencingComponents } }); return this.httpClient.delete( diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts index f0fc80574cb9..12565fff4cde 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts @@ -348,7 +348,7 @@ export class ControllerServicesEffects { switchMap(([request, parameterContextReference, processGroupId]) => { if (parameterContextReference && parameterContextReference.permissions.canRead) { return from( - this.parameterContextService.getParameterContext(parameterContextReference.id, true) + this.parameterContextService.getParameterContext(parameterContextReference.id, true, false) ).pipe( map((parameterContext) => { return [request, parameterContext, processGroupId]; diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts index a66564ab5bc6..8193ef7bf8cc 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts @@ -350,7 +350,7 @@ export class FlowEffects { case ComponentType.Processor: return of(FlowActions.openNewProcessorDialog({ request })); case ComponentType.ProcessGroup: - return from(this.parameterContextService.getParameterContexts()).pipe( + return from(this.parameterContextService.getParameterContexts(false)).pipe( concatLatestFrom(() => this.store.select(selectCurrentParameterContext)), map(([response, parameterContext]) => { const dialogRequest: CreateProcessGroupDialogRequest = { @@ -646,7 +646,7 @@ export class FlowEffects { map((action) => action.request), concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request]) => - from(this.parameterContextService.getParameterContexts()).pipe( + from(this.parameterContextService.getParameterContexts(false)).pipe( concatLatestFrom(() => this.store.select(selectCurrentParameterContext)), map(([response, parameterContext]) => { const dialogRequest: GroupComponentsDialogRequest = { @@ -1320,7 +1320,7 @@ export class FlowEffects { case ComponentType.Connection: return of(FlowActions.openEditConnectionDialog({ request })); case ComponentType.ProcessGroup: - return from(this.parameterContextService.getParameterContexts()).pipe( + return from(this.parameterContextService.getParameterContexts(false)).pipe( map((response) => { const editComponentDialogRequest = { ...request, @@ -1354,7 +1354,7 @@ export class FlowEffects { ofType(FlowActions.editCurrentProcessGroup), map((action) => action.request), switchMap((request) => { - return from(this.parameterContextService.getParameterContexts()).pipe( + return from(this.parameterContextService.getParameterContexts(false)).pipe( switchMap((parameterContextResponse) => from(this.flowService.getProcessGroup(request.id)).pipe( map((response) => @@ -1505,7 +1505,7 @@ export class FlowEffects { switchMap(([request, parameterContextReference, processGroupId]) => { if (parameterContextReference && parameterContextReference.permissions.canRead) { return from( - this.parameterContextService.getParameterContext(parameterContextReference.id) + this.parameterContextService.getParameterContext(parameterContextReference.id, true, false) ).pipe( map((parameterContext) => { return [request, parameterContext, processGroupId]; diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts index 536512d7dc60..2edbaebc2528 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts @@ -65,7 +65,7 @@ export class ParameterEffects { ofType(ParameterActions.submitParameterContextUpdateRequest), map((action) => action.request), switchMap((request) => - from(this.parameterService.submitParameterContextUpdate(request)).pipe( + from(this.parameterService.submitParameterContextUpdate(request, false)).pipe( map((response) => ParameterActions.submitParameterContextUpdateRequestSuccess({ response: { @@ -123,7 +123,8 @@ export class ParameterEffects { from( this.parameterService.pollParameterContextUpdate( parameterContextId, - updateRequest.request.requestId + updateRequest.request.requestId, + false ) ).pipe( map((response) => @@ -173,7 +174,8 @@ export class ParameterEffects { return from( this.parameterService.deleteParameterContextUpdate( parameterContextId, - updateRequest.request.requestId + updateRequest.request.requestId, + false ) ).pipe( map(() => ParameterActions.editParameterContextComplete()), @@ -279,7 +281,7 @@ export class ParameterEffects { ofType(ParameterActions.createParameterContext), map((action) => action.request), switchMap((request) => - from(this.parameterContextService.createParameterContext(request)).pipe( + from(this.parameterContextService.createParameterContext(request, false)).pipe( map((response) => ParameterActions.createParameterContextSuccess({ response: { diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts index 83d1bc466ab4..f81bc94efa09 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts @@ -31,42 +31,63 @@ export class ParameterContextService { private static readonly API: string = '../nifi-api'; - getParameterContexts(): Observable { - return this.httpClient.get(`${ParameterContextService.API}/flow/parameter-contexts`); + getParameterContexts(includeReferencingComponents: boolean): Observable { + return this.httpClient.get(`${ParameterContextService.API}/flow/parameter-contexts`, { + params: { includeReferencingComponents } + }); } - createParameterContext(createParameterContext: CreateParameterContextRequest): Observable { + createParameterContext( + createParameterContext: CreateParameterContextRequest, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.post( `${ParameterContextService.API}/parameter-contexts`, - createParameterContext.payload + createParameterContext.payload, + { params: { includeReferencingComponents } } ); } - getParameterContext(id: string, includeInheritedParameters = true): Observable { + getParameterContext(id: string, includeInheritedParameters: boolean, includeReferencingComponents: boolean): Observable { return this.httpClient.get(`${ParameterContextService.API}/parameter-contexts/${id}`, { params: { - includeInheritedParameters + includeInheritedParameters, + includeReferencingComponents } }); } - submitParameterContextUpdate(configureParameterContext: SubmitParameterContextUpdate): Observable { + submitParameterContextUpdate( + configureParameterContext: SubmitParameterContextUpdate, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.post( `${ParameterContextService.API}/parameter-contexts/${configureParameterContext.id}/update-requests`, - configureParameterContext.payload + configureParameterContext.payload, + { params: { includeReferencingComponents } } ); } - pollParameterContextUpdate(parameterContextId: string, requestId: string): Observable { + pollParameterContextUpdate( + parameterContextId: string, + requestId: string, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.get( - `${ParameterContextService.API}/parameter-contexts/${parameterContextId}/update-requests/${requestId}` + `${ParameterContextService.API}/parameter-contexts/${parameterContextId}/update-requests/${requestId}`, + { params: { includeReferencingComponents } } ); } - deleteParameterContextUpdate(parameterContextId: string, requestId: string): Observable { + deleteParameterContextUpdate( + parameterContextId: string, + requestId: string, + includeReferencingComponents: boolean + ): Observable { const params = new HttpParams({ fromObject: { - disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() + disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(), + includeReferencingComponents } }); return this.httpClient.delete( @@ -75,12 +96,16 @@ export class ParameterContextService { ); } - deleteParameterContext(deleteParameterContext: DeleteParameterContextRequest): Observable { + deleteParameterContext( + deleteParameterContext: DeleteParameterContextRequest, + includeReferencingComponents: boolean + ): Observable { const entity: ParameterContextEntity = deleteParameterContext.parameterContext; const params = new HttpParams({ fromObject: { ...this.client.getRevision(entity), - disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() + disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(), + includeReferencingComponents } }); return this.httpClient.delete(`${ParameterContextService.API}/parameter-contexts/${entity.id}`, { params }); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.spec.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.spec.ts index 544b5ce1630f..d838e1aac25b 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.spec.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.spec.ts @@ -272,7 +272,8 @@ describe('ParameterContextListingEffects', () => { effects.deleteParameterContextUpdateRequest$.subscribe(() => { expect(parameterContextService.deleteParameterContextUpdate).toHaveBeenCalledWith( parameterContextId, - mockUpdateRequest.requestId + mockUpdateRequest.requestId, + false ); }); }); @@ -295,7 +296,8 @@ describe('ParameterContextListingEffects', () => { effects.deleteParameterContextUpdateRequest$.subscribe(() => { expect(parameterContextService.deleteParameterContextUpdate).toHaveBeenCalledWith( parameterContextId, - mockUpdateRequest.requestId + mockUpdateRequest.requestId, + false ); }); }); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts index 74b9a005cb8b..14a4e7908d30 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts @@ -74,7 +74,7 @@ export class ParameterContextListingEffects { ofType(ParameterContextListingActions.loadParameterContexts), concatLatestFrom(() => this.store.select(selectParameterContextLoadedTimestamp)), switchMap(([, loadedTimestamp]) => - from(this.parameterContextService.getParameterContexts()).pipe( + from(this.parameterContextService.getParameterContexts(false)).pipe( map((response) => ParameterContextListingActions.loadParameterContextsSuccess({ response: { @@ -195,7 +195,7 @@ export class ParameterContextListingEffects { ofType(ParameterContextListingActions.createParameterContext), map((action) => action.request), switchMap((request) => - from(this.parameterContextService.createParameterContext(request)).pipe( + from(this.parameterContextService.createParameterContext(request, false)).pipe( map((response) => ParameterContextListingActions.createParameterContextSuccess({ response: { @@ -291,7 +291,7 @@ export class ParameterContextListingEffects { ofType(ParameterContextListingActions.getEffectiveParameterContextAndOpenDialog), map((action) => action.request), switchMap((request) => - from(this.parameterContextService.getParameterContext(request.id, true)).pipe( + from(this.parameterContextService.getParameterContext(request.id, true, true)).pipe( map((response) => ParameterContextListingActions.openParameterContextDialog({ request: { @@ -434,7 +434,7 @@ export class ParameterContextListingEffects { ofType(ParameterContextListingActions.submitParameterContextUpdateRequest), map((action) => action.request), switchMap((request) => - from(this.parameterContextService.submitParameterContextUpdate(request)).pipe( + from(this.parameterContextService.submitParameterContextUpdate(request, false)).pipe( map((response) => ParameterContextListingActions.submitParameterContextUpdateRequestSuccess({ response: { @@ -501,7 +501,8 @@ export class ParameterContextListingEffects { from( this.parameterContextService.pollParameterContextUpdate( parameterContextId, - updateRequest.request.requestId + updateRequest.request.requestId, + false ) ).pipe( map((response) => @@ -557,7 +558,7 @@ export class ParameterContextListingEffects { ]), tap(([, parameterContextId, updateRequest]) => { this.parameterContextService - .deleteParameterContextUpdate(parameterContextId, updateRequest.request.requestId) + .deleteParameterContextUpdate(parameterContextId, updateRequest.request.requestId, false) .subscribe((response) => { this.store.dispatch( ParameterContextListingActions.deleteParameterContextUpdateRequestSuccess({ @@ -606,7 +607,7 @@ export class ParameterContextListingEffects { ofType(ParameterContextListingActions.deleteParameterContext), map((action) => action.request), switchMap((request) => - from(this.parameterContextService.deleteParameterContext(request)).pipe( + from(this.parameterContextService.deleteParameterContext(request, false)).pipe( map((response) => ParameterContextListingActions.deleteParameterContextSuccess({ response: { diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/service/parameter-provider.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/service/parameter-provider.service.ts index 1b24905f2d75..eba98b72da66 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/service/parameter-provider.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/service/parameter-provider.service.ts @@ -96,7 +96,10 @@ export class ParameterProviderService implements PropertyDescriptorRetriever { ); } - fetchParameters(request: FetchParameterProviderParametersRequest): Observable { + fetchParameters( + request: FetchParameterProviderParametersRequest, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.post( `${ParameterProviderService.API}/parameter-providers/${request.id}/parameters/fetch-requests`, { @@ -104,31 +107,44 @@ export class ParameterProviderService implements PropertyDescriptorRetriever { revision: request.revision, disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() }, - { params: { disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() } } + { + params: { + disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(), + includeReferencingComponents + } + } ); } - applyParameters(request: ParameterProviderParameterApplicationEntity): Observable { + applyParameters( + request: ParameterProviderParameterApplicationEntity, + includeReferencingComponents: boolean + ): Observable { return this.httpClient.post( `${ParameterProviderService.API}/parameter-providers/${request.id}/apply-parameters-requests`, - request + request, + { params: { includeReferencingComponents } } ); } pollParameterProviderParametersUpdateRequest( - updateRequest: ParameterProviderApplyParametersRequest + updateRequest: ParameterProviderApplyParametersRequest, + includeReferencingComponents: boolean ): Observable { return this.httpClient.get( - `${ParameterProviderService.API}/parameter-providers/${updateRequest.parameterProvider.id}/apply-parameters-requests/${updateRequest.requestId}` + `${ParameterProviderService.API}/parameter-providers/${updateRequest.parameterProvider.id}/apply-parameters-requests/${updateRequest.requestId}`, + { params: { includeReferencingComponents } } ); } deleteParameterProviderParametersUpdateRequest( - updateRequest: ParameterProviderApplyParametersRequest + updateRequest: ParameterProviderApplyParametersRequest, + includeReferencingComponents: boolean ): Observable { const params = new HttpParams({ fromObject: { - disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged() + disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(), + includeReferencingComponents } }); return this.httpClient.delete( diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.spec.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.spec.ts index 0d67d37677e8..e7b8cc5ad71d 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.spec.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.spec.ts @@ -469,7 +469,7 @@ describe('ParameterProvidersEffects', () => { response: { parameterProvider: mockResponse } }) ); - expect(mockParameterProviderService.fetchParameters).toHaveBeenCalledWith(mockRequest); + expect(mockParameterProviderService.fetchParameters).toHaveBeenCalledWith(mockRequest, true); }); it('should handle error when fetching parameters fails', async () => { diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.ts index 52ae6dc5494e..edf5779a9458 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/settings/state/parameter-providers/parameter-providers.effects.ts @@ -550,7 +550,7 @@ export class ParameterProvidersEffects { ofType(ParameterProviderActions.fetchParameterProviderParametersAndOpenDialog), map((action) => action.request), switchMap((request) => - from(this.parameterProviderService.fetchParameters(request)).pipe( + from(this.parameterProviderService.fetchParameters(request, true)).pipe( map((response: ParameterProviderEntity) => ParameterProviderActions.fetchParameterProviderParametersSuccess({ response: { parameterProvider: response } @@ -680,7 +680,7 @@ export class ParameterProvidersEffects { map((action) => action.request), switchMap((request) => from( - this.parameterProviderService.applyParameters(request).pipe( + this.parameterProviderService.applyParameters(request, false).pipe( map((response: any) => ParameterProviderActions.submitParameterProviderParametersUpdateRequestSuccess({ response: { @@ -739,7 +739,10 @@ export class ParameterProvidersEffects { switchMap(([, updateRequest]) => { if (updateRequest) { return from( - this.parameterProviderService.pollParameterProviderParametersUpdateRequest(updateRequest) + this.parameterProviderService.pollParameterProviderParametersUpdateRequest( + updateRequest, + false + ) ).pipe( map((response) => ParameterProviderActions.pollParameterProviderParametersUpdateRequestSuccess({ @@ -789,7 +792,7 @@ export class ParameterProvidersEffects { tap(([, updateRequest]) => { if (updateRequest) { this.parameterProviderService - .deleteParameterProviderParametersUpdateRequest(updateRequest) + .deleteParameterProviderParametersUpdateRequest(updateRequest, false) .subscribe(); } })