diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java index b0365765dc..b9ca1a699b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java @@ -49,6 +49,7 @@ public class ParameterProviderDTO extends ComponentDTO { private Map descriptors; private Collection parameterGroupConfigurations; private Set affectedComponents; + private Set parameterStatus; private Set referencingParameterContexts; private String customUiUrl; @@ -84,6 +85,15 @@ public class ParameterProviderDTO extends ComponentDTO { this.referencingParameterContexts = referencingParameterContexts; } + @ApiModelProperty("The status of all provided parameters for this parameter provider") + public Set getParameterStatus() { + return parameterStatus; + } + + public void setParameterStatus(Set parameterStatus) { + this.parameterStatus = parameterStatus; + } + @ApiModelProperty(value = "The Parameter Contexts that reference this Parameter Provider", accessMode = ApiModelProperty.AccessMode.READ_ONLY) public Set getReferencingParameterContexts() { return referencingParameterContexts; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatus.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatus.java new file mode 100644 index 0000000000..b728396291 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatus.java @@ -0,0 +1,25 @@ +/* + * 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.web.api.dto; + +public enum ParameterStatus { + NEW, + CHANGED, + REMOVED, // The parameter was removed, + MISSING_BUT_REFERENCED, // The parameter would have been removed, but is currently referenced by a component, so it is preserved + UNCHANGED +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java new file mode 100644 index 0000000000..12193f9288 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java @@ -0,0 +1,46 @@ +/* + * 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.web.api.dto; + +import io.swagger.annotations.ApiModelProperty; +import org.apache.nifi.web.api.entity.ParameterEntity; + +import javax.xml.bind.annotation.XmlType; + +@XmlType(name = "parameterStatus") +public class ParameterStatusDTO { + private ParameterEntity parameter; + private ParameterStatus status; + + @ApiModelProperty("The name of the Parameter") + public ParameterEntity getParameter() { + return parameter; + } + + public void setParameter(final ParameterEntity parameter) { + this.parameter = parameter; + } + + @ApiModelProperty("Indicates the status of the parameter, compared to the existing parameter context") + public ParameterStatus getStatus() { + return status; + } + + public void setStatus(ParameterStatus status) { + this.status = status; + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index 89566968ea..8f6cf6e3d8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -3476,6 +3476,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } } else { parameterEntity = dtoFactory.createParameterEntity(parameterContext, parameter, revisionManager, parameterContextDAO); + // Need to unmask in order to actually apply the value + if (parameterEntity.getParameter() != null && parameterEntity.getParameter().getSensitive() != null + && parameterEntity.getParameter().getSensitive()) { + parameterEntity.getParameter().setValue(parameter.getValue()); + } updatedParameterEntities.add(parameterEntity); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java index e3d7c6f13c..7f8f47a738 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java @@ -16,6 +16,7 @@ */ package org.apache.nifi.web.api; +import com.google.common.base.Functions; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -60,6 +61,8 @@ import org.apache.nifi.web.api.dto.ParameterProviderApplyParametersRequestDTO; import org.apache.nifi.web.api.dto.ParameterProviderApplyParametersUpdateStepDTO; import org.apache.nifi.web.api.dto.ParameterProviderConfigurationDTO; import org.apache.nifi.web.api.dto.ParameterProviderDTO; +import org.apache.nifi.web.api.dto.ParameterStatus; +import org.apache.nifi.web.api.dto.ParameterStatusDTO; import org.apache.nifi.web.api.dto.PropertyDescriptorDTO; import org.apache.nifi.web.api.dto.RevisionDTO; import org.apache.nifi.web.api.dto.VerifyConfigRequestDTO; @@ -767,8 +770,6 @@ public class ParameterProviderResource extends AbstractParameterResource { authorizable.getAuthorizable().authorize(authorizer, RequestAction.READ, user); references.forEach(reference -> lookup.getParameterContext(reference.getComponent().getId()).authorize(authorizer, RequestAction.READ, user)); - // Verify READ permission for user, for every component that is currently referenced by relevant parameter contexts - referencingParameterContextDtos.forEach(parameterContextDto -> authorizeReferencingComponents(parameterContextDto.getId(), lookup, user)); }, () -> serviceFacade.verifyCanFetchParameters(fetchParametersEntity.getId()), (revision, parameterProviderFetchEntity) -> { @@ -791,11 +792,21 @@ public class ParameterProviderResource extends AbstractParameterResource { }); final List parameterContextUpdates = serviceFacade.getParameterContextUpdatesForAppliedParameters(parameterProviderId, parameterGroupConfigurations); + final Set removedParameters = parameterContextUpdates.stream() + .flatMap(context -> context.getComponent().getParameters().stream()) + .filter(parameterEntity -> { + final ParameterDTO dto = parameterEntity.getParameter(); + return dto.getSensitive() == null && dto.getValue() == null && dto.getDescription() == null; + }) + .collect(Collectors.toSet()); final Set affectedComponents = getAffectedComponentEntities(parameterContextUpdates); - if (!affectedComponents.isEmpty()) { entity.getComponent().setAffectedComponents(affectedComponents); } + final Set parameterStatus = getParameterStatus(entity, parameterContextUpdates, removedParameters, user); + if (!parameterStatus.isEmpty()) { + entity.getComponent().setParameterStatus(parameterStatus); + } populateRemainingParameterProviderEntityContent(entity); return generateOkResponse(entity).build(); @@ -932,13 +943,82 @@ public class ParameterProviderResource extends AbstractParameterResource { ); } - private Set getAffectedComponentEntities(List parameterContextUpdates) { + private Set getAffectedComponentEntities(final List parameterContextUpdates) { final Collection updatedParameterContextDTOs = parameterContextUpdates.stream() .map(ParameterContextEntity::getComponent) .collect(Collectors.toList()); return serviceFacade.getComponentsAffectedByParameterContextUpdate(updatedParameterContextDTOs); } + private Set getParameterStatus(final ParameterProviderEntity parameterProvider, final List parameterContextUpdates, + final Set removedParameters, final NiFiUser niFiUser) { + final Set parameterStatus = new HashSet<>(); + if (parameterProvider.getComponent() == null || parameterProvider.getComponent().getReferencingParameterContexts() == null) { + return parameterStatus; + } + + final Map> removedParameterNamesByContextId = new HashMap<>(); + removedParameters.forEach(parameterEntity -> { + removedParameterNamesByContextId.computeIfAbsent(parameterEntity.getParameter().getParameterContext().getComponent().getId(), key -> new HashSet<>()) + .add(parameterEntity.getParameter().getName()); + }); + + final Map parameterContextUpdateMap = parameterContextUpdates.stream() + .collect(Collectors.toMap(entity -> entity.getComponent().getId(), Functions.identity())); + + for (final ParameterProviderReferencingComponentEntity reference : parameterProvider.getComponent().getReferencingParameterContexts()) { + final String parameterContextId = reference.getComponent().getId(); + final ParameterContextEntity parameterContext = serviceFacade.getParameterContext(parameterContextId, false, niFiUser); + if (parameterContext.getComponent() == null) { + continue; + } + + final Set removedParameterNames = removedParameterNamesByContextId.get(parameterContext.getComponent().getId()); + final ParameterContextEntity parameterContextUpdate = parameterContextUpdateMap.get(parameterContextId); + final Map updatedParameters = parameterContextUpdate == null ? Collections.emptyMap() : parameterContextUpdate.getComponent().getParameters().stream() + .collect(Collectors.toMap(parameter -> parameter.getParameter().getName(), Functions.identity())); + final Set currentParameterNames = new HashSet<>(); + + // Report changed and removed parameters + for (final ParameterEntity parameter : parameterContext.getComponent().getParameters()) { + currentParameterNames.add(parameter.getParameter().getName()); + + final ParameterStatusDTO dto = new ParameterStatusDTO(); + final ParameterEntity updatedParameter = updatedParameters.get(parameter.getParameter().getName()); + if (updatedParameter == null) { + dto.setParameter(parameter); + if (removedParameterNames != null && removedParameterNames.contains(parameter.getParameter().getName())) { + dto.setStatus(ParameterStatus.MISSING_BUT_REFERENCED); + } else { + dto.setStatus(ParameterStatus.UNCHANGED); + } + } else { + final ParameterDTO updatedParameterDTO = updatedParameter.getParameter(); + final boolean isDeletion = updatedParameterDTO.getSensitive() == null && updatedParameterDTO.getDescription() == null && updatedParameterDTO.getValue() == null; + dto.setParameter(updatedParameter); + dto.setStatus(isDeletion ? ParameterStatus.REMOVED : ParameterStatus.CHANGED); + } + parameterStatus.add(dto); + } + // Report new parameters + updatedParameters.forEach((parameterName, parameterEntity) -> { + if (!currentParameterNames.contains(parameterName)) { + final ParameterStatusDTO dto = new ParameterStatusDTO(); + dto.setParameter(parameterEntity); + dto.setStatus(ParameterStatus.NEW); + parameterStatus.add(dto); + } + }); + parameterStatus.forEach(dto -> { + final ParameterDTO parameterDTO = dto.getParameter().getParameter(); + if (parameterDTO.getValue() != null && parameterDTO.getSensitive() != null && parameterDTO.getSensitive()) { + parameterDTO.setValue(DtoFactory.SENSITIVE_VALUE_MASK); + } + }); + } + return parameterStatus; + } + @GET @Consumes(MediaType.WILDCARD) @Produces(MediaType.APPLICATION_JSON)