Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public static void merge(final ParameterContextEntity target, final Map<NodeIden
public static void merge(final ParameterContextDTO target, final Map<NodeIdentifier, ParameterContextDTO> entityMap) {
final Map<String, ProcessGroupEntity> mergedBoundGroups = new HashMap<>();
final Map<String, Map<String, AffectedComponentEntity>> affectedComponentsByParameterName = new HashMap<>();
final Set<String> parameterNamesWithReferencingComponents = new HashSet<>();

final Set<String> unwritableParameters = new HashSet<>();
for (final Map.Entry<NodeIdentifier, ParameterContextDTO> entry : entityMap.entrySet()) {
Expand Down Expand Up @@ -94,14 +95,17 @@ public static void merge(final ParameterContextDTO target, final Map<NodeIdentif

final Map<String, AffectedComponentEntity> 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);
}
}
}
}
Expand All @@ -117,8 +121,12 @@ public static void merge(final ParameterContextDTO target, final Map<NodeIdentif
parameterEntity.setCanWrite(false);
}

final Map<String, AffectedComponentEntity> 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<String, AffectedComponentEntity> componentMap = affectedComponentsByParameterName.get(parameterDto.getName());
parameterDto.setReferencingComponents(new HashSet<>(componentMap.values()));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<NodeIdentifier, ParameterContextDTO> 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<NodeIdentifier, ParameterContextDTO> 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<AffectedComponentEntity> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,12 @@ Set<ControllerServiceEntity> 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);

Expand Down Expand Up @@ -1407,9 +1408,10 @@ Set<DocumentedTypeDTO> 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<ParameterContextEntity> getParameterContexts();
Set<ParameterContextEntity> getParameterContexts(boolean includeReferences);

/**
* Returns the Parameter Context with the given name
Expand All @@ -1425,33 +1427,39 @@ Set<DocumentedTypeDTO> 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
Expand Down Expand Up @@ -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<ParameterContextEntity> getParameterContextUpdatesForAppliedParameters(String parameterProviderId, Collection<ParameterGroupConfiguration> parameterGroupConfigurations);
List<ParameterContextEntity> getParameterContextUpdatesForAppliedParameters(String parameterProviderId,
Collection<ParameterGroupConfiguration> parameterGroupConfigurations,
boolean includeReferences);

/**
* Gets the references for specified parameter provider.
Expand Down
Loading
Loading