mirror of
https://github.com/apache/nifi.git
synced 2025-03-01 15:09:11 +00:00
NIFI-8490: Adding inherited parameter contexts (#5072)
- Allowing inherited param contexts on creation, updating PC authorization
This commit is contained in:
parent
60b08cc569
commit
4a3e81531b
@ -21,10 +21,20 @@ import java.util.Objects;
|
||||
public class Parameter {
|
||||
private final ParameterDescriptor descriptor;
|
||||
private final String value;
|
||||
private final String parameterContextId;
|
||||
|
||||
public Parameter(final ParameterDescriptor descriptor, final String value) {
|
||||
private Parameter(final ParameterDescriptor descriptor, final String value, final String parameterContextId) {
|
||||
this.descriptor = descriptor;
|
||||
this.value = value;
|
||||
this.parameterContextId = parameterContextId;
|
||||
}
|
||||
|
||||
public Parameter(final Parameter parameter, final String parameterContextId) {
|
||||
this(parameter.getDescriptor(), parameter.getValue(), parameterContextId);
|
||||
}
|
||||
|
||||
public Parameter(final ParameterDescriptor descriptor, final String value) {
|
||||
this(descriptor, value, null);
|
||||
}
|
||||
|
||||
public ParameterDescriptor getDescriptor() {
|
||||
@ -35,6 +45,10 @@ public class Parameter {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getParameterContextId() {
|
||||
return parameterContextId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
|
@ -21,14 +21,15 @@ import java.util.Optional;
|
||||
public interface ParameterLookup {
|
||||
|
||||
/**
|
||||
* Returns the Parameter with the given name
|
||||
* Returns the Parameter with the given name, considering the base and all inherited ParameterContexts.
|
||||
* @param parameterName the name of the Parameter
|
||||
* @return the Parameter with the given name or an empty Optional if no Parameter exists with that name
|
||||
*/
|
||||
Optional<Parameter> getParameter(String parameterName);
|
||||
|
||||
/**
|
||||
* Returns false if any Parameters are available, true if no Parameters have been defined
|
||||
* Returns false if any Parameters are available, true if no Parameters have been defined in this or any
|
||||
* inherited ParameterContexts.
|
||||
* @return true if empty
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
@ -17,10 +17,12 @@
|
||||
package org.apache.nifi.web.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterEntity;
|
||||
import org.apache.nifi.web.api.entity.ProcessGroupEntity;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@XmlType(name = "parameterContext")
|
||||
@ -30,6 +32,7 @@ public class ParameterContextDTO {
|
||||
private String description;
|
||||
private Set<ParameterEntity> parameters;
|
||||
private Set<ProcessGroupEntity> boundProcessGroups;
|
||||
private List<ParameterContextReferenceEntity> inheritedParameterContexts;
|
||||
|
||||
public void setId(String id) {
|
||||
this.identifier = id;
|
||||
@ -71,6 +74,15 @@ public class ParameterContextDTO {
|
||||
this.boundProcessGroups = boundProcessGroups;
|
||||
}
|
||||
|
||||
@ApiModelProperty("A list of references of Parameter Contexts from which this one inherits parameters")
|
||||
public List<ParameterContextReferenceEntity> getInheritedParameterContexts() {
|
||||
return inheritedParameterContexts;
|
||||
}
|
||||
|
||||
public void setInheritedParameterContexts(final List<ParameterContextReferenceEntity> inheritedParameterContexts) {
|
||||
this.inheritedParameterContexts = inheritedParameterContexts;
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "The Process Groups that are bound to this Parameter Context", accessMode = ApiModelProperty.AccessMode.READ_ONLY)
|
||||
public Set<ProcessGroupEntity> getBoundProcessGroups() {
|
||||
return boundProcessGroups;
|
||||
|
@ -18,6 +18,7 @@ package org.apache.nifi.web.api.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.apache.nifi.web.api.entity.AffectedComponentEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import java.util.Set;
|
||||
@ -30,6 +31,7 @@ public class ParameterDTO {
|
||||
private String value;
|
||||
private Boolean valueRemoved;
|
||||
private Set<AffectedComponentEntity> referencingComponents;
|
||||
private ParameterContextReferenceEntity parameterContext;
|
||||
|
||||
@ApiModelProperty("The name of the Parameter")
|
||||
public String getName() {
|
||||
@ -82,6 +84,15 @@ public class ParameterDTO {
|
||||
return referencingComponents;
|
||||
}
|
||||
|
||||
public void setParameterContext(final ParameterContextReferenceEntity parameterContext) {
|
||||
this.parameterContext = parameterContext;
|
||||
}
|
||||
|
||||
@ApiModelProperty("A reference to the Parameter Context that contains this one")
|
||||
public ParameterContextReferenceEntity getParameterContext() {
|
||||
return parameterContext;
|
||||
}
|
||||
|
||||
public void setReferencingComponents(final Set<AffectedComponentEntity> referencingComponents) {
|
||||
this.referencingComponents = referencingComponents;
|
||||
}
|
||||
|
@ -39,16 +39,20 @@ import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterContextManager;
|
||||
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||
import org.apache.nifi.parameter.ReferenceOnlyParameterContext;
|
||||
import org.apache.nifi.parameter.StandardParameterContext;
|
||||
import org.apache.nifi.parameter.StandardParameterReferenceManager;
|
||||
import org.apache.nifi.registry.flow.FlowRegistryClient;
|
||||
import org.apache.nifi.remote.PublicPort;
|
||||
import org.apache.nifi.remote.RemoteGroupPort;
|
||||
import org.apache.nifi.util.ReflectionUtils;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -75,6 +79,8 @@ public abstract class AbstractFlowManager implements FlowManager {
|
||||
private volatile ControllerServiceProvider controllerServiceProvider;
|
||||
private volatile ProcessGroup rootGroup;
|
||||
|
||||
private final ThreadLocal<Boolean> withParameterContextResolution = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
public AbstractFlowManager(final FlowFileEventRepository flowFileEventRepository, final ParameterContextManager parameterContextManager,
|
||||
final FlowRegistryClient flowRegistryClient, final BooleanSupplier flowInitializedCheck) {
|
||||
this.flowFileEventRepository = flowFileEventRepository;
|
||||
@ -414,7 +420,8 @@ public abstract class AbstractFlowManager implements FlowManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterContext createParameterContext(final String id, final String name, final Map<String, Parameter> parameters) {
|
||||
public ParameterContext createParameterContext(final String id, final String name, final Map<String, Parameter> parameters,
|
||||
final List<ParameterContextReferenceEntity> parameterContexts) {
|
||||
final boolean namingConflict = parameterContextManager.getParameterContexts().stream()
|
||||
.anyMatch(paramContext -> paramContext.getName().equals(name));
|
||||
|
||||
@ -425,9 +432,72 @@ public abstract class AbstractFlowManager implements FlowManager {
|
||||
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(this);
|
||||
final ParameterContext parameterContext = new StandardParameterContext(id, name, referenceManager, getParameterContextParent());
|
||||
parameterContext.setParameters(parameters);
|
||||
|
||||
if (parameterContexts != null && !parameterContexts.isEmpty()) {
|
||||
if (!withParameterContextResolution.get()) {
|
||||
throw new IllegalStateException("A ParameterContext with inherited ParameterContexts may only be created from within a call to AbstractFlowManager#withParameterContextResolution");
|
||||
}
|
||||
final List<ParameterContext> parameterContextList = new ArrayList<>();
|
||||
for(final ParameterContextReferenceEntity parameterContextRef : parameterContexts) {
|
||||
parameterContextList.add(lookupParameterContext(parameterContextRef.getId()));
|
||||
}
|
||||
parameterContext.setInheritedParameterContexts(parameterContextList);
|
||||
}
|
||||
|
||||
parameterContextManager.addParameterContext(parameterContext);
|
||||
return parameterContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withParameterContextResolution(final Runnable parameterContextAction) {
|
||||
withParameterContextResolution.set(true);
|
||||
parameterContextAction.run();
|
||||
withParameterContextResolution.set(false);
|
||||
|
||||
for (final ParameterContext parameterContext : parameterContextManager.getParameterContexts()) {
|
||||
// if a param context in the manager itself is reference-only, it means there is a reference to a param
|
||||
// context that no longer exists
|
||||
if (parameterContext instanceof ReferenceOnlyParameterContext) {
|
||||
throw new IllegalStateException(String.format("A Parameter Context tries to inherit from another Parameter Context [%s] that does not exist",
|
||||
parameterContext.getIdentifier()));
|
||||
}
|
||||
|
||||
// resolve any references nested in the actual param contexts
|
||||
final List<ParameterContext> inheritedParamContexts = new ArrayList<>();
|
||||
for(final ParameterContext inheritedParamContext : parameterContext.getInheritedParameterContexts()) {
|
||||
if (inheritedParamContext instanceof ReferenceOnlyParameterContext) {
|
||||
inheritedParamContexts.add(parameterContextManager.getParameterContext(inheritedParamContext.getIdentifier()));
|
||||
} else {
|
||||
inheritedParamContexts.add(inheritedParamContext);
|
||||
}
|
||||
}
|
||||
parameterContext.setInheritedParameterContexts(inheritedParamContexts);
|
||||
}
|
||||
|
||||
// if any reference-only inherited param contexts still exist, it means they couldn't be resolved
|
||||
for (final ParameterContext parameterContext : parameterContextManager.getParameterContexts()) {
|
||||
for(final ParameterContext inheritedParamContext : parameterContext.getInheritedParameterContexts()) {
|
||||
if (inheritedParamContext instanceof ReferenceOnlyParameterContext) {
|
||||
throw new IllegalStateException(String.format("Parameter Context [%s] tries to inherit from a Parameter Context [%s] that does not exist",
|
||||
parameterContext.getName(), inheritedParamContext.getIdentifier()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a ParameterContext by ID. If not found, registers a ReferenceOnlyParameterContext, preventing
|
||||
* chicken-egg scenarios where a referenced ParameterContext is not registered before the referencing one.
|
||||
* @param id A parameter context ID
|
||||
* @return The matching ParameterContext, or ReferenceOnlyParameterContext if not found yet
|
||||
*/
|
||||
private ParameterContext lookupParameterContext(final String id) {
|
||||
if (!parameterContextManager.hasParameterContext(id)) {
|
||||
parameterContextManager.addParameterContext(new ReferenceOnlyParameterContext(id));
|
||||
}
|
||||
return parameterContextManager.getParameterContext(id);
|
||||
|
||||
}
|
||||
|
||||
protected abstract Authorizable getParameterContextParent();
|
||||
}
|
||||
|
@ -140,8 +140,10 @@ import org.apache.nifi.util.ReflectionUtils;
|
||||
import org.apache.nifi.util.SnippetUtils;
|
||||
import org.apache.nifi.web.ResourceNotFoundException;
|
||||
import org.apache.nifi.web.Revision;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.TemplateDTO;
|
||||
import org.apache.nifi.web.api.dto.VersionedFlowDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -3171,7 +3173,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
|
||||
// For each Parameter in the updated parameter context, add a ParameterUpdate to our map
|
||||
final Map<String, ParameterUpdate> updatedParameters = new HashMap<>();
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : updatedParameterContext.getParameters().entrySet()) {
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : updatedParameterContext.getEffectiveParameters().entrySet()) {
|
||||
final ParameterDescriptor updatedDescriptor = entry.getKey();
|
||||
final Parameter updatedParameter = entry.getValue();
|
||||
|
||||
@ -3186,7 +3188,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
}
|
||||
|
||||
// For each Parameter that was in the previous parameter context that is not in the updated Paramter Context, add a ParameterUpdate to our map with `null` for the updated value
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : previousParameterContext.getParameters().entrySet()) {
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : previousParameterContext.getEffectiveParameters().entrySet()) {
|
||||
final ParameterDescriptor previousDescriptor = entry.getKey();
|
||||
final Parameter previousParameter = entry.getValue();
|
||||
|
||||
@ -3206,7 +3208,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
private Map<String, ParameterUpdate> createParameterUpdates(final ParameterContext parameterContext, final BiFunction<ParameterDescriptor, String, ParameterUpdate> parameterUpdateMapper) {
|
||||
final Map<String, ParameterUpdate> updatedParameters = new HashMap<>();
|
||||
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : parameterContext.getParameters().entrySet()) {
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : parameterContext.getEffectiveParameters().entrySet()) {
|
||||
final ParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
final Parameter parameter = entry.getValue();
|
||||
|
||||
@ -3979,7 +3981,7 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
group.setPosition(new Position(proposed.getPosition().getX(), proposed.getPosition().getY()));
|
||||
}
|
||||
|
||||
updateParameterContext(group, proposed, versionedParameterContexts, componentIdSeed);
|
||||
flowManager.withParameterContextResolution(() -> updateParameterContext(group, proposed, versionedParameterContexts, componentIdSeed));
|
||||
updateVariableRegistry(group, proposed, variablesToSkip);
|
||||
|
||||
final FlowFileConcurrency flowFileConcurrency = proposed.getFlowFileConcurrency() == null ? FlowFileConcurrency.UNBOUNDED :
|
||||
@ -4411,7 +4413,8 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
}
|
||||
}
|
||||
|
||||
private ParameterContext createParameterContext(final VersionedParameterContext versionedParameterContext, final String parameterContextId) {
|
||||
private ParameterContext createParameterContext(final VersionedParameterContext versionedParameterContext, final String parameterContextId,
|
||||
final Map<String, VersionedParameterContext> versionedParameterContexts, final String componentIdSeed) {
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
for (final VersionedParameter versionedParameter : versionedParameterContext.getParameters()) {
|
||||
final ParameterDescriptor descriptor = new ParameterDescriptor.Builder()
|
||||
@ -4423,11 +4426,32 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
final Parameter parameter = new Parameter(descriptor, versionedParameter.getValue());
|
||||
parameters.put(versionedParameter.getName(), parameter);
|
||||
}
|
||||
final List<ParameterContextReferenceEntity> parameterContextRefs = new ArrayList<>();
|
||||
if (versionedParameterContext.getInheritedParameterContexts() != null) {
|
||||
parameterContextRefs.addAll(versionedParameterContext.getInheritedParameterContexts().stream()
|
||||
.map(name -> createParameterReferenceEntity(name, versionedParameterContexts, componentIdSeed))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
return flowManager.createParameterContext(parameterContextId, versionedParameterContext.getName(), parameters);
|
||||
return flowManager.createParameterContext(parameterContextId, versionedParameterContext.getName(), parameters, parameterContextRefs);
|
||||
}
|
||||
|
||||
private void addMissingParameters(final VersionedParameterContext versionedParameterContext, final ParameterContext currentParameterContext) {
|
||||
private ParameterContextReferenceEntity createParameterReferenceEntity(final String parameterContextName,
|
||||
final Map<String, VersionedParameterContext> versionedParameterContexts,
|
||||
final String componentIdSeed) {
|
||||
final ParameterContextReferenceEntity entity = new ParameterContextReferenceEntity();
|
||||
final ParameterContextReferenceDTO dto = new ParameterContextReferenceDTO();
|
||||
final VersionedParameterContext versionedParameterContext = versionedParameterContexts.get(parameterContextName);
|
||||
final ParameterContext selectedParameterContext = selectParameterContext(versionedParameterContext, componentIdSeed, versionedParameterContexts);
|
||||
dto.setName(selectedParameterContext.getName());
|
||||
dto.setId(selectedParameterContext.getIdentifier());
|
||||
entity.setId(dto.getId());
|
||||
entity.setComponent(dto);
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void addMissingConfiguration(final VersionedParameterContext versionedParameterContext, final ParameterContext currentParameterContext,
|
||||
final String componentIdSeed, final Map<String, VersionedParameterContext> versionedParameterContexts) {
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
for (final VersionedParameter versionedParameter : versionedParameterContext.getParameters()) {
|
||||
final Optional<Parameter> parameterOption = currentParameterContext.getParameter(versionedParameter.getName());
|
||||
@ -4447,6 +4471,15 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
}
|
||||
|
||||
currentParameterContext.setParameters(parameters);
|
||||
|
||||
// If the current parameter context doesn't have any inherited param contexts but the versioned one does,
|
||||
// add the versioned ones.
|
||||
if (versionedParameterContext.getInheritedParameterContexts() != null && !versionedParameterContext.getInheritedParameterContexts().isEmpty()
|
||||
&& currentParameterContext.getInheritedParameterContexts().isEmpty()) {
|
||||
currentParameterContext.setInheritedParameterContexts(versionedParameterContext.getInheritedParameterContexts().stream()
|
||||
.map(name -> selectParameterContext(versionedParameterContexts.get(name), componentIdSeed, versionedParameterContexts))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
private ParameterContext getParameterContextByName(final String contextName) {
|
||||
@ -4473,25 +4506,30 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
+ "' does not exist in set of available parameter contexts [" + paramContextNames + "]");
|
||||
}
|
||||
|
||||
final ParameterContext contextByName = getParameterContextByName(versionedParameterContext.getName());
|
||||
final ParameterContext selectedParameterContext;
|
||||
if (contextByName == null) {
|
||||
final String parameterContextId = generateUuid(versionedParameterContext.getName(), versionedParameterContext.getName(), componentIdSeed);
|
||||
selectedParameterContext = createParameterContext(versionedParameterContext, parameterContextId);
|
||||
} else {
|
||||
selectedParameterContext = contextByName;
|
||||
addMissingParameters(versionedParameterContext, selectedParameterContext);
|
||||
}
|
||||
|
||||
final ParameterContext selectedParameterContext = selectParameterContext(versionedParameterContext, componentIdSeed, versionedParameterContexts);
|
||||
group.setParameterContext(selectedParameterContext);
|
||||
} else {
|
||||
// Update the current Parameter Context so that it has any Parameters included in the proposed context
|
||||
final VersionedParameterContext versionedParameterContext = versionedParameterContexts.get(proposedParameterContextName);
|
||||
addMissingParameters(versionedParameterContext, currentParamContext);
|
||||
addMissingConfiguration(versionedParameterContext, currentParamContext, componentIdSeed, versionedParameterContexts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ParameterContext selectParameterContext(final VersionedParameterContext versionedParameterContext, final String componentIdSeed,
|
||||
final Map<String, VersionedParameterContext> versionedParameterContexts) {
|
||||
final ParameterContext contextByName = getParameterContextByName(versionedParameterContext.getName());
|
||||
final ParameterContext selectedParameterContext;
|
||||
if (contextByName == null) {
|
||||
final String parameterContextId = generateUuid(versionedParameterContext.getName(), versionedParameterContext.getName(), componentIdSeed);
|
||||
selectedParameterContext = createParameterContext(versionedParameterContext, parameterContextId, versionedParameterContexts, componentIdSeed);
|
||||
} else {
|
||||
selectedParameterContext = contextByName;
|
||||
addMissingConfiguration(versionedParameterContext, selectedParameterContext, componentIdSeed, versionedParameterContexts);
|
||||
}
|
||||
return selectedParameterContext;
|
||||
}
|
||||
|
||||
private void updateVariableRegistry(final ProcessGroup group, final VersionedProcessGroup proposed, final Set<String> variablesToSkip) {
|
||||
// Determine which variables have been added/removed and add/remove them from this group's variable registry.
|
||||
// We don't worry about if a variable value has changed, because variables are designed to be 'environment specific.'
|
||||
@ -5633,6 +5671,17 @@ public final class StandardProcessGroup implements ProcessGroup {
|
||||
return dataValve;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referencesParameterContext(final ParameterContext parameterContext) {
|
||||
final ParameterContext ownParameterContext = this.getParameterContext();
|
||||
if (ownParameterContext == null || parameterContext == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ownParameterContext.getIdentifier().equals(parameterContext.getIdentifier())
|
||||
|| ownParameterContext.inheritsFrom(parameterContext.getIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultFlowFileExpiration(final String defaultFlowFileExpiration) {
|
||||
// use default if value not provided
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.parameter;
|
||||
|
||||
/**
|
||||
* Represents only an ID reference for a ParameterContext.
|
||||
*/
|
||||
public class ReferenceOnlyParameterContext extends StandardParameterContext {
|
||||
|
||||
public ReferenceOnlyParameterContext(String id) {
|
||||
super(id, String.format("Reference-Only Parameter Context [%s]", id), ParameterReferenceManager.EMPTY, null);
|
||||
}
|
||||
}
|
@ -16,10 +16,14 @@
|
||||
*/
|
||||
package org.apache.nifi.parameter;
|
||||
|
||||
import org.apache.nifi.authorization.AccessDeniedException;
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.Resource;
|
||||
import org.apache.nifi.authorization.resource.Authorizable;
|
||||
import org.apache.nifi.authorization.resource.ResourceFactory;
|
||||
import org.apache.nifi.authorization.resource.ResourceType;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.controller.ComponentNode;
|
||||
import org.apache.nifi.controller.ProcessorNode;
|
||||
@ -30,14 +34,18 @@ import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StandardParameterContext implements ParameterContext {
|
||||
private static final Logger logger = LoggerFactory.getLogger(StandardParameterContext.class);
|
||||
@ -49,14 +57,15 @@ public class StandardParameterContext implements ParameterContext {
|
||||
private String name;
|
||||
private long version = 0L;
|
||||
private final Map<ParameterDescriptor, Parameter> parameters = new LinkedHashMap<>();
|
||||
private final List<ParameterContext> inheritedParameterContexts = new ArrayList<>();
|
||||
private volatile String description;
|
||||
|
||||
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
private final Lock readLock = rwLock.readLock();
|
||||
private final Lock writeLock = rwLock.writeLock();
|
||||
|
||||
|
||||
public StandardParameterContext(final String id, final String name, final ParameterReferenceManager parameterReferenceManager, final Authorizable parentAuthorizable) {
|
||||
public StandardParameterContext(final String id, final String name, final ParameterReferenceManager parameterReferenceManager,
|
||||
final Authorizable parentAuthorizable) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
this.name = Objects.requireNonNull(name);
|
||||
this.parameterReferenceManager = parameterReferenceManager;
|
||||
@ -102,43 +111,57 @@ public class StandardParameterContext implements ParameterContext {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(final Map<String, Parameter> updatedParameters) {
|
||||
final Map<String, ParameterUpdate> parameterUpdates = new HashMap<>();
|
||||
boolean changeAffectingComponents = false;
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
this.version++;
|
||||
verifyCanSetParameters(updatedParameters);
|
||||
final Map<ParameterDescriptor, Parameter> currentEffectiveParameters = getEffectiveParameters();
|
||||
final Map<ParameterDescriptor, Parameter> effectiveProposedParameters = getEffectiveParameters(getProposedParameters(updatedParameters));
|
||||
|
||||
for (final Map.Entry<String, Parameter> entry : updatedParameters.entrySet()) {
|
||||
final String parameterName = entry.getKey();
|
||||
final Parameter parameter = entry.getValue();
|
||||
final Map<String, Parameter> effectiveParameterUpdates = getEffectiveParameterUpdates(currentEffectiveParameters, effectiveProposedParameters);
|
||||
|
||||
if (parameter == null) {
|
||||
changeAffectingComponents = true;
|
||||
verifyCanSetParameters(effectiveParameterUpdates);
|
||||
|
||||
final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder().name(parameterName).build();
|
||||
final Parameter oldParameter = parameters.remove(parameterDescriptor);
|
||||
// Update the actual parameters
|
||||
updateParameters(parameters, updatedParameters, true);
|
||||
|
||||
parameterUpdates.put(parameterName, new StandardParameterUpdate(parameterName, oldParameter.getValue(), null, parameterDescriptor.isSensitive()));
|
||||
} else {
|
||||
final Parameter updatedParameter = createFullyPopulatedParameter(parameter);
|
||||
|
||||
final Parameter oldParameter = parameters.put(updatedParameter.getDescriptor(), updatedParameter);
|
||||
if (oldParameter == null || !Objects.equals(oldParameter.getValue(), updatedParameter.getValue())) {
|
||||
changeAffectingComponents = true;
|
||||
|
||||
final String previousValue = oldParameter == null ? null : oldParameter.getValue();
|
||||
parameterUpdates.put(parameterName, new StandardParameterUpdate(parameterName, previousValue, updatedParameter.getValue(), updatedParameter.getDescriptor().isSensitive()));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get a list of all effective updates in order to alert referencing components
|
||||
parameterUpdates.putAll(updateParameters(currentEffectiveParameters, effectiveParameterUpdates, false));
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
if (changeAffectingComponents) {
|
||||
alertReferencingComponents(parameterUpdates);
|
||||
}
|
||||
|
||||
private Map<ParameterDescriptor, Parameter> getProposedParameters(final Map<String, Parameter> proposedParameterUpdates) {
|
||||
final Map<ParameterDescriptor, Parameter> proposedParameters = new HashMap<>(this.parameters);
|
||||
for(final Map.Entry<String, Parameter> entry : proposedParameterUpdates.entrySet()) {
|
||||
final String parameterName = entry.getKey();
|
||||
final Parameter parameter = entry.getValue();
|
||||
if (parameter == null) {
|
||||
final Optional<Parameter> existingParameter = getParameter(parameterName);
|
||||
if (existingParameter.isPresent()) {
|
||||
proposedParameters.remove(existingParameter.get().getDescriptor());
|
||||
}
|
||||
} else {
|
||||
// Remove is necessary first in case sensitivity changes
|
||||
proposedParameters.remove(parameter.getDescriptor());
|
||||
proposedParameters.put(parameter.getDescriptor(), parameter);
|
||||
}
|
||||
}
|
||||
return proposedParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alerts all referencing components of any relevant updates.
|
||||
* @param parameterUpdates A map from parameter name to ParameterUpdate (empty if none are applicable)
|
||||
*/
|
||||
private void alertReferencingComponents(final Map<String, ParameterUpdate> parameterUpdates) {
|
||||
if (!parameterUpdates.isEmpty()) {
|
||||
logger.debug("Parameter Context {} was updated. {} parameters changed ({}). Notifying all affected components.", this, parameterUpdates.size(), parameterUpdates);
|
||||
|
||||
for (final ProcessGroup processGroup : parameterReferenceManager.getProcessGroupsBound(this)) {
|
||||
@ -153,6 +176,42 @@ public class StandardParameterContext implements ParameterContext {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map from parameter name to ParameterUpdate for any actual updates to parameters.
|
||||
* @param currentParameters The current parameters
|
||||
* @param updatedParameters An updated parameters map
|
||||
* @param performUpdate If true, this will actually perform the updates on the currentParameters map. Otherwise,
|
||||
* the updates are simply collected and returned.
|
||||
* @return A map from parameter name to ParameterUpdate for any actual parameters
|
||||
*/
|
||||
private Map<String, ParameterUpdate> updateParameters(final Map<ParameterDescriptor, Parameter> currentParameters,
|
||||
final Map<String, Parameter> updatedParameters, final boolean performUpdate) {
|
||||
final Map<String, ParameterUpdate> parameterUpdates = new HashMap<>();
|
||||
|
||||
for (final Map.Entry<String, Parameter> entry : updatedParameters.entrySet()) {
|
||||
final String parameterName = entry.getKey();
|
||||
final Parameter parameter = entry.getValue();
|
||||
|
||||
if (parameter == null) {
|
||||
final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder().name(parameterName).build();
|
||||
final Parameter oldParameter = performUpdate ? currentParameters.remove(parameterDescriptor)
|
||||
: currentParameters.get(parameterDescriptor);
|
||||
|
||||
parameterUpdates.put(parameterName, new StandardParameterUpdate(parameterName, oldParameter.getValue(), null, parameterDescriptor.isSensitive()));
|
||||
} else {
|
||||
final Parameter updatedParameter = createFullyPopulatedParameter(parameter);
|
||||
|
||||
final Parameter oldParameter = performUpdate ? currentParameters.put(updatedParameter.getDescriptor(), updatedParameter)
|
||||
: currentParameters.get(updatedParameter.getDescriptor());
|
||||
if (oldParameter == null || !Objects.equals(oldParameter.getValue(), updatedParameter.getValue())) {
|
||||
final String previousValue = oldParameter == null ? null : oldParameter.getValue();
|
||||
parameterUpdates.put(parameterName, new StandardParameterUpdate(parameterName, previousValue, updatedParameter.getValue(), updatedParameter.getDescriptor().isSensitive()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return parameterUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* When updating a Parameter, the provided 'updated' Parameter may or may not contain a value. This is done because once a Parameter is set,
|
||||
* a user may want to change the description of the Parameter but cannot include the value of the Parameter in the request if the Parameter is sensitive (because
|
||||
@ -212,7 +271,7 @@ public class StandardParameterContext implements ParameterContext {
|
||||
public boolean isEmpty() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return parameters.isEmpty();
|
||||
return getEffectiveParameters().isEmpty();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
@ -228,12 +287,25 @@ public class StandardParameterContext implements ParameterContext {
|
||||
// the name via the Expression Language. In this case, we want to strip out those
|
||||
// escaping tick marks and use just the raw name for looking up the Parameter.
|
||||
final ParameterDescriptor unescaped = unescape(parameterDescriptor);
|
||||
return Optional.ofNullable(parameters.get(unescaped));
|
||||
// Short circuit getEffectiveParameters if we know there are no inherited ParameterContexts
|
||||
return Optional.ofNullable((inheritedParameterContexts.isEmpty() ? parameters : getEffectiveParameters())
|
||||
.get(unescaped));
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEffectiveValueIfRemoved(final ParameterDescriptor parameterDescriptor) {
|
||||
final Map<ParameterDescriptor, List<Parameter>> allOverrides = getAllParametersIncludingOverrides();
|
||||
final List<Parameter> parameters = allOverrides.get(parameterDescriptor);
|
||||
if (parameters == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parameters.size() > 1;
|
||||
}
|
||||
|
||||
private ParameterDescriptor unescape(final ParameterDescriptor descriptor) {
|
||||
final String parameterName = descriptor.getName().trim();
|
||||
if ((parameterName.startsWith("'") && parameterName.endsWith("'")) || (parameterName.startsWith("\"") && parameterName.endsWith("\""))) {
|
||||
@ -257,13 +329,251 @@ public class StandardParameterContext implements ParameterContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ParameterDescriptor, Parameter> getEffectiveParameters() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return this.getEffectiveParameters(inheritedParameterContexts);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an effective view of the parameters, including nested parameters, assuming the given map of parameters.
|
||||
* This allows an inspection of what parameters would be available if the given parameters were set in this ParameterContext.
|
||||
* @param proposedParameters A Map of proposed parameters that should be used in place of the current parameters
|
||||
* @return The view of the parameters with all overriding applied
|
||||
*/
|
||||
private Map<ParameterDescriptor, Parameter> getEffectiveParameters(final Map<ParameterDescriptor, Parameter> proposedParameters) {
|
||||
return getEffectiveParameters(this.inheritedParameterContexts, proposedParameters, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an effective view of the parameters, including nested parameters, assuming the given list of ParameterContexts.
|
||||
* This allows an inspection of what parameters would be available if the given list were set in this ParameterContext.
|
||||
* @param parameterContexts An ordered list of ParameterContexts from which to inherit
|
||||
* @return The view of the parameters with all overriding applied
|
||||
*/
|
||||
private Map<ParameterDescriptor, Parameter> getEffectiveParameters(final List<ParameterContext> parameterContexts) {
|
||||
return getEffectiveParameters(parameterContexts, this.parameters, new HashMap<>());
|
||||
}
|
||||
|
||||
private Map<ParameterDescriptor, List<Parameter>> getAllParametersIncludingOverrides() {
|
||||
final Map<ParameterDescriptor, List<Parameter>> allOverrides = new HashMap<>();
|
||||
getEffectiveParameters(this.inheritedParameterContexts, this.parameters, allOverrides);
|
||||
return allOverrides;
|
||||
}
|
||||
|
||||
private Map<ParameterDescriptor, Parameter> getEffectiveParameters(final List<ParameterContext> parameterContexts,
|
||||
final Map<ParameterDescriptor, Parameter> proposedParameters,
|
||||
final Map<ParameterDescriptor, List<Parameter>> allOverrides) {
|
||||
final Map<ParameterDescriptor, Parameter> effectiveParameters = new LinkedHashMap<>();
|
||||
|
||||
// Loop backwards so that the first ParameterContext in the list will override any parameters later in the list
|
||||
for(int i = parameterContexts.size() - 1; i >= 0; i--) {
|
||||
ParameterContext parameterContext = parameterContexts.get(i);
|
||||
allOverrides.putAll(overrideParameters(effectiveParameters, parameterContext.getEffectiveParameters(), parameterContext));
|
||||
}
|
||||
|
||||
// Finally, override all child parameters with our own
|
||||
allOverrides.putAll(overrideParameters(effectiveParameters, proposedParameters, this));
|
||||
|
||||
return effectiveParameters;
|
||||
}
|
||||
|
||||
private Map<ParameterDescriptor, List<Parameter>> overrideParameters(final Map<ParameterDescriptor, Parameter> existingParameters,
|
||||
final Map<ParameterDescriptor, Parameter> overridingParameters,
|
||||
final ParameterContext overridingContext) {
|
||||
final Map<ParameterDescriptor, List<Parameter>> allOverrides = new HashMap<>();
|
||||
for(final Map.Entry<ParameterDescriptor, Parameter> entry : existingParameters.entrySet()) {
|
||||
final List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(entry.getValue());
|
||||
allOverrides.put(entry.getKey(), parameters);
|
||||
}
|
||||
|
||||
for(final Map.Entry<ParameterDescriptor, Parameter> entry : overridingParameters.entrySet()) {
|
||||
final ParameterDescriptor overridingParameterDescriptor = entry.getKey();
|
||||
Parameter overridingParameter = entry.getValue();
|
||||
|
||||
if (existingParameters.containsKey(overridingParameterDescriptor)) {
|
||||
final Parameter existingParameter = existingParameters.get(overridingParameterDescriptor);
|
||||
final ParameterDescriptor existingParameterDescriptor = existingParameter.getDescriptor();
|
||||
|
||||
if (existingParameterDescriptor.isSensitive() && !overridingParameterDescriptor.isSensitive()) {
|
||||
throw new IllegalStateException(String.format("Cannot add ParameterContext because Sensitive Parameter [%s] would be overridden by " +
|
||||
"a Non Sensitive Parameter with the same name", existingParameterDescriptor.getName()));
|
||||
}
|
||||
|
||||
if (!existingParameterDescriptor.isSensitive() && overridingParameterDescriptor.isSensitive()) {
|
||||
throw new IllegalStateException(String.format("Cannot add ParameterContext because Non Sensitive Parameter [%s] would be overridden by " +
|
||||
"a Sensitive Parameter with the same name", existingParameterDescriptor.getName()));
|
||||
}
|
||||
}
|
||||
if (overridingParameter.getParameterContextId() == null) {
|
||||
overridingParameter = new Parameter(overridingParameter, overridingContext.getIdentifier());
|
||||
}
|
||||
allOverrides.computeIfAbsent(overridingParameterDescriptor, p -> new ArrayList<>()).add(overridingParameter);
|
||||
|
||||
existingParameters.put(overridingParameterDescriptor, overridingParameter);
|
||||
}
|
||||
return allOverrides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterReferenceManager getParameterReferenceManager() {
|
||||
return parameterReferenceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that no cycles would exist in the ParameterContext reference graph, if this ParameterContext were
|
||||
* to inherit from the given list of ParameterContexts.
|
||||
* @param parameterContexts A list of proposed ParameterContexts
|
||||
*/
|
||||
private void verifyNoCycles(final List<ParameterContext> parameterContexts) {
|
||||
final Stack<String> traversedIds = new Stack<>();
|
||||
traversedIds.push(id);
|
||||
verifyNoCycles(traversedIds, parameterContexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for performing a depth first search to verify there are no cycles in the proposed
|
||||
* list of ParameterContexts.
|
||||
* @param traversedIds A collection of already traversed ids in the graph
|
||||
* @param parameterContexts The ParameterContexts for which to check for cycles
|
||||
* @throws IllegalStateException If a cycle was detected
|
||||
*/
|
||||
private void verifyNoCycles(final Stack<String> traversedIds, final List<ParameterContext> parameterContexts) {
|
||||
for (final ParameterContext parameterContext : parameterContexts) {
|
||||
final String id = parameterContext.getIdentifier();
|
||||
if (traversedIds.contains(id)) {
|
||||
throw new IllegalStateException(String.format("Circular references in Parameter Contexts not allowed. [%s] was detected in a cycle.", parameterContext.getName()));
|
||||
}
|
||||
|
||||
traversedIds.push(id);
|
||||
verifyNoCycles(traversedIds, parameterContext.getInheritedParameterContexts());
|
||||
traversedIds.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInheritedParameterContexts(final List<ParameterContext> inheritedParameterContexts) {
|
||||
if (inheritedParameterContexts.equals(this.inheritedParameterContexts)) {
|
||||
// No changes
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, ParameterUpdate> parameterUpdates = new HashMap<>();
|
||||
|
||||
writeLock.lock();
|
||||
try {
|
||||
this.version++;
|
||||
verifyNoCycles(inheritedParameterContexts);
|
||||
|
||||
final Map<ParameterDescriptor, Parameter> currentEffectiveParameters = getEffectiveParameters();
|
||||
final Map<ParameterDescriptor, Parameter> effectiveProposedParameters = getEffectiveParameters(inheritedParameterContexts);
|
||||
final Map<String, Parameter> effectiveParameterUpdates = getEffectiveParameterUpdates(currentEffectiveParameters, effectiveProposedParameters);
|
||||
|
||||
try {
|
||||
verifyCanSetParameters(currentEffectiveParameters, effectiveParameterUpdates);
|
||||
} catch (final IllegalStateException e) {
|
||||
// Wrap with a more accurate message
|
||||
throw new IllegalStateException(String.format("Could not update inherited Parameter Contexts for Parameter Context [%s] because: %s",
|
||||
name, e.getMessage()), e);
|
||||
}
|
||||
|
||||
this.inheritedParameterContexts.clear();
|
||||
|
||||
this.inheritedParameterContexts.addAll(inheritedParameterContexts);
|
||||
|
||||
parameterUpdates.putAll(updateParameters(currentEffectiveParameters, effectiveParameterUpdates, false));
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
alertReferencingComponents(parameterUpdates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map that can be used to indicate all effective parameters updates, including removed parameters.
|
||||
* @param currentEffectiveParameters A current map of effective parameters
|
||||
* @param effectiveProposedParameters A map of effective parameters that would result if a proposed update were applied
|
||||
* @return a map that can be used to indicate all effective parameters updates, including removed parameters
|
||||
*/
|
||||
private static Map<String, Parameter> getEffectiveParameterUpdates(final Map<ParameterDescriptor, Parameter> currentEffectiveParameters,
|
||||
final Map<ParameterDescriptor, Parameter> effectiveProposedParameters) {
|
||||
final Map<String, Parameter> effectiveParameterUpdates = new HashMap<>();
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : effectiveProposedParameters.entrySet()) {
|
||||
final ParameterDescriptor proposedParameterDescriptor = entry.getKey();
|
||||
final Parameter proposedParameter = entry.getValue();
|
||||
if (currentEffectiveParameters.containsKey(proposedParameterDescriptor)) {
|
||||
final Parameter currentParameter = currentEffectiveParameters.get(proposedParameterDescriptor);
|
||||
if (!currentParameter.equals(proposedParameter) || currentParameter.getDescriptor().isSensitive() != proposedParameter.getDescriptor().isSensitive()) {
|
||||
// The parameter has been updated in some way
|
||||
effectiveParameterUpdates.put(proposedParameterDescriptor.getName(), proposedParameter);
|
||||
}
|
||||
} else {
|
||||
// It's a new parameter
|
||||
effectiveParameterUpdates.put(proposedParameterDescriptor.getName(), proposedParameter);
|
||||
}
|
||||
}
|
||||
for (final Map.Entry<ParameterDescriptor, Parameter> entry : currentEffectiveParameters.entrySet()) {
|
||||
final ParameterDescriptor currentParameterDescriptor = entry.getKey();
|
||||
if (!effectiveProposedParameters.containsKey(currentParameterDescriptor)) {
|
||||
// If a current parameter is not in the proposed parameters, it was effectively removed
|
||||
effectiveParameterUpdates.put(currentParameterDescriptor.getName(), null);
|
||||
}
|
||||
}
|
||||
return effectiveParameterUpdates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ParameterContext> getInheritedParameterContexts() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return new ArrayList<>(inheritedParameterContexts);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getInheritedParameterContextNames() {
|
||||
readLock.lock();
|
||||
try {
|
||||
return inheritedParameterContexts.stream().map(ParameterContext::getName)
|
||||
.collect(Collectors.toList());
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsFrom(final String parameterContextId) {
|
||||
readLock.lock();
|
||||
try {
|
||||
if (!inheritedParameterContexts.isEmpty()) {
|
||||
for(final ParameterContext inheritedParameterContext : inheritedParameterContexts) {
|
||||
if (inheritedParameterContext.getIdentifier().equals(parameterContextId)) {
|
||||
return true;
|
||||
}
|
||||
if (inheritedParameterContext.inheritsFrom(parameterContextId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyCanSetParameters(final Map<String, Parameter> updatedParameters) {
|
||||
verifyCanSetParameters(parameters, updatedParameters);
|
||||
}
|
||||
|
||||
public void verifyCanSetParameters(final Map<ParameterDescriptor, Parameter> currentParameters, final Map<String, Parameter> updatedParameters) {
|
||||
// Ensure that the updated parameters will not result in changing the sensitivity flag of any parameter.
|
||||
for (final Map.Entry<String, Parameter> entry : updatedParameters.entrySet()) {
|
||||
final String parameterName = entry.getKey();
|
||||
@ -278,14 +588,14 @@ public class StandardParameterContext implements ParameterContext {
|
||||
throw new IllegalArgumentException("Parameter '" + parameterName + "' was specified with the wrong key in the Map");
|
||||
}
|
||||
|
||||
validateSensitiveFlag(parameter);
|
||||
validateSensitiveFlag(currentParameters, parameter);
|
||||
validateReferencingComponents(parameterName, parameter, "update");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSensitiveFlag(final Parameter updatedParameter) {
|
||||
private void validateSensitiveFlag(final Map<ParameterDescriptor, Parameter> currentParameters, final Parameter updatedParameter) {
|
||||
final ParameterDescriptor updatedDescriptor = updatedParameter.getDescriptor();
|
||||
final Parameter existingParameter = parameters.get(updatedDescriptor);
|
||||
final Parameter existingParameter = currentParameters.get(updatedDescriptor);
|
||||
|
||||
if (existingParameter == null) {
|
||||
return;
|
||||
@ -357,6 +667,17 @@ public class StandardParameterContext implements ParameterContext {
|
||||
return "StandardParameterContext[name=" + name + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorize(final Authorizer authorizer, final RequestAction action, final NiFiUser user) throws AccessDeniedException {
|
||||
ParameterContext.super.authorize(authorizer, action, user);
|
||||
|
||||
if (RequestAction.READ == action) {
|
||||
for (final ParameterContext parameterContext : inheritedParameterContexts) {
|
||||
parameterContext.authorize(authorizer, action, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authorizable getParentAuthorizable() {
|
||||
return new Authorizable() {
|
||||
|
@ -21,10 +21,17 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StandardParameterContextManager implements ParameterContextManager {
|
||||
private final Map<String, ParameterContext> parameterContexts = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean hasParameterContext(final String id) {
|
||||
return parameterContexts.get(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ParameterContext getParameterContext(final String id) {
|
||||
return parameterContexts.get(id);
|
||||
@ -35,7 +42,9 @@ public class StandardParameterContextManager implements ParameterContextManager
|
||||
Objects.requireNonNull(parameterContext);
|
||||
|
||||
if (parameterContexts.containsKey(parameterContext.getIdentifier())) {
|
||||
throw new IllegalStateException("Cannot add Parameter Context because another Parameter Context already exists with the same ID");
|
||||
if (!(parameterContexts.get(parameterContext.getIdentifier()) instanceof ReferenceOnlyParameterContext)) {
|
||||
throw new IllegalStateException("Cannot add Parameter Context because another Parameter Context already exists with the same ID");
|
||||
}
|
||||
}
|
||||
|
||||
for (final ParameterContext context : parameterContexts.values()) {
|
||||
@ -57,4 +66,9 @@ public class StandardParameterContextManager implements ParameterContextManager
|
||||
public synchronized Set<ParameterContext> getParameterContexts() {
|
||||
return new HashSet<>(parameterContexts.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ParameterContext> getParameterContextNameMapping() {
|
||||
return parameterContexts.values().stream().collect(Collectors.toMap(ParameterContext::getName, Function.identity()));
|
||||
}
|
||||
}
|
||||
|
@ -51,9 +51,7 @@ public class StandardParameterReferenceManager implements ParameterReferenceMana
|
||||
@Override
|
||||
public Set<ProcessGroup> getProcessGroupsBound(final ParameterContext parameterContext) {
|
||||
final ProcessGroup rootGroup = flowManager.getRootGroup();
|
||||
final String contextId = parameterContext.getIdentifier();
|
||||
final List<ProcessGroup> referencingGroups = rootGroup.findAllProcessGroups(
|
||||
group -> group.getParameterContext() != null && group.getParameterContext().getIdentifier().equals(contextId));
|
||||
final List<ProcessGroup> referencingGroups = rootGroup.findAllProcessGroups(group -> group.referencesParameterContext(parameterContext));
|
||||
|
||||
return new HashSet<>(referencingGroups);
|
||||
}
|
||||
@ -63,9 +61,7 @@ public class StandardParameterReferenceManager implements ParameterReferenceMana
|
||||
final Set<T> referencingComponents = new HashSet<>();
|
||||
|
||||
final ProcessGroup rootGroup = flowManager.getRootGroup();
|
||||
final String contextId = parameterContext.getIdentifier();
|
||||
final List<ProcessGroup> referencingGroups = rootGroup.findAllProcessGroups(
|
||||
group -> group.getParameterContext() != null && group.getParameterContext().getIdentifier().equals(contextId));
|
||||
final List<ProcessGroup> referencingGroups = rootGroup.findAllProcessGroups(group -> group.referencesParameterContext(parameterContext));
|
||||
|
||||
for (final ProcessGroup group : referencingGroups) {
|
||||
for (final T componentNode : componentFunction.apply(group)) {
|
||||
|
@ -688,15 +688,7 @@ public class NiFiRegistryFlowMapper {
|
||||
final Map<String, VersionedParameterContext> parameterContexts) {
|
||||
final ParameterContext parameterContext = processGroup.getParameterContext();
|
||||
if (parameterContext != null) {
|
||||
// map this process group's parameter context and add to the collection
|
||||
final Set<VersionedParameter> parameters = parameterContext.getParameters().values().stream()
|
||||
.map(this::mapParameter)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final VersionedParameterContext versionedContext = new VersionedParameterContext();
|
||||
versionedContext.setName(parameterContext.getName());
|
||||
versionedContext.setParameters(parameters);
|
||||
parameterContexts.put(versionedContext.getName(), versionedContext);
|
||||
mapParameterContext(parameterContext, parameterContexts);
|
||||
}
|
||||
|
||||
for (final ProcessGroup child : processGroup.getProcessGroups()) {
|
||||
@ -707,6 +699,23 @@ public class NiFiRegistryFlowMapper {
|
||||
}
|
||||
}
|
||||
|
||||
private void mapParameterContext(final ParameterContext parameterContext, final Map<String, VersionedParameterContext> parameterContexts) {
|
||||
// map this process group's parameter context and add to the collection
|
||||
final Set<VersionedParameter> parameters = parameterContext.getParameters().values().stream()
|
||||
.map(this::mapParameter)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final VersionedParameterContext versionedContext = new VersionedParameterContext();
|
||||
versionedContext.setName(parameterContext.getName());
|
||||
versionedContext.setParameters(parameters);
|
||||
versionedContext.setInheritedParameterContexts(parameterContext.getInheritedParameterContextNames());
|
||||
for(final ParameterContext inheritedParameterContext : parameterContext.getInheritedParameterContexts()) {
|
||||
mapParameterContext(inheritedParameterContext, parameterContexts);
|
||||
}
|
||||
|
||||
parameterContexts.put(versionedContext.getName(), versionedContext);
|
||||
}
|
||||
|
||||
private VersionedParameter mapParameter(final Parameter parameter) {
|
||||
if (parameter == null) {
|
||||
return null;
|
||||
|
@ -22,11 +22,14 @@ import org.apache.nifi.controller.service.ControllerServiceState;
|
||||
import org.apache.nifi.groups.ProcessGroup;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ -172,9 +175,7 @@ public class TestStandardParameterContext {
|
||||
final HashMapParameterReferenceManager referenceManager = new HashMapParameterReferenceManager();
|
||||
final StandardParameterContext context = new StandardParameterContext("unit-test-context", "unit-test-context", referenceManager, null);
|
||||
|
||||
final ProcessorNode procNode = Mockito.mock(ProcessorNode.class);
|
||||
Mockito.when(procNode.isRunning()).thenReturn(false);
|
||||
referenceManager.addProcessorReference("abc", procNode);
|
||||
final ProcessorNode procNode = getProcessorNode("abc", referenceManager);
|
||||
|
||||
final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build();
|
||||
|
||||
@ -190,17 +191,15 @@ public class TestStandardParameterContext {
|
||||
assertEquals("321", context.getParameter("abc").get().getValue());
|
||||
|
||||
// Make processor 'running'
|
||||
Mockito.when(procNode.isRunning()).thenReturn(true);
|
||||
startProcessor(procNode);
|
||||
|
||||
parameters.clear();
|
||||
parameters.put("abc", new Parameter(abcDescriptor, "123"));
|
||||
|
||||
try {
|
||||
context.setParameters(parameters);
|
||||
Assert.fail("Was able to change parameter while referencing processor was running");
|
||||
} catch (final IllegalStateException expected) {
|
||||
}
|
||||
// Cannot update parameters while running
|
||||
Assert.assertThrows(IllegalStateException.class, () -> context.setParameters(parameters));
|
||||
|
||||
// This passes no parameters to update, so it should be fine
|
||||
context.setParameters(Collections.emptyMap());
|
||||
|
||||
parameters.clear();
|
||||
@ -214,13 +213,204 @@ public class TestStandardParameterContext {
|
||||
assertEquals("321", context.getParameter("abc").get().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangingNestedParameterForRunningProcessor() {
|
||||
final String inheritedParamName = "def";
|
||||
final String originalValue = "123";
|
||||
final String changedValue = "321";
|
||||
|
||||
final HashMapParameterReferenceManager referenceManager = new HashMapParameterReferenceManager();
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup, referenceManager);
|
||||
addParameter(a, "abc", "123");
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup, referenceManager);
|
||||
addParameter(b, inheritedParamName, originalValue);
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
|
||||
// Structure is now:
|
||||
// Param context A
|
||||
// Param abc
|
||||
// (Inherited) Param def (from B)
|
||||
|
||||
// Processor references param 'def'
|
||||
final ProcessorNode procNode = getProcessorNode(inheritedParamName, referenceManager);
|
||||
|
||||
// Show that inherited param 'def' starts with the original value from B
|
||||
Assert.assertEquals(originalValue, a.getParameter(inheritedParamName).get().getValue());
|
||||
|
||||
// Now demonstrate that we can't effectively add the parameter by referencing Context B while processor runs
|
||||
a.setInheritedParameterContexts(Collections.emptyList()); // A now no longer includes 'def'
|
||||
startProcessor(procNode);
|
||||
try {
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
Assert.fail("Was able to change effective parameter while referencing processor was running");
|
||||
} catch (final IllegalStateException expected) {
|
||||
Assert.assertTrue(expected.getMessage().contains("def"));
|
||||
}
|
||||
|
||||
// Safely add Context B, and show we can't effectively remove 'def' while processor runs
|
||||
stopProcessor(procNode);
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
startProcessor(procNode);
|
||||
try {
|
||||
a.setInheritedParameterContexts(Collections.emptyList());
|
||||
Assert.fail("Was able to remove parameter while referencing processor was running");
|
||||
} catch (final IllegalStateException expected) {
|
||||
Assert.assertTrue(expected.getMessage().contains("def"));
|
||||
}
|
||||
|
||||
// Show we can't effectively change the value by changing it in B
|
||||
try {
|
||||
addParameter(b, inheritedParamName, changedValue);
|
||||
Assert.fail("Was able to change parameter while referencing processor was running");
|
||||
} catch (final IllegalStateException expected) {
|
||||
Assert.assertTrue(expected.getMessage().contains("def"));
|
||||
}
|
||||
assertEquals(originalValue, a.getParameter(inheritedParamName).get().getValue());
|
||||
|
||||
// Show we can't effectively change the value by adding Context C with 'def' ahead of 'B'
|
||||
stopProcessor(procNode);
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup, referenceManager);
|
||||
addParameter(c, inheritedParamName, changedValue);
|
||||
startProcessor(procNode);
|
||||
|
||||
try {
|
||||
a.setInheritedParameterContexts(Arrays.asList(c, b));
|
||||
Assert.fail("Was able to change parameter while referencing processor was running");
|
||||
} catch (final IllegalStateException expected) {
|
||||
Assert.assertTrue(expected.getMessage().contains("def"));
|
||||
}
|
||||
assertEquals(originalValue, a.getParameter(inheritedParamName).get().getValue());
|
||||
|
||||
// Show that if the effective value of 'def' doesn't change, we don't prevent updating
|
||||
// ParameterContext references that refer to 'def'
|
||||
a.setInheritedParameterContexts(Arrays.asList(b, c));
|
||||
assertEquals(originalValue, a.getParameter(inheritedParamName).get().getValue());
|
||||
|
||||
stopProcessor(procNode);
|
||||
removeParameter(b, inheritedParamName);
|
||||
b.setInheritedParameterContexts(Collections.singletonList(c));
|
||||
// Now a gets 'def' by inheriting through B and then C.
|
||||
|
||||
// Show that updating a value on a grandchild is prevented because the processor is running and
|
||||
// references the parameter via the grandparent
|
||||
startProcessor(procNode);
|
||||
Assert.assertThrows(IllegalStateException.class, () -> removeParameter(c, inheritedParamName));
|
||||
}
|
||||
|
||||
private static ProcessorNode getProcessorNode(String parameterName, HashMapParameterReferenceManager referenceManager) {
|
||||
final ProcessorNode procNode = Mockito.mock(ProcessorNode.class);
|
||||
Mockito.when(procNode.isRunning()).thenReturn(false);
|
||||
referenceManager.addProcessorReference(parameterName, procNode);
|
||||
return procNode;
|
||||
}
|
||||
|
||||
private static void startProcessor(final ProcessorNode processorNode) {
|
||||
setProcessorRunning(processorNode, true);
|
||||
}
|
||||
|
||||
private static void stopProcessor(final ProcessorNode processorNode) {
|
||||
setProcessorRunning(processorNode, false);
|
||||
}
|
||||
|
||||
private static void setProcessorRunning(final ProcessorNode processorNode, final boolean isRunning) {
|
||||
Mockito.when(processorNode.isRunning()).thenReturn(isRunning);
|
||||
}
|
||||
|
||||
private static void setControllerServiceState(final ControllerServiceNode serviceNode, final ControllerServiceState state) {
|
||||
Mockito.when(serviceNode.getState()).thenReturn(state);
|
||||
}
|
||||
|
||||
private static void enableControllerService(final ControllerServiceNode serviceNode) {
|
||||
setControllerServiceState(serviceNode, ControllerServiceState.ENABLED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlertReferencingComponents() {
|
||||
final String inheritedParamName = "def";
|
||||
final String originalValue = "123";
|
||||
final String changedValue = "321";
|
||||
|
||||
final HashMapParameterReferenceManager referenceManager = Mockito.spy(new HashMapParameterReferenceManager());
|
||||
final Set<ProcessGroup> processGroups = new HashSet<>();
|
||||
final ProcessGroup processGroup = Mockito.mock(ProcessGroup.class);
|
||||
processGroups.add(processGroup);
|
||||
Mockito.when(referenceManager.getProcessGroupsBound(ArgumentMatchers.any())).thenReturn(processGroups);
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup, referenceManager);
|
||||
addParameter(a, "abc", "123");
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup, referenceManager);
|
||||
addParameter(b, inheritedParamName, originalValue);
|
||||
|
||||
getProcessorNode(inheritedParamName, referenceManager);
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
|
||||
// Once for setting abc, once for setting def, and once for adding B to context A
|
||||
Mockito.verify(processGroup, Mockito.times(3)).onParameterContextUpdated(ArgumentMatchers.anyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangingNestedParameterForEnabledControllerService() {
|
||||
final String inheritedParamName = "def";
|
||||
final String inheritedParamName2 = "ghi";
|
||||
final String originalValue = "123";
|
||||
final String changedValue = "321";
|
||||
|
||||
final HashMapParameterReferenceManager referenceManager = new HashMapParameterReferenceManager();
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup, referenceManager);
|
||||
addParameter(a, "abc", "123");
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup, referenceManager);
|
||||
addParameter(b, inheritedParamName, originalValue);
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup, referenceManager);
|
||||
addParameter(c, "ghi", originalValue);
|
||||
|
||||
// Structure is now:
|
||||
// Param context A
|
||||
// Param abc
|
||||
// (Inherited) Param def (from B)
|
||||
|
||||
final ControllerServiceNode serviceNode = Mockito.mock(ControllerServiceNode.class);
|
||||
enableControllerService(serviceNode);
|
||||
|
||||
referenceManager.addControllerServiceReference(inheritedParamName, serviceNode);
|
||||
referenceManager.addControllerServiceReference(inheritedParamName2, serviceNode);
|
||||
|
||||
for (final ControllerServiceState state : EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.ENABLING, ControllerServiceState.DISABLING)) {
|
||||
setControllerServiceState(serviceNode, state);
|
||||
|
||||
Assert.assertThrows(IllegalStateException.class, () -> addParameter(b, inheritedParamName, changedValue));
|
||||
|
||||
Assert.assertThrows(IllegalStateException.class, () -> b.setInheritedParameterContexts(Collections.singletonList(c)));
|
||||
|
||||
assertEquals(originalValue, a.getParameter(inheritedParamName).get().getValue());
|
||||
}
|
||||
|
||||
Assert.assertThrows(IllegalStateException.class, () -> removeParameter(b, inheritedParamName));
|
||||
setControllerServiceState(serviceNode, ControllerServiceState.DISABLED);
|
||||
|
||||
b.setInheritedParameterContexts(Collections.singletonList(c));
|
||||
|
||||
setControllerServiceState(serviceNode, ControllerServiceState.DISABLING);
|
||||
|
||||
Assert.assertThrows(IllegalStateException.class, () -> b.setInheritedParameterContexts(Collections.emptyList()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangingParameterForEnabledControllerService() {
|
||||
final HashMapParameterReferenceManager referenceManager = new HashMapParameterReferenceManager();
|
||||
final StandardParameterContext context = new StandardParameterContext("unit-test-context", "unit-test-context", referenceManager, null);
|
||||
|
||||
final ControllerServiceNode serviceNode = Mockito.mock(ControllerServiceNode.class);
|
||||
Mockito.when(serviceNode.getState()).thenReturn(ControllerServiceState.ENABLED);
|
||||
enableControllerService(serviceNode);
|
||||
|
||||
final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build();
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
@ -234,7 +424,7 @@ public class TestStandardParameterContext {
|
||||
parameters.put("abc", new Parameter(abcDescriptor, "321"));
|
||||
|
||||
for (final ControllerServiceState state : EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.ENABLING, ControllerServiceState.DISABLING)) {
|
||||
Mockito.when(serviceNode.getState()).thenReturn(state);
|
||||
setControllerServiceState(serviceNode, state);
|
||||
|
||||
try {
|
||||
context.setParameters(parameters);
|
||||
@ -256,7 +446,307 @@ public class TestStandardParameterContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterContexts_foundCycle() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
// Set up a hierarchy as follows:
|
||||
// a
|
||||
// / |
|
||||
// b c
|
||||
// / |
|
||||
// d e
|
||||
// |
|
||||
// a (cyclical)
|
||||
//
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup, a); // Here's the cycle
|
||||
final ParameterContext e = createParameterContext("e", parameterContextLookup);
|
||||
|
||||
b.setInheritedParameterContexts(Arrays.asList(d, e));
|
||||
|
||||
Assert.assertThrows(IllegalStateException.class, () -> a.setInheritedParameterContexts(Arrays.asList(b, c)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterContexts_duplicationButNoCycle() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
// Set up a hierarchy as follows:
|
||||
// a
|
||||
// / |
|
||||
// b c
|
||||
// / |
|
||||
// d e
|
||||
// |
|
||||
// c (duplicate node, but not a cycle)
|
||||
//
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup, c); // Here's the duplicate
|
||||
final ParameterContext e = createParameterContext("e", parameterContextLookup);
|
||||
|
||||
b.setInheritedParameterContexts(Arrays.asList(d, e));
|
||||
a.setInheritedParameterContexts(Arrays.asList(b, c));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterContexts_success() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup);
|
||||
final ParameterContext e = createParameterContext("e", parameterContextLookup);
|
||||
final ParameterContext f = createParameterContext("f", parameterContextLookup);
|
||||
|
||||
b.setInheritedParameterContexts(Arrays.asList(d, e));
|
||||
d.setInheritedParameterContexts(Arrays.asList(f));
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b, c));
|
||||
Assert.assertEquals(Arrays.asList(b, c), a.getInheritedParameterContexts());
|
||||
|
||||
Assert.assertArrayEquals(new String[] {"B", "C"}, a.getInheritedParameterContextNames().toArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetEffectiveParameters() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
// Set up a hierarchy as follows:
|
||||
// a
|
||||
// / |
|
||||
// b c
|
||||
// |
|
||||
// d
|
||||
//
|
||||
// Parameter priority should be: a, b, c, d
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterDescriptor foo = addParameter(a, "foo", "a.foo"); // Should take precedence over all other foo params
|
||||
final ParameterDescriptor bar = addParameter(a, "bar", "a.bar"); // Should take precedence over all other foo params
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
addParameter(b,"foo", "b.foo"); // Overridden by a.foo since a is the parent
|
||||
final ParameterDescriptor child = addParameter(b, "child", "b.child");
|
||||
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
addParameter(c, "foo", "c.foo"); // Overridden by a.foo since a is the parent
|
||||
addParameter(c, "child", "c.child"); // Overridden by b.child since b comes first in the list
|
||||
final ParameterDescriptor secondChild = addParameter(c, "secondChild", "c.secondChild");
|
||||
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup);
|
||||
addParameter(d, "foo", "d.foo"); // Overridden by a.foo since a is the grandparent
|
||||
addParameter(d, "child", "d.child"); // Overridden by b.foo since b is the parent
|
||||
final ParameterDescriptor grandchild = addParameter(d, "grandchild", "d.grandchild");
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b, c));
|
||||
b.setInheritedParameterContexts(Arrays.asList(d));
|
||||
|
||||
final Map<ParameterDescriptor, Parameter> effectiveParameters = a.getEffectiveParameters();
|
||||
|
||||
Assert.assertEquals(5, effectiveParameters.size());
|
||||
|
||||
Assert.assertEquals("a.foo", effectiveParameters.get(foo).getValue());
|
||||
Assert.assertEquals("a", effectiveParameters.get(foo).getParameterContextId());
|
||||
|
||||
Assert.assertEquals("a.bar", effectiveParameters.get(bar).getValue());
|
||||
Assert.assertEquals("a", effectiveParameters.get(bar).getParameterContextId());
|
||||
|
||||
Assert.assertEquals("b.child", effectiveParameters.get(child).getValue());
|
||||
Assert.assertEquals("b", effectiveParameters.get(child).getParameterContextId());
|
||||
|
||||
Assert.assertEquals("c.secondChild", effectiveParameters.get(secondChild).getValue());
|
||||
Assert.assertEquals("c", effectiveParameters.get(secondChild).getParameterContextId());
|
||||
|
||||
Assert.assertEquals("d.grandchild", effectiveParameters.get(grandchild).getValue());
|
||||
Assert.assertEquals("d", effectiveParameters.get(grandchild).getParameterContextId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasEffectiveValueIfRemoved() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
// Set up a hierarchy as follows:
|
||||
// a (foo, bar, baz)
|
||||
// |
|
||||
// b (foo, child)
|
||||
// |
|
||||
// c (bar, grandchild)
|
||||
//
|
||||
// foo is in a/b; bar is in a/c; baz is only in a
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterDescriptor foo = addParameter(a, "foo", "a.foo");
|
||||
final ParameterDescriptor bar = addParameter(a, "bar", "a.bar");
|
||||
final ParameterDescriptor baz = addParameter(a, "baz", "a.baz");
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
addParameter(b,"foo", "b.foo");
|
||||
final ParameterDescriptor child = addParameter(b, "child", "b.child");
|
||||
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
addParameter(c, "bar", "c.foo");
|
||||
addParameter(c, "grandchild", "c.child");
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
b.setInheritedParameterContexts(Arrays.asList(c));
|
||||
|
||||
assertTrue(a.hasEffectiveValueIfRemoved(foo));
|
||||
assertTrue(a.hasEffectiveValueIfRemoved(bar));
|
||||
assertFalse(a.hasEffectiveValueIfRemoved(baz));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetEffectiveParameters_duplicateOverride() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
// Set up a hierarchy as follows:
|
||||
// a
|
||||
// / |
|
||||
// c b
|
||||
// |
|
||||
// d
|
||||
// |
|
||||
// c
|
||||
//
|
||||
// Parameter priority should be: a, c, b, d
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
final ParameterDescriptor child = addParameter(b, "child", "b.child"); // Overridden by c.child since c comes first in the list
|
||||
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
addParameter(c, "child", "c.child");
|
||||
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup);
|
||||
addParameter(d, "child", "d.child"); // Overridden by c.foo since c precedes d's ancestor b
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(c, b));
|
||||
b.setInheritedParameterContexts(Arrays.asList(d));
|
||||
d.setInheritedParameterContexts(Arrays.asList(c));
|
||||
|
||||
final Map<ParameterDescriptor, Parameter> effectiveParameters = a.getEffectiveParameters();
|
||||
|
||||
Assert.assertEquals(1, effectiveParameters.size());
|
||||
|
||||
Assert.assertEquals("c.child", effectiveParameters.get(child).getValue());
|
||||
Assert.assertEquals("c", effectiveParameters.get(child).getParameterContextId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterContexts_noParameterConflict() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
addParameter(a, "foo", "a.foo", true);
|
||||
addParameter(a, "bar", "a.bar", false);
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
addParameter(b,"foo", "b.foo", true); // Sensitivity matches, no conflict
|
||||
addParameter(b, "child", "b.child", false);
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
Assert.assertEquals(Arrays.asList(b), a.getInheritedParameterContexts());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritsFrom() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
final ParameterContext c = createParameterContext("c", parameterContextLookup);
|
||||
final ParameterContext d = createParameterContext("d", parameterContextLookup);
|
||||
final ParameterContext e = createParameterContext("e", parameterContextLookup);
|
||||
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
b.setInheritedParameterContexts(Arrays.asList(c, d));
|
||||
d.setInheritedParameterContexts(Arrays.asList(e));
|
||||
|
||||
Assert.assertTrue(a.inheritsFrom("b"));
|
||||
Assert.assertTrue(a.inheritsFrom("c"));
|
||||
Assert.assertTrue(a.inheritsFrom("d"));
|
||||
Assert.assertTrue(a.inheritsFrom("e"));
|
||||
Assert.assertFalse(a.inheritsFrom("a"));
|
||||
|
||||
Assert.assertTrue(b.inheritsFrom("e"));
|
||||
Assert.assertFalse(b.inheritsFrom("a"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterContexts_parameterSensitivityConflict() {
|
||||
final StandardParameterContextManager parameterContextLookup = new StandardParameterContextManager();
|
||||
|
||||
final ParameterContext a = createParameterContext("a", parameterContextLookup);
|
||||
addParameter(a, "foo", "a.foo", true);
|
||||
addParameter(a, "bar", "a.bar", false);
|
||||
|
||||
final ParameterContext b = createParameterContext("b", parameterContextLookup);
|
||||
addParameter(b,"foo", "b.foo", false); // Sensitivity does not match!
|
||||
addParameter(b, "child", "b.child", false);
|
||||
|
||||
try {
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
Assert.fail("Should get a failure for sensitivity mismatch in overriding");
|
||||
} catch (IllegalStateException e) {
|
||||
Assert.assertTrue(e.getMessage().contains("foo"));
|
||||
}
|
||||
Assert.assertEquals(Collections.emptyList(), a.getInheritedParameterContexts());
|
||||
|
||||
// Now switch and set a.foo to non-sensitive and b.foo to sensitive
|
||||
removeParameter(a, "foo");
|
||||
addParameter(a, "foo", "a.foo", false);
|
||||
|
||||
removeParameter(b, "foo");
|
||||
addParameter(b, "foo", "a.foo", true);
|
||||
|
||||
try {
|
||||
a.setInheritedParameterContexts(Arrays.asList(b));
|
||||
Assert.fail("Should get a failure for sensitivity mismatch in overriding");
|
||||
} catch (IllegalStateException e) {
|
||||
Assert.assertTrue(e.getMessage().contains("foo"));
|
||||
}
|
||||
Assert.assertEquals(Collections.emptyList(), a.getInheritedParameterContexts());
|
||||
}
|
||||
|
||||
private static void removeParameter(final ParameterContext parameterContext, final String name) {
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
for(final Map.Entry<ParameterDescriptor, Parameter> entry : parameterContext.getParameters().entrySet()) {
|
||||
if (entry.getKey().getName().equals(name)) {
|
||||
parameters.put(name, null);
|
||||
} else {
|
||||
parameters.put(entry.getKey().getName(), entry.getValue());
|
||||
}
|
||||
}
|
||||
parameterContext.setParameters(parameters);
|
||||
}
|
||||
|
||||
private static ParameterDescriptor addParameter(final ParameterContext parameterContext, final String name, final String value) {
|
||||
return addParameter(parameterContext, name, value, false);
|
||||
}
|
||||
|
||||
private static ParameterDescriptor addParameter(final ParameterContext parameterContext, final String name, final String value, final boolean isSensitive) {
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
for(final Map.Entry<ParameterDescriptor, Parameter> entry : parameterContext.getParameters().entrySet()) {
|
||||
parameters.put(entry.getKey().getName(), entry.getValue());
|
||||
}
|
||||
final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder().name(name).sensitive(isSensitive).build();
|
||||
parameters.put(name, new Parameter(parameterDescriptor, value));
|
||||
parameterContext.setParameters(parameters);
|
||||
return parameterDescriptor;
|
||||
}
|
||||
|
||||
private static ParameterContext createParameterContext(final String id, final ParameterContextManager parameterContextLookup,
|
||||
final ParameterContext... children) {
|
||||
return createParameterContext(id, parameterContextLookup, ParameterReferenceManager.EMPTY, children);
|
||||
}
|
||||
|
||||
private static ParameterContext createParameterContext(final String id, final ParameterContextManager parameterContextLookup,
|
||||
final ParameterReferenceManager referenceManager, final ParameterContext... children) {
|
||||
final ParameterContext parameterContext = new StandardParameterContext(id, id.toUpperCase(), referenceManager, null );
|
||||
parameterContext.setInheritedParameterContexts(Arrays.asList(children));
|
||||
|
||||
parameterContextLookup.addParameterContext(parameterContext);
|
||||
return parameterContext;
|
||||
}
|
||||
|
||||
private static class HashMapParameterReferenceManager implements ParameterReferenceManager {
|
||||
private final Map<String, ProcessorNode> processors = new HashMap<>();
|
||||
|
@ -33,9 +33,11 @@ import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterContextManager;
|
||||
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -323,7 +325,41 @@ public interface FlowManager {
|
||||
|
||||
void removeRootControllerService(final ControllerServiceNode service);
|
||||
|
||||
ParameterContext createParameterContext(String id, String name, Map<String, Parameter> parameters);
|
||||
/**
|
||||
* Creates a <code>ParameterContext</code>. Note that in order to safely create a <code>ParameterContext</code> that includes
|
||||
* inherited <code>ParameterContext</code>s, the action must be performed using {@link FlowManager#withParameterContextResolution(Runnable)},
|
||||
* which ensures that all inherited <code>ParameterContext</code>s are resolved. If <code>parameterContexts</code> is
|
||||
* not empty and this method is called outside of {@link FlowManager#withParameterContextResolution(Runnable)},
|
||||
* <code>IllegalStateException</code> is thrown. See {@link FlowManager#withParameterContextResolution(Runnable)}
|
||||
* for example usage.
|
||||
*
|
||||
* @param id The unique id
|
||||
* @param name The ParameterContext name
|
||||
* @param parameters The Parameters
|
||||
* @param parameterContexts Optional inherited ParameterContexts
|
||||
* @return The created ParameterContext
|
||||
* @throws IllegalStateException If <code>parameterContexts</code> is not empty and this method is called without being wrapped
|
||||
* by {@link FlowManager#withParameterContextResolution(Runnable)}
|
||||
*/
|
||||
ParameterContext createParameterContext(String id, String name, Map<String, Parameter> parameters, List<ParameterContextReferenceEntity> parameterContexts);
|
||||
|
||||
/**
|
||||
* Performs the given ParameterContext-related action, and then resolves all inherited ParameterContext references.
|
||||
* Example usage: <br/><br/>
|
||||
* <pre>
|
||||
* // This ensures that regardless of the order of parameter contexts created in the loop,
|
||||
* // all inherited parameter contexts will be resolved if possible. If not possible, IllegalStateException is thrown.
|
||||
* flowManager.withParameterContextResolution(() -> {
|
||||
* for (final ParameterContextDTO dto : parameterContextDtos) {
|
||||
* flowManager.createParameterContext(dto.getId(), dto.getName(), parameters, dto.getInheritedParameterContexts());
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* @param parameterContextAction A runnable action, usually involving creating a ParameterContext, that requires
|
||||
* parameter context references to be resolved after it is performed
|
||||
* @throws IllegalStateException if an invalid parameter context reference was detected
|
||||
*/
|
||||
void withParameterContextResolution(Runnable parameterContextAction);
|
||||
|
||||
ParameterContextManager getParameterContextManager();
|
||||
|
||||
|
@ -1175,6 +1175,13 @@ public interface ProcessGroup extends ComponentAuthorizable, Positionable, Versi
|
||||
*/
|
||||
DataValve getDataValve();
|
||||
|
||||
/**
|
||||
* @param parameterContext A ParameterContext
|
||||
* @return True if the provided ParameterContext is referenced by this Process Group, either directly or
|
||||
* indirectly through inherited ParameterContexts.
|
||||
*/
|
||||
boolean referencesParameterContext(ParameterContext parameterContext);
|
||||
|
||||
/**
|
||||
* @return the default flowfile expiration of the ProcessGroup
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@ package org.apache.nifi.parameter;
|
||||
|
||||
import org.apache.nifi.authorization.resource.ComponentAuthorizable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -68,9 +69,9 @@ public interface ParameterContext extends ParameterLookup, ComponentAuthorizable
|
||||
*/
|
||||
void verifyCanSetParameters(Map<String, Parameter> parameters);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Parameter with the given descriptor
|
||||
* Returns the Parameter with the given descriptor, considering this and all inherited
|
||||
* ParameterContexts.
|
||||
*
|
||||
* @param parameterDescriptor descriptor for the parameter
|
||||
* @return the Parameter with the given name, or <code>null</code> if no parameter exists with the given descriptor
|
||||
@ -78,18 +79,77 @@ public interface ParameterContext extends ParameterLookup, ComponentAuthorizable
|
||||
Optional<Parameter> getParameter(ParameterDescriptor parameterDescriptor);
|
||||
|
||||
/**
|
||||
* Returns the Map of all Parameters in this context. Note that the Map that is returned may either be immutable or may be a defensive copy but
|
||||
* modifying the Map that is returned will have no effect on the contents of this Parameter Context.
|
||||
* Checks whether this ParameterContext would still have an effective value for the given parameter if the
|
||||
* parameter was removed from this or any inherited parameter context, no matter how indirect. This allows
|
||||
* the ParameterContext to be checked for validity: if it will still have an effective value, the parameter
|
||||
* can be safely removed.
|
||||
*
|
||||
* @param parameterDescriptor parameter descriptor to check
|
||||
* @return True if, when the parameter is removed, this ParameterContext would still have an effective value
|
||||
* for the parameter.
|
||||
*/
|
||||
boolean hasEffectiveValueIfRemoved(ParameterDescriptor parameterDescriptor);
|
||||
|
||||
/**
|
||||
* Returns the Map of all Parameters in this context (not in any inherited ParameterContexts). Note that the Map that
|
||||
* is returned may either be immutable or may be a defensive copy but modifying the Map that is returned will have
|
||||
* no effect on the contents of this Parameter Context.
|
||||
*
|
||||
* @return a Map that contains all Parameters in the context keyed by their descriptors
|
||||
*/
|
||||
Map<ParameterDescriptor, Parameter> getParameters();
|
||||
|
||||
/**
|
||||
* Returns the Map of all Parameters in this context, as well as in all inherited ParameterContexts. Any duplicate
|
||||
* parameters will be overridden as described in {@link #setInheritedParameterContexts(List) setParameterContexts}.
|
||||
* Note that the Map that is returned may either be immutable or may be a defensive copy but
|
||||
* modifying the Map that is returned will have no effect on the contents of this Parameter Context or any other.
|
||||
*
|
||||
* @return a Map that contains all Parameters in the context and all nested ParameterContexts, keyed by their descriptors
|
||||
*/
|
||||
Map<ParameterDescriptor, Parameter> getEffectiveParameters();
|
||||
|
||||
/**
|
||||
* Returns the ParameterReferenceManager that is associated with this ParameterContext
|
||||
* @return the ParameterReferenceManager that is associated with this ParameterContext
|
||||
*/
|
||||
ParameterReferenceManager getParameterReferenceManager();
|
||||
|
||||
/**
|
||||
* Updates the ParameterContexts within this context to match the given list of ParameterContexts. All parameter in these
|
||||
* ParameterContexts are inherited by this ParameterContext, and can be referenced as if they were actually in this ParameterContext.
|
||||
* The order of the list specifies the priority of parameter overriding, where parameters in the first ParameterContext in the list have
|
||||
* top priority. However, all parameters in this ParameterContext take precedence over any in its list of inherited ParameterContexts.
|
||||
* Note that this method should only update the ordering of the ParameterContexts, it cannot be used to modify the
|
||||
* contents of the ParameterContexts in the list.
|
||||
*
|
||||
* @param inheritedParameterContexts the list of ParameterContexts from which to inherit parameters, in priority order first to last
|
||||
* @throws IllegalStateException if the list of ParameterContexts is invalid (in case of a circular reference or
|
||||
* in case {@link #verifyCanSetParameters(Map)} verifyCanSetParameters} would throw an exception)
|
||||
*/
|
||||
void setInheritedParameterContexts(List<ParameterContext> inheritedParameterContexts);
|
||||
|
||||
/**
|
||||
* Returns a list of ParameterContexts from which this ParameterContext inherits parameters.
|
||||
* See {@link #setInheritedParameterContexts(List) setParameterContexts} for further information. Note that the List that is returned may
|
||||
* either be immutable or may be a defensive copy but modifying the list will not update the ParameterContexts inherited by this one.
|
||||
* @return An ordered list of ParameterContexts from which this one inherits parameters
|
||||
*/
|
||||
List<ParameterContext> getInheritedParameterContexts();
|
||||
|
||||
/**
|
||||
* Returns a list of names of ParameterContexts from which this ParameterContext inherits parameters.
|
||||
* See {@link #setInheritedParameterContexts(List) setParameterContexts} for further information. Note that the List that is returned may
|
||||
* either be immutable or may be a defensive copy but modifying the list will not update the ParameterContexts inherited by this one.
|
||||
* @return An ordered list of ParameterContext names from which this one inherits parameters
|
||||
*/
|
||||
List<String> getInheritedParameterContextNames();
|
||||
|
||||
/**
|
||||
* Returns true if this ParameterContext inherits from the given parameter context, either
|
||||
* directly or indirectly.
|
||||
* @param parameterContextId The ID of the sought parameter context
|
||||
* @return True if this inherits from the given ParameterContext
|
||||
*/
|
||||
boolean inheritsFrom(String parameterContextId);
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.parameter;
|
||||
|
||||
public interface ParameterContextLookup {
|
||||
|
||||
/**
|
||||
* Returns true if the lookup has the given parameter context.
|
||||
*
|
||||
* @param id the id of the parameter context
|
||||
* @return true if the context has been found
|
||||
*/
|
||||
boolean hasParameterContext(String id);
|
||||
|
||||
/**
|
||||
* Gets the specified parameter context.
|
||||
*
|
||||
* @param id the id of the parameter context
|
||||
* @return the parameter context
|
||||
*/
|
||||
ParameterContext getParameterContext(String id);
|
||||
|
||||
ParameterContextLookup EMPTY = new ParameterContextLookup() {
|
||||
@Override
|
||||
public boolean hasParameterContext(String id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterContext getParameterContext(final String id) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
@ -16,14 +16,16 @@
|
||||
*/
|
||||
package org.apache.nifi.parameter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ParameterContextManager {
|
||||
ParameterContext getParameterContext(String id);
|
||||
public interface ParameterContextManager extends ParameterContextLookup {
|
||||
|
||||
void addParameterContext(ParameterContext parameterContext);
|
||||
|
||||
ParameterContext removeParameterContext(String parameterContextId);
|
||||
|
||||
Set<ParameterContext> getParameterContexts();
|
||||
|
||||
Map<String, ParameterContext> getParameterContextNameMapping();
|
||||
}
|
||||
|
@ -418,15 +418,16 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
|
||||
client.addFlowRegistry(registryId, registryName, registryUrl, description);
|
||||
}
|
||||
}
|
||||
|
||||
final Element parameterContextsElement = DomUtils.getChild(rootElement, "parameterContexts");
|
||||
if (parameterContextsElement != null) {
|
||||
final List<Element> contextElements = DomUtils.getChildElementsByTagName(parameterContextsElement, "parameterContext");
|
||||
for (final Element contextElement : contextElements) {
|
||||
final ParameterContextDTO parameterContextDto = FlowFromDOMFactory.getParameterContext(contextElement, encryptor);
|
||||
createParameterContext(parameterContextDto, controller.getFlowManager());
|
||||
controller.getFlowManager().withParameterContextResolution(() -> {
|
||||
final Element parameterContextsElement = DomUtils.getChild(rootElement, "parameterContexts");
|
||||
if (parameterContextsElement != null) {
|
||||
final List<Element> contextElements = DomUtils.getChildElementsByTagName(parameterContextsElement, "parameterContext");
|
||||
for (final Element contextElement : contextElements) {
|
||||
final ParameterContextDTO parameterContextDto = FlowFromDOMFactory.getParameterContext(contextElement, encryptor);
|
||||
createParameterContext(parameterContextDto, controller.getFlowManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
logger.trace("Adding root process group");
|
||||
rootGroup = addProcessGroup(controller, /* parent group */ null, rootGroupElement, encryptor, encodingVersion);
|
||||
@ -529,7 +530,7 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
|
||||
.map(this::createParameter)
|
||||
.collect(Collectors.toMap(param -> param.getDescriptor().getName(), Function.identity()));
|
||||
|
||||
final ParameterContext context = flowManager.createParameterContext(dto.getId(), dto.getName(), parameters);
|
||||
final ParameterContext context = flowManager.createParameterContext(dto.getId(), dto.getName(), parameters, dto.getInheritedParameterContexts());
|
||||
context.setDescription(dto.getDescription());
|
||||
return context;
|
||||
}
|
||||
|
@ -168,6 +168,14 @@ public class FlowFromDOMFactory {
|
||||
parameterEntity.setParameter(parameterDto);
|
||||
parameterDtos.add(parameterEntity);
|
||||
}
|
||||
final List<Element> inheritedParameterContextIds = FlowFromDOMFactory.getChildrenByTagName(element, "inheritedParameterContextId");
|
||||
final List<ParameterContextReferenceEntity> parameterContexts = new ArrayList<>();
|
||||
for (final Element inheritedParameterContextElement : inheritedParameterContextIds) {
|
||||
final ParameterContextReferenceEntity parameterContextReference = new ParameterContextReferenceEntity();
|
||||
parameterContextReference.setId(inheritedParameterContextElement.getTextContent());
|
||||
parameterContexts.add(parameterContextReference);
|
||||
}
|
||||
dto.setInheritedParameterContexts(parameterContexts);
|
||||
|
||||
dto.setParameters(parameterDtos);
|
||||
|
||||
|
@ -161,6 +161,10 @@ public class StandardFlowSerializer implements FlowSerializer<Document> {
|
||||
addStringElement(parameterContextElement, "name", parameterContext.getName());
|
||||
addStringElement(parameterContextElement, "description", parameterContext.getDescription());
|
||||
|
||||
for(final ParameterContext childContext : parameterContext.getInheritedParameterContexts()) {
|
||||
addStringElement(parameterContextElement, "inheritedParameterContextId", childContext.getIdentifier());
|
||||
}
|
||||
|
||||
for (final Parameter parameter : parameterContext.getParameters().values()) {
|
||||
addParameter(parameterContextElement, parameter);
|
||||
}
|
||||
|
@ -312,6 +312,15 @@ public class FingerprintFactory {
|
||||
}
|
||||
}
|
||||
|
||||
final List<Element> inheritedParameterContexts = DomUtils.getChildElementsByTagName(parameterContextElement, "inheritedParameterContextId");
|
||||
if (inheritedParameterContexts == null || inheritedParameterContexts.isEmpty()) {
|
||||
builder.append("NO_INHERITED_PARAMETER_CONTEXT_IDS");
|
||||
} else {
|
||||
for (final Element inheritedParameterContextId : inheritedParameterContexts) {
|
||||
builder.append(inheritedParameterContextId.getTextContent());
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,7 @@
|
||||
<xs:element name="id" type="NonEmptyStringType" />
|
||||
<xs:element name="name" type="NonEmptyStringType" />
|
||||
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="inheritedParameterContextId" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="parameter" type="ParameterType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
@ -36,6 +36,7 @@ import org.apache.nifi.controller.flow.FlowManager;
|
||||
import org.apache.nifi.controller.reporting.ReportingTaskInstantiationException;
|
||||
import org.apache.nifi.controller.repository.FlowFileEventRepository;
|
||||
import org.apache.nifi.controller.scheduling.StandardProcessScheduler;
|
||||
import org.apache.nifi.controller.serialization.FlowSynchronizationException;
|
||||
import org.apache.nifi.controller.serialization.FlowSynchronizer;
|
||||
import org.apache.nifi.controller.service.ControllerServiceNode;
|
||||
import org.apache.nifi.controller.service.ControllerServiceProvider;
|
||||
@ -53,6 +54,9 @@ import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
||||
import org.apache.nifi.nar.InstanceClassLoader;
|
||||
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
||||
import org.apache.nifi.nar.SystemBundle;
|
||||
import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterDescriptor;
|
||||
import org.apache.nifi.processor.Relationship;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
@ -66,9 +70,11 @@ import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.web.api.dto.BundleDTO;
|
||||
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
|
||||
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.PositionDTO;
|
||||
import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
|
||||
import org.apache.nifi.web.api.dto.ProcessorDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
@ -101,6 +107,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -327,6 +334,91 @@ public class TestFlowController {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = FlowSynchronizationException.class)
|
||||
public void testSynchronizeFlowWithInvalidParameterContextReference() throws IOException {
|
||||
final FlowSynchronizer standardFlowSynchronizer = new StandardFlowSynchronizer(
|
||||
PropertyEncryptorFactory.getPropertyEncryptor(nifiProperties), nifiProperties, extensionManager);
|
||||
|
||||
final File flowFile = new File("src/test/resources/conf/parameter-context-flow-error.xml");
|
||||
final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
|
||||
|
||||
final String authFingerprint = "<authorizations></authorizations>";
|
||||
final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
|
||||
|
||||
try {
|
||||
controller.synchronize(standardFlowSynchronizer, proposedDataFlow, Mockito.mock(FlowService.class));
|
||||
controller.initializeFlow();
|
||||
} finally {
|
||||
purgeFlow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronizeFlowWithNestedParameterContexts() throws IOException {
|
||||
final FlowSynchronizer standardFlowSynchronizer = new StandardFlowSynchronizer(
|
||||
PropertyEncryptorFactory.getPropertyEncryptor(nifiProperties), nifiProperties, extensionManager);
|
||||
|
||||
final File flowFile = new File("src/test/resources/conf/parameter-context-flow.xml");
|
||||
final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
|
||||
|
||||
final String authFingerprint = "<authorizations></authorizations>";
|
||||
final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
|
||||
|
||||
try {
|
||||
controller.synchronize(standardFlowSynchronizer, proposedDataFlow, Mockito.mock(FlowService.class));
|
||||
controller.initializeFlow();
|
||||
|
||||
ParameterContext parameterContext = controller.getFlowManager().getParameterContextManager().getParameterContext("context");
|
||||
Assert.assertNotNull(parameterContext);
|
||||
Assert.assertEquals(2, parameterContext.getInheritedParameterContexts().size());
|
||||
Assert.assertEquals("referenced-context", parameterContext.getInheritedParameterContexts().get(0).getIdentifier());
|
||||
Assert.assertEquals("referenced-context-2", parameterContext.getInheritedParameterContexts().get(1).getIdentifier());
|
||||
} finally {
|
||||
purgeFlow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateParameterContextWithAndWithoutValidation() throws IOException {
|
||||
final FlowSynchronizer standardFlowSynchronizer = new StandardFlowSynchronizer(
|
||||
PropertyEncryptorFactory.getPropertyEncryptor(nifiProperties), nifiProperties, extensionManager);
|
||||
|
||||
final File flowFile = new File("src/test/resources/conf/parameter-context-flow.xml");
|
||||
final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
|
||||
|
||||
final String authFingerprint = "<authorizations></authorizations>";
|
||||
final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
|
||||
|
||||
try {
|
||||
controller.synchronize(standardFlowSynchronizer, proposedDataFlow, Mockito.mock(FlowService.class));
|
||||
controller.initializeFlow();
|
||||
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
parameters.put("param", new Parameter(new ParameterDescriptor.Builder().name("param").build(), "value"));
|
||||
|
||||
// No problem since there are no inherited parameter contexts
|
||||
controller.getFlowManager().createParameterContext("id", "name", parameters, Collections.emptyList());
|
||||
|
||||
final ParameterContext existingParameterContext = controller.getFlowManager().getParameterContextManager().getParameterContext("context");
|
||||
final ParameterContextReferenceEntity ref = new ParameterContextReferenceEntity();
|
||||
ref.setId(existingParameterContext.getIdentifier());
|
||||
final ParameterContextReferenceDTO dto = new ParameterContextReferenceDTO();
|
||||
dto.setId(existingParameterContext.getIdentifier());
|
||||
dto.setName(existingParameterContext.getName());
|
||||
|
||||
// This is not wrapped in FlowManager#withParameterContextResolution(Runnable), so it will throw an exception
|
||||
assertThrows(IllegalStateException.class, () ->
|
||||
controller.getFlowManager().createParameterContext("id", "name", parameters, Collections.singletonList(ref)));
|
||||
|
||||
// Instead, this is how it should be called
|
||||
controller.getFlowManager().withParameterContextResolution(() -> controller
|
||||
.getFlowManager().createParameterContext("id2", "name2", parameters, Collections.singletonList(ref)));
|
||||
|
||||
} finally {
|
||||
purgeFlow();
|
||||
}
|
||||
}
|
||||
|
||||
private void purgeFlow() {
|
||||
final ProcessGroup processGroup = controller.getFlowManager().getRootGroup();
|
||||
for (final ProcessorNode procNode : processGroup.getProcessors()) {
|
||||
|
@ -30,6 +30,11 @@ import org.apache.nifi.encrypt.PropertyEncryptorFactory;
|
||||
import org.apache.nifi.nar.ExtensionDiscoveringManager;
|
||||
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
|
||||
import org.apache.nifi.nar.SystemBundle;
|
||||
import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterDescriptor;
|
||||
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||
import org.apache.nifi.parameter.StandardParameterContext;
|
||||
import org.apache.nifi.provenance.MockProvenanceRepository;
|
||||
import org.apache.nifi.registry.VariableRegistry;
|
||||
import org.apache.nifi.registry.flow.FlowRegistryClient;
|
||||
@ -45,6 +50,7 @@ import org.w3c.dom.Document;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -113,7 +119,22 @@ public class StandardFlowSerializerTest {
|
||||
dummy.setComments(RAW_COMMENTS);
|
||||
controller.getFlowManager().getRootGroup().addProcessor(dummy);
|
||||
|
||||
final ParameterContext parameterContext = new StandardParameterContext("context", "Context", ParameterReferenceManager.EMPTY, null);
|
||||
final ParameterContext referencedContext = new StandardParameterContext("referenced-context", "Referenced Context", ParameterReferenceManager.EMPTY, null);
|
||||
final ParameterContext referencedContext2 = new StandardParameterContext("referenced-context-2", "Referenced Context 2", ParameterReferenceManager.EMPTY, null);
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder().name("foo").sensitive(true).build();
|
||||
parameters.put("foo", new Parameter(parameterDescriptor, "value"));
|
||||
parameterContext.setInheritedParameterContexts(Arrays.asList(referencedContext, referencedContext2));
|
||||
parameterContext.setParameters(parameters);
|
||||
|
||||
controller.getFlowManager().getParameterContextManager().addParameterContext(parameterContext);
|
||||
controller.getFlowManager().getParameterContextManager().addParameterContext(referencedContext);
|
||||
controller.getFlowManager().getParameterContextManager().addParameterContext(referencedContext2);
|
||||
|
||||
controller.getFlowManager().getRootGroup().setParameterContext(parameterContext);
|
||||
controller.getFlowManager().getRootGroup().setVariables(Collections.singletonMap(RAW_VARIABLE_NAME, RAW_VARIABLE_VALUE));
|
||||
controller.getFlowManager().getRootGroup().setParameterContext(parameterContext);
|
||||
|
||||
// serialize the controller
|
||||
final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
@ -129,6 +150,7 @@ public class StandardFlowSerializerTest {
|
||||
assertTrue(serializedFlow.contains(SERIALIZED_VARIABLE_VALUE));
|
||||
assertFalse(serializedFlow.contains(RAW_VARIABLE_VALUE));
|
||||
assertFalse(serializedFlow.contains("\u0001"));
|
||||
assertTrue(serializedFlow.contains("<inheritedParameterContextId>referenced-context</inheritedParameterContextId>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -812,6 +812,11 @@ public class MockProcessGroup implements ProcessGroup {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referencesParameterContext(final ParameterContext parameterContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultFlowFileExpiration() {
|
||||
return defaultFlowfileExpiration;
|
||||
|
@ -94,6 +94,23 @@ public class FingerprintFactoryTest {
|
||||
assertNotEquals(fp1, fp2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritedParameterContextsInFingerprint() throws IOException {
|
||||
final String flowWithParameterContext = new String(getResourceBytes("/nifi/fingerprint/flow-with-parameter-context.xml"));
|
||||
final String flowWithNoInheritedParameterContexts = flowWithParameterContext.replaceAll("<inheritedParameterContextId>.*?</inheritedParameterContextId>", "");
|
||||
final String flowWithDifferentInheritedParamContextOrder = flowWithParameterContext
|
||||
.replaceFirst("153a6266-dcd0-33e9-b5af-b8c282d25bf1", "SWAP")
|
||||
.replaceFirst("253a6266-dcd0-33e9-b5af-b8c282d25bf2", "153a6266-dcd0-33e9-b5af-b8c282d25bf1")
|
||||
.replaceFirst("SWAP", "253a6266-dcd0-33e9-b5af-b8c282d25bf2");
|
||||
|
||||
final String originalFingerprint = fingerprintFactory.createFingerprint(flowWithParameterContext.getBytes(StandardCharsets.UTF_8), null);
|
||||
final String fingerprintWithNoInheritedParameterContexts = fingerprintFactory.createFingerprint(flowWithNoInheritedParameterContexts.getBytes(StandardCharsets.UTF_8), null);
|
||||
final String fingerprintWithDifferentInheritedParamContextOrder = fingerprintFactory.createFingerprint(flowWithDifferentInheritedParamContextOrder.getBytes(StandardCharsets.UTF_8), null);
|
||||
|
||||
assertNotEquals(originalFingerprint, fingerprintWithNoInheritedParameterContexts);
|
||||
assertNotEquals(originalFingerprint, fingerprintWithDifferentInheritedParamContextOrder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceValueInFingerprint() throws IOException {
|
||||
final String fingerprint = fingerprintFactory.createFingerprint(getResourceBytes("/nifi/fingerprint/flow1a.xml"), null);
|
||||
|
@ -41,6 +41,7 @@ import org.apache.nifi.processor.StandardProcessContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -48,6 +49,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@ -78,6 +80,61 @@ public class ParametersIT extends FrameworkIntegrationTest {
|
||||
assertEquals("unit", flowFileRecord.getAttribute("test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedParamSubstitution_configProcessorFirst() throws ExecutionException, InterruptedException {
|
||||
runParameterSubstitutionInNestedParameterContextTest((updateAttribute, parameterContext) -> {
|
||||
updateAttribute.setProperties(Collections.singletonMap("test", "#{test}"));
|
||||
getRootGroup().setParameterContext(parameterContext);
|
||||
}, "unit");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedParamSubstitution_configProcessorLast() throws ExecutionException, InterruptedException {
|
||||
runParameterSubstitutionInNestedParameterContextTest((updateAttribute, parameterContext) -> {
|
||||
getRootGroup().setParameterContext(parameterContext);
|
||||
updateAttribute.setProperties(Collections.singletonMap("test", "#{test}"));
|
||||
}, "unit");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedParamSubstitution_updateParamContext() throws ExecutionException, InterruptedException {
|
||||
runParameterSubstitutionInNestedParameterContextTest((updateAttribute, parameterContext) -> {
|
||||
getRootGroup().setParameterContext(parameterContext);
|
||||
updateAttribute.setProperties(Collections.singletonMap("test", "#{test}"));
|
||||
parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "bar")));
|
||||
|
||||
getRootGroup().setParameterContext(parameterContext);
|
||||
}, "bar");
|
||||
}
|
||||
|
||||
public void runParameterSubstitutionInNestedParameterContextTest(BiConsumer<ProcessorNode, ParameterContext> testConsumer, String expectedValue) throws ExecutionException, InterruptedException {
|
||||
final ProcessorNode generate = createProcessorNode(GenerateProcessor.class);
|
||||
final ProcessorNode updateAttribute = createProcessorNode(UpdateAttributeNoEL.class);
|
||||
final ProcessorNode terminate = getTerminateProcessor();
|
||||
|
||||
final Connection generatedFlowFileConnection = connect(generate, updateAttribute, REL_SUCCESS);
|
||||
final Connection updatedAttributeConnection = connect(updateAttribute, terminate, REL_SUCCESS);
|
||||
|
||||
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
|
||||
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
|
||||
parameterContext.setParameters(Collections.singletonMap("foo", new Parameter(new ParameterDescriptor.Builder().name("foo").build(), "bar")));
|
||||
|
||||
final ParameterContext referencedParameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context-2", referenceManager, null);
|
||||
referencedParameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
|
||||
|
||||
parameterContext.setInheritedParameterContexts(Arrays.asList(referencedParameterContext));
|
||||
|
||||
testConsumer.accept(updateAttribute, parameterContext);
|
||||
|
||||
triggerOnce(generate);
|
||||
triggerOnce(updateAttribute);
|
||||
|
||||
final FlowFileQueue flowFileQueue = updatedAttributeConnection.getFlowFileQueue();
|
||||
final FlowFileRecord flowFileRecord = flowFileQueue.poll(Collections.emptySet());
|
||||
|
||||
assertEquals(expectedValue, flowFileRecord.getAttribute("test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterSubstitutionWithinELWhenELNotSupported() throws ExecutionException, InterruptedException {
|
||||
final ProcessorNode generate = createProcessorNode(GenerateProcessor.class);
|
||||
@ -128,6 +185,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
|
||||
assertEquals("UNIT", flowFileRecord.getAttribute("test"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMixAndMatchELAndParameters() throws ExecutionException, InterruptedException {
|
||||
final ProcessorNode generate = createProcessorNode(GenerateProcessor.class);
|
||||
|
@ -80,6 +80,7 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@ -139,6 +140,8 @@ public class NiFiRegistryFlowMapperTest {
|
||||
|
||||
// verify single parameter context
|
||||
assertEquals(1, versionedParameterContexts.size());
|
||||
assertEquals(1, versionedParameterContexts.get("context10").getInheritedParameterContexts().size());
|
||||
assertEquals("other-context", versionedParameterContexts.get("context10").getInheritedParameterContexts().get(0));
|
||||
|
||||
final String expectedName = innerProcessGroup.getParameterContext().getName();
|
||||
verifyParameterContext(innerProcessGroup.getParameterContext(), versionedParameterContexts.get(expectedName));
|
||||
@ -261,6 +264,7 @@ public class NiFiRegistryFlowMapperTest {
|
||||
when(parameterContext.getName()).thenReturn("context" + (counter++));
|
||||
final Map<ParameterDescriptor, Parameter> parametersMap = Maps.newHashMap();
|
||||
when(parameterContext.getParameters()).thenReturn(parametersMap);
|
||||
when(parameterContext.getInheritedParameterContextNames()).thenReturn(Arrays.asList("other-context"));
|
||||
|
||||
addParameter(parametersMap, "value" + (counter++), false);
|
||||
addParameter(parametersMap, "value" + (counter++), true);
|
||||
|
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<flowController encoding-version="1.4">
|
||||
<maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
|
||||
<maxEventDrivenThreadCount>1</maxEventDrivenThreadCount>
|
||||
<registries/>
|
||||
<parameterContexts>
|
||||
<parameterContext>
|
||||
<id>context</id>
|
||||
<name>Context</name>
|
||||
<description/>
|
||||
<inheritedParameterContextId>referenced-context</inheritedParameterContextId>
|
||||
<inheritedParameterContextId>referenced-context-2</inheritedParameterContextId>
|
||||
<parameter>
|
||||
<name>foo</name>
|
||||
<description/>
|
||||
<sensitive>true</sensitive>
|
||||
<value>enc{c5e2924eeec6d395ba09090cd50c5f2cee1ba23735d7eadfedae96d0b0fd257b}</value>
|
||||
</parameter>
|
||||
</parameterContext>
|
||||
<parameterContext>
|
||||
<id>referenced-context</id>
|
||||
<name>Referenced Context</name>
|
||||
<description/>
|
||||
</parameterContext>
|
||||
</parameterContexts>
|
||||
<rootGroup>
|
||||
<id>2ae3cdb4-0179-1000-6ddc-ed1dca231bac</id>
|
||||
<name>NiFi Flow</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<comment/>
|
||||
<flowfileConcurrency>UNBOUNDED</flowfileConcurrency>
|
||||
<flowfileOutboundPolicy>STREAM_WHEN_AVAILABLE</flowfileOutboundPolicy>
|
||||
<processor>
|
||||
<id>c40fc154-ef89-48b8-82bf-ff6cc9e8f591</id>
|
||||
<name>DummyScheduledProcessor</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<styles/>
|
||||
<comment><tagName> "This" is an ' example with many characters that need to be filtered and escaped in it.  † </comment>
|
||||
<class>org.apache.nifi.controller.DummyScheduledProcessor</class>
|
||||
<maxConcurrentTasks>5</maxConcurrentTasks>
|
||||
<schedulingPeriod>0 0 0 1/1 * ?</schedulingPeriod>
|
||||
<penalizationPeriod>30 sec</penalizationPeriod>
|
||||
<yieldPeriod>1 sec</yieldPeriod>
|
||||
<bulletinLevel>WARN</bulletinLevel>
|
||||
<lossTolerant>false</lossTolerant>
|
||||
<scheduledState>STOPPED</scheduledState>
|
||||
<schedulingStrategy>CRON_DRIVEN</schedulingStrategy>
|
||||
<executionNode>ALL</executionNode>
|
||||
<runDurationNanos>0</runDurationNanos>
|
||||
</processor>
|
||||
<variable name="Name with escape needed" value="Value with escape needed"/>
|
||||
<inheritedParameterContextId>context</inheritedParameterContextId>
|
||||
</rootGroup>
|
||||
<controllerServices/>
|
||||
<reportingTasks/>
|
||||
</flowController>
|
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<flowController encoding-version="1.4">
|
||||
<maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
|
||||
<maxEventDrivenThreadCount>1</maxEventDrivenThreadCount>
|
||||
<registries/>
|
||||
<parameterContexts>
|
||||
<parameterContext>
|
||||
<id>context</id>
|
||||
<name>Context</name>
|
||||
<description/>
|
||||
<inheritedParameterContextId>referenced-context</inheritedParameterContextId>
|
||||
<inheritedParameterContextId>referenced-context-2</inheritedParameterContextId>
|
||||
<parameter>
|
||||
<name>foo</name>
|
||||
<description/>
|
||||
<sensitive>true</sensitive>
|
||||
<value>enc{c5e2924eeec6d395ba09090cd50c5f2cee1ba23735d7eadfedae96d0b0fd257b}</value>
|
||||
</parameter>
|
||||
</parameterContext>
|
||||
<parameterContext>
|
||||
<id>referenced-context</id>
|
||||
<name>Referenced Context</name>
|
||||
<description/>
|
||||
</parameterContext>
|
||||
<parameterContext>
|
||||
<id>referenced-context-2</id>
|
||||
<name>Referenced Context 2</name>
|
||||
<description/>
|
||||
</parameterContext>
|
||||
</parameterContexts>
|
||||
<rootGroup>
|
||||
<id>2ae3cdb4-0179-1000-6ddc-ed1dca231bac</id>
|
||||
<name>NiFi Flow</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<comment/>
|
||||
<flowfileConcurrency>UNBOUNDED</flowfileConcurrency>
|
||||
<flowfileOutboundPolicy>STREAM_WHEN_AVAILABLE</flowfileOutboundPolicy>
|
||||
<processor>
|
||||
<id>c40fc154-ef89-48b8-82bf-ff6cc9e8f591</id>
|
||||
<name>DummyScheduledProcessor</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<styles/>
|
||||
<comment><tagName> "This" is an ' example with many characters that need to be filtered and escaped in it.  † </comment>
|
||||
<class>org.apache.nifi.controller.DummyScheduledProcessor</class>
|
||||
<maxConcurrentTasks>5</maxConcurrentTasks>
|
||||
<schedulingPeriod>0 0 0 1/1 * ?</schedulingPeriod>
|
||||
<penalizationPeriod>30 sec</penalizationPeriod>
|
||||
<yieldPeriod>1 sec</yieldPeriod>
|
||||
<bulletinLevel>WARN</bulletinLevel>
|
||||
<lossTolerant>false</lossTolerant>
|
||||
<scheduledState>STOPPED</scheduledState>
|
||||
<schedulingStrategy>CRON_DRIVEN</schedulingStrategy>
|
||||
<executionNode>ALL</executionNode>
|
||||
<runDurationNanos>0</runDurationNanos>
|
||||
</processor>
|
||||
<variable name="Name with escape needed" value="Value with escape needed"/>
|
||||
<inheritedParameterContextId>context</inheritedParameterContextId>
|
||||
</rootGroup>
|
||||
<controllerServices/>
|
||||
<reportingTasks/>
|
||||
</flowController>
|
@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<flowController>
|
||||
<maxThreadCount>15</maxThreadCount>
|
||||
<parameterContexts>
|
||||
<parameterContext>
|
||||
<id>053a6266-dcd0-33e9-b5af-b8c282d25bf0</id>
|
||||
<name>Context</name>
|
||||
<description/>
|
||||
<inheritedParameterContextId>153a6266-dcd0-33e9-b5af-b8c282d25bf1</inheritedParameterContextId>
|
||||
<inheritedParameterContextId>253a6266-dcd0-33e9-b5af-b8c282d25bf2</inheritedParameterContextId>
|
||||
<parameter>
|
||||
<name>parameter</name>
|
||||
<description>Parent</description>
|
||||
<sensitive>false</sensitive>
|
||||
<value>parent value</value>
|
||||
</parameter>
|
||||
</parameterContext>
|
||||
<parameterContext>
|
||||
<id>153a6266-dcd0-33e9-b5af-b8c282d25bf1</id>
|
||||
<name>Child Context</name>
|
||||
<description/>
|
||||
<parameter>
|
||||
<name>parameter</name>
|
||||
<description>Child</description>
|
||||
<sensitive>false</sensitive>
|
||||
<value>child value</value>
|
||||
</parameter>
|
||||
</parameterContext>
|
||||
<parameterContext>
|
||||
<id>253a6266-dcd0-33e9-b5af-b8c282d25bf2</id>
|
||||
<name>Second Child Context</name>
|
||||
<description/>
|
||||
<parameter>
|
||||
<name>parameter</name>
|
||||
<description>Second child</description>
|
||||
<sensitive>false</sensitive>
|
||||
<value>second child value</value>
|
||||
</parameter>
|
||||
</parameterContext>
|
||||
</parameterContexts>
|
||||
<rootGroup>
|
||||
<id>e3909250-331d-420b-a9b3-cc54ad459401</id>
|
||||
<name>NiFi Flow</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style/>
|
||||
<comment/>
|
||||
<processor>
|
||||
<id>d89ada5d-35fb-44ff-83f1-4cc00b48b2df</id>
|
||||
<name>GenerateFlowFile</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<styles/>
|
||||
<comment/>
|
||||
<class>org.apache.nifi.processors.standard.GenerateFlowFile</class>
|
||||
<bundle>
|
||||
<group>org.apache.nifi</group>
|
||||
<artifact>nifi-standard-nar</artifact>
|
||||
<version>1.3.0-SNAPSHOT</version>
|
||||
</bundle>
|
||||
<maxConcurrentTasks>1</maxConcurrentTasks>
|
||||
<schedulingPeriod>0 sec</schedulingPeriod>
|
||||
<penalizationPeriod>30 sec</penalizationPeriod>
|
||||
<yieldPeriod>1 sec</yieldPeriod>
|
||||
<bulletinLevel>WARN</bulletinLevel>
|
||||
<lossTolerant>false</lossTolerant>
|
||||
<scheduledState>RUNNING</scheduledState>
|
||||
<schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
|
||||
<executionNode>ALL</executionNode>
|
||||
<runDurationNanos>0</runDurationNanos>
|
||||
<property>
|
||||
<name>file.size</name>
|
||||
<value>5</value>
|
||||
</property>
|
||||
<annotationData/>
|
||||
</processor>
|
||||
<processor>
|
||||
<id>e520797a-dddb-4930-9034-2092d3e816a6</id>
|
||||
<name>LogAttribute</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style>processor</style>
|
||||
<comment/>
|
||||
<class>org.apache.nifi.processors.standard.LogAttribute</class>
|
||||
<maxConcurrentTasks>1</maxConcurrentTasks>
|
||||
<schedulingPeriod>0 s</schedulingPeriod>
|
||||
<lossTolerant>false</lossTolerant>
|
||||
<running>false</running>
|
||||
<annotationData/>
|
||||
<autoTerminatedRelationship>success</autoTerminatedRelationship>
|
||||
</processor>
|
||||
<processGroup>
|
||||
<id>efeece05-3934-4298-a725-658eec116470</id>
|
||||
<name>Hello</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style>process-group</style>
|
||||
<comment/>
|
||||
<processor>
|
||||
<id>34caa1d6-cf14-4ec0-9f18-12859c37d55d</id>
|
||||
<name>LogAttribute</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style>processor</style>
|
||||
<comment/>
|
||||
<class>org.apache.nifi.processors.standard.LogAttribute</class>
|
||||
<maxConcurrentTasks>1</maxConcurrentTasks>
|
||||
<schedulingPeriod>0 s</schedulingPeriod>
|
||||
<lossTolerant>false</lossTolerant>
|
||||
<running>false</running>
|
||||
<annotationData/>
|
||||
</processor>
|
||||
<inputPort>
|
||||
<id>91fae6d8-ad95-47cf-aa83-a6dfc742b7cb</id>
|
||||
<name>In</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style>input-port</style>
|
||||
<comments/>
|
||||
<running>false</running>
|
||||
</inputPort>
|
||||
<outputPort>
|
||||
<id>a65695bb-a938-4d3d-bf5d-f70a335268ec</id>
|
||||
<name>Out</name>
|
||||
<position x="0.0" y="0.0"/>
|
||||
<style>output-port</style>
|
||||
<comments/>
|
||||
<running>false</running>
|
||||
</outputPort>
|
||||
<connection>
|
||||
<id>b25c3c8f-8dfe-4dda-950e-b6edfb6c99f4</id>
|
||||
<name>In Connection</name>
|
||||
<bendPoints/>
|
||||
<labelIndex>1</labelIndex>
|
||||
<zIndex>0</zIndex>
|
||||
<style/>
|
||||
<sourceId>91fae6d8-ad95-47cf-aa83-a6dfc742b7cb</sourceId>
|
||||
<sourceGroupId>efeece05-3934-4298-a725-658eec116470</sourceGroupId>
|
||||
<sourceType>INPUT_PORT</sourceType>
|
||||
<destinationId>34caa1d6-cf14-4ec0-9f18-12859c37d55d</destinationId>
|
||||
<destinationGroupId>efeece05-3934-4298-a725-658eec116470</destinationGroupId>
|
||||
<destinationType>PROCESSOR</destinationType>
|
||||
<relationship/>
|
||||
<maxWorkQueueSize>0</maxWorkQueueSize>
|
||||
<flowFileExpiration>0 s</flowFileExpiration>
|
||||
</connection>
|
||||
<connection>
|
||||
<id>908afab7-8777-4acf-a807-24f684f7aa9f</id>
|
||||
<name/>
|
||||
<bendPoints/>
|
||||
<labelIndex>1</labelIndex>
|
||||
<zIndex>0</zIndex>
|
||||
<style/>
|
||||
<sourceId>34caa1d6-cf14-4ec0-9f18-12859c37d55d</sourceId>
|
||||
<sourceGroupId>efeece05-3934-4298-a725-658eec116470</sourceGroupId>
|
||||
<sourceType>PROCESSOR</sourceType>
|
||||
<destinationId>a65695bb-a938-4d3d-bf5d-f70a335268ec</destinationId>
|
||||
<destinationGroupId>efeece05-3934-4298-a725-658eec116470</destinationGroupId>
|
||||
<destinationType>OUTPUT_PORT</destinationType>
|
||||
<relationship>success</relationship>
|
||||
<maxWorkQueueSize>0</maxWorkQueueSize>
|
||||
<flowFileExpiration>0 s</flowFileExpiration>
|
||||
</connection>
|
||||
</processGroup>
|
||||
<connection>
|
||||
<id>03f4f5bf-baa5-47fa-9b1a-b77860d67d4f</id>
|
||||
<name/>
|
||||
<bendPoints/>
|
||||
<labelIndex>1</labelIndex>
|
||||
<zIndex>0</zIndex>
|
||||
<style/>
|
||||
<sourceId>d89ada5d-35fb-44ff-83f1-4cc00b48b2df</sourceId>
|
||||
<sourceGroupId>e3909250-331d-420b-a9b3-cc54ad459401</sourceGroupId>
|
||||
<sourceType>PROCESSOR</sourceType>
|
||||
<destinationId>91fae6d8-ad95-47cf-aa83-a6dfc742b7cb</destinationId>
|
||||
<destinationGroupId>efeece05-3934-4298-a725-658eec116470</destinationGroupId>
|
||||
<destinationType>INPUT_PORT</destinationType>
|
||||
<relationship>success</relationship>
|
||||
<maxWorkQueueSize>0</maxWorkQueueSize>
|
||||
<flowFileExpiration>0 s</flowFileExpiration>
|
||||
</connection>
|
||||
<connection>
|
||||
<id>5bd05300-f03d-4511-a13f-6a36afe2bcc5</id>
|
||||
<name/>
|
||||
<bendPoints/>
|
||||
<labelIndex>1</labelIndex>
|
||||
<zIndex>0</zIndex>
|
||||
<style/>
|
||||
<sourceId>a65695bb-a938-4d3d-bf5d-f70a335268ec</sourceId>
|
||||
<sourceGroupId>efeece05-3934-4298-a725-658eec116470</sourceGroupId>
|
||||
<sourceType>OUTPUT_PORT</sourceType>
|
||||
<destinationId>e520797a-dddb-4930-9034-2092d3e816a6</destinationId>
|
||||
<destinationGroupId>e3909250-331d-420b-a9b3-cc54ad459401</destinationGroupId>
|
||||
<destinationType>PROCESSOR</destinationType>
|
||||
<relationship/>
|
||||
<maxWorkQueueSize>0</maxWorkQueueSize>
|
||||
<flowFileExpiration>0 s</flowFileExpiration>
|
||||
</connection>
|
||||
</rootGroup>
|
||||
</flowController>
|
@ -40,6 +40,7 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Audits processor creation/removal and configuration changes.
|
||||
@ -277,6 +278,10 @@ public class ParameterContextAuditor extends NiFiAuditor {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!parameterContext.getInheritedParameterContexts().isEmpty()) {
|
||||
values.put("Inherited Parameter Contexts", parameterContext.getInheritedParameterContexts()
|
||||
.stream().map(pc -> pc.getIdentifier()).collect(Collectors.joining(", ")));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import org.apache.nifi.web.api.dto.FlowSnippetDTO;
|
||||
import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
|
||||
import org.apache.nifi.web.api.dto.ProcessorDTO;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -160,6 +161,8 @@ public class AuthorizeParameterReference {
|
||||
.map(ParameterDescriptor::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final List<String> existingParameterContextNames = parameterContext.getInheritedParameterContextNames();
|
||||
|
||||
boolean requiresAddition = false;
|
||||
for (final VersionedParameter versionedParameter : versionedParameterContext.getParameters()) {
|
||||
final String versionedParameterName = versionedParameter.getName();
|
||||
@ -169,7 +172,7 @@ public class AuthorizeParameterReference {
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresAddition) {
|
||||
if (requiresAddition || !existingParameterContextNames.equals(versionedParameterContext.getInheritedParameterContexts())) {
|
||||
// User is required to have WRITE permission to the Parameter Context in order to add one or more parameters.
|
||||
parameterContext.authorize(authorizer, RequestAction.WRITE, user);
|
||||
}
|
||||
|
@ -1092,10 +1092,11 @@ public interface NiFiServiceFacade {
|
||||
/**
|
||||
* Returns the ParameterContextEntity for the ParameterContext with the given ID
|
||||
* @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
|
||||
* @return the ParameterContextEntity
|
||||
*/
|
||||
ParameterContextEntity getParameterContext(String parameterContextId, NiFiUser user);
|
||||
ParameterContextEntity getParameterContext(String parameterContextId, boolean includeInheritedParameters, NiFiUser user);
|
||||
|
||||
/**
|
||||
* Creates a new Parameter Context
|
||||
|
@ -101,6 +101,7 @@ import org.apache.nifi.metrics.jvm.JmxJvmMetrics;
|
||||
import org.apache.nifi.nar.ExtensionManager;
|
||||
import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterContextLookup;
|
||||
import org.apache.nifi.parameter.ParameterDescriptor;
|
||||
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||
import org.apache.nifi.parameter.StandardParameterContext;
|
||||
@ -1053,7 +1054,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
final RevisionUpdate<ParameterContextDTO> snapshot = updateComponent(revision,
|
||||
parameterContext,
|
||||
() -> parameterContextDAO.updateParameterContext(parameterContextDto),
|
||||
context -> dtoFactory.createParameterContextDto(context, revisionManager));
|
||||
context -> dtoFactory.createParameterContextDto(context, revisionManager, false, parameterContextDAO));
|
||||
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(parameterContext);
|
||||
final RevisionDTO revisionDto = dtoFactory.createRevisionDTO(snapshot.getLastModification());
|
||||
@ -1062,9 +1063,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterContextEntity getParameterContext(final String parameterContextId, final NiFiUser user) {
|
||||
public ParameterContextEntity getParameterContext(final String parameterContextId, final boolean includeInheritedParameters, final NiFiUser user) {
|
||||
final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextId);
|
||||
return createParameterContextEntity(parameterContext, user);
|
||||
return createParameterContextEntity(parameterContext, includeInheritedParameters, user, parameterContextDAO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1072,7 +1073,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
final NiFiUser user = NiFiUserUtils.getNiFiUser();
|
||||
|
||||
final Set<ParameterContextEntity> entities = parameterContextDAO.getParameterContexts().stream()
|
||||
.map(context -> createParameterContextEntity(context, user))
|
||||
.map(context -> createParameterContextEntity(context, false, user, parameterContextDAO))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return entities;
|
||||
@ -1100,10 +1101,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
return parameterContext;
|
||||
}
|
||||
|
||||
private ParameterContextEntity createParameterContextEntity(final ParameterContext parameterContext, final NiFiUser user) {
|
||||
private ParameterContextEntity createParameterContextEntity(final ParameterContext parameterContext, final boolean includeInheritedParameters, final NiFiUser user,
|
||||
final ParameterContextLookup parameterContextLookup) {
|
||||
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(parameterContext, user);
|
||||
final RevisionDTO revisionDto = dtoFactory.createRevisionDTO(revisionManager.getRevision(parameterContext.getIdentifier()));
|
||||
final ParameterContextDTO parameterContextDto = dtoFactory.createParameterContextDto(parameterContext, revisionManager);
|
||||
final ParameterContextDTO parameterContextDto = dtoFactory.createParameterContextDto(parameterContext, revisionManager, includeInheritedParameters, parameterContextLookup);
|
||||
final ParameterContextEntity entity = entityFactory.createParameterContextEntity(parameterContextDto, revisionDto, permissions);
|
||||
return entity;
|
||||
}
|
||||
@ -1113,7 +1115,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextDto.getId());
|
||||
final Set<ProcessGroup> boundProcessGroups = parameterContext.getParameterReferenceManager().getProcessGroupsBound(parameterContext);
|
||||
|
||||
final ParameterContext updatedParameterContext = new StandardParameterContext(parameterContext.getIdentifier(), parameterContext.getName(), ParameterReferenceManager.EMPTY, null);
|
||||
final ParameterContext updatedParameterContext = new StandardParameterContext(parameterContext.getIdentifier(), parameterContext.getName(),
|
||||
ParameterReferenceManager.EMPTY, null);
|
||||
final Map<String, Parameter> parameters = new HashMap<>();
|
||||
parameterContextDto.getParameters().stream()
|
||||
.map(ParameterEntity::getParameter)
|
||||
@ -1186,7 +1189,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
// save the update
|
||||
controllerFacade.save();
|
||||
|
||||
final ParameterContextDTO dto = dtoFactory.createParameterContextDto(parameterContext, revisionManager);
|
||||
final ParameterContextDTO dto = dtoFactory.createParameterContextDto(parameterContext, revisionManager, false, parameterContextDAO);
|
||||
final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity());
|
||||
return new StandardRevisionUpdate<>(dto, lastMod);
|
||||
});
|
||||
@ -1211,7 +1214,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
parameterContext.getResource(),
|
||||
() -> parameterContextDAO.deleteParameterContext(parameterContextId),
|
||||
true,
|
||||
dtoFactory.createParameterContextDto(parameterContext, revisionManager));
|
||||
dtoFactory.createParameterContextDto(parameterContext, revisionManager, false, parameterContextDAO));
|
||||
|
||||
return entityFactory.createParameterContextEntity(snapshot, null, permissions);
|
||||
|
||||
@ -1286,8 +1289,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
||||
|
||||
private Set<AffectedComponentEntity> getComponentsAffectedByParameterContextUpdate(final ParameterContextDTO parameterContextDto, final boolean includeInactive) {
|
||||
final ProcessGroup rootGroup = processGroupDAO.getProcessGroup("root");
|
||||
final ParameterContext parameterContext = parameterContextDAO.getParameterContext(parameterContextDto.getId());
|
||||
final List<ProcessGroup> groupsReferencingParameterContext = rootGroup.findAllProcessGroups(
|
||||
group -> group.getParameterContext() != null && group.getParameterContext().getIdentifier().equals(parameterContextDto.getId()));
|
||||
group -> group.getParameterContext() != null && (group.getParameterContext().getIdentifier().equals(parameterContextDto.getId())
|
||||
|| group.getParameterContext().inheritsFrom(parameterContext.getIdentifier())));
|
||||
|
||||
final Set<String> updatedParameterNames = getUpdatedParameterNames(parameterContextDto);
|
||||
|
||||
|
@ -147,7 +147,10 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
@ApiResponse(code = 404, message = "The specified resource could not be found."),
|
||||
@ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
|
||||
})
|
||||
public Response getParameterContext(@ApiParam("The ID of the Parameter Context") @PathParam("id") final String parameterContextId) {
|
||||
public Response getParameterContext(@ApiParam("The ID of the Parameter Context") @PathParam("id") final String parameterContextId,
|
||||
@ApiParam("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) {
|
||||
// authorize access
|
||||
authorizeReadParameterContext(parameterContextId);
|
||||
|
||||
@ -156,7 +159,7 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
}
|
||||
|
||||
// get the specified parameter context
|
||||
final ParameterContextEntity entity = serviceFacade.getParameterContext(parameterContextId, NiFiUserUtils.getNiFiUser());
|
||||
final ParameterContextEntity entity = serviceFacade.getParameterContext(parameterContextId, includeInheritedParameters, NiFiUserUtils.getNiFiUser());
|
||||
entity.setUri(generateResourceUri("parameter-contexts", entity.getId()));
|
||||
|
||||
// generate the response
|
||||
@ -171,7 +174,8 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
value = "Create a Parameter Context",
|
||||
response = ParameterContextEntity.class,
|
||||
authorizations = {
|
||||
@Authorization(value = "Write - /parameter-contexts")
|
||||
@Authorization(value = "Write - /parameter-contexts"),
|
||||
@Authorization(value = "Read - for every inherited parameter context")
|
||||
})
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
|
||||
@ -315,7 +319,9 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
@Authorization(value = "Read - /parameter-contexts/{parameterContextId}"),
|
||||
@Authorization(value = "Write - /parameter-contexts/{parameterContextId}"),
|
||||
@Authorization(value = "Read - for every component that is affected by the update"),
|
||||
@Authorization(value = "Write - for every component that is affected by the update")
|
||||
@Authorization(value = "Write - for every component that is affected by the update"),
|
||||
@Authorization(value = "Read - for every currently inherited parameter context"),
|
||||
@Authorization(value = "Read - for any new inherited parameter context")
|
||||
})
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
|
||||
@ -400,11 +406,13 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
}
|
||||
|
||||
private void validateParameterNames(final ParameterContextDTO parameterContextDto) {
|
||||
for (final ParameterEntity entity : parameterContextDto.getParameters()) {
|
||||
final String parameterName = entity.getParameter().getName();
|
||||
if (!isLegalParameterName(parameterName)) {
|
||||
throw new IllegalArgumentException("Request contains an illegal Parameter Name (" + parameterName + "). Parameter names may only include letters, numbers, spaces, and the special " +
|
||||
"characters .-_");
|
||||
if (parameterContextDto.getParameters() != null) {
|
||||
for (final ParameterEntity entity : parameterContextDto.getParameters()) {
|
||||
final String parameterName = entity.getParameter().getName();
|
||||
if (!isLegalParameterName(parameterName)) {
|
||||
throw new IllegalArgumentException("Request contains an illegal Parameter Name (" + parameterName
|
||||
+ "). Parameter names may only include letters, numbers, spaces, and the special characters .-_");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -576,7 +584,7 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
parameterContext.authorize(authorizer, RequestAction.READ, user);
|
||||
parameterContext.authorize(authorizer, RequestAction.WRITE, user);
|
||||
|
||||
final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, user);
|
||||
final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(parameterContextId, false, user);
|
||||
for (final ProcessGroupEntity boundGroupEntity : contextEntity.getComponent().getBoundProcessGroups()) {
|
||||
final String groupId = boundGroupEntity.getId();
|
||||
final Authorizable groupAuthorizable = lookup.getProcessGroup(groupId).getAuthorizable();
|
||||
@ -660,7 +668,7 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
}
|
||||
|
||||
private void authorizeReferencingComponents(final String parameterContextId, final AuthorizableLookup lookup, final NiFiUser user) {
|
||||
final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, NiFiUserUtils.getNiFiUser());
|
||||
final ParameterContextEntity context = serviceFacade.getParameterContext(parameterContextId, false, NiFiUserUtils.getNiFiUser());
|
||||
|
||||
for (final ParameterEntity parameterEntity : context.getComponent().getParameters()) {
|
||||
final ParameterDTO dto = parameterEntity.getParameter();
|
||||
@ -946,7 +954,7 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
throw new LifecycleManagementException("Failed to update Flow on all nodes in cluster due to " + explanation);
|
||||
}
|
||||
|
||||
return serviceFacade.getParameterContext(updatedContext.getId(), user);
|
||||
return serviceFacade.getParameterContext(updatedContext.getId(), false, user);
|
||||
} else {
|
||||
serviceFacade.verifyUpdateParameterContext(updatedContext.getComponent(), true);
|
||||
return serviceFacade.updateParameterContext(revision, updatedContext.getComponent());
|
||||
@ -965,7 +973,11 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
private <T> T getResponseEntity(final NodeResponse nodeResponse, final Class<T> clazz) {
|
||||
T entity = (T) nodeResponse.getUpdatedEntity();
|
||||
if (entity == null) {
|
||||
entity = nodeResponse.getClientResponse().readEntity(clazz);
|
||||
if (nodeResponse.getClientResponse() != null) {
|
||||
entity = nodeResponse.getClientResponse().readEntity(clazz);
|
||||
} else {
|
||||
entity = (T) nodeResponse.getThrowable().toString();
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
@ -1188,7 +1200,7 @@ public class ParameterContextResource extends ApplicationResource {
|
||||
updateRequestDto.setReferencingComponents(new HashSet<>(affectedComponents.values()));
|
||||
|
||||
// Populate the Affected Components
|
||||
final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(asyncRequest.getComponentId(), NiFiUserUtils.getNiFiUser());
|
||||
final ParameterContextEntity contextEntity = serviceFacade.getParameterContext(asyncRequest.getComponentId(), false, NiFiUserUtils.getNiFiUser());
|
||||
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'
|
||||
|
@ -128,6 +128,7 @@ import org.apache.nifi.nar.ExtensionManager;
|
||||
import org.apache.nifi.nar.NarClassLoadersHolder;
|
||||
import org.apache.nifi.parameter.Parameter;
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterContextLookup;
|
||||
import org.apache.nifi.parameter.ParameterDescriptor;
|
||||
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||
import org.apache.nifi.processor.Processor;
|
||||
@ -1448,7 +1449,8 @@ public final class DtoFactory {
|
||||
return dto;
|
||||
}
|
||||
|
||||
public ParameterContextDTO createParameterContextDto(final ParameterContext parameterContext, final RevisionManager revisionManager) {
|
||||
public ParameterContextDTO createParameterContextDto(final ParameterContext parameterContext, final RevisionManager revisionManager,
|
||||
final boolean includeInheritedParameters, final ParameterContextLookup parameterContextLookup) {
|
||||
final ParameterContextDTO dto = new ParameterContextDTO();
|
||||
dto.setId(parameterContext.getIdentifier());
|
||||
dto.setName(parameterContext.getName());
|
||||
@ -1465,16 +1467,27 @@ public final class DtoFactory {
|
||||
dto.setBoundProcessGroups(boundGroups);
|
||||
|
||||
final Set<ParameterEntity> parameterEntities = new LinkedHashSet<>();
|
||||
for (final Parameter parameter : parameterContext.getParameters().values()) {
|
||||
parameterEntities.add(createParameterEntity(parameterContext, parameter, revisionManager));
|
||||
final Map<ParameterDescriptor, Parameter> parameters = includeInheritedParameters ? parameterContext.getEffectiveParameters()
|
||||
: parameterContext.getParameters();
|
||||
for (final Parameter parameter : parameters.values()) {
|
||||
parameterEntities.add(createParameterEntity(parameterContext, parameter, revisionManager, parameterContextLookup));
|
||||
}
|
||||
|
||||
final List<ParameterContextReferenceEntity> parameterContextRefs = new ArrayList<>();
|
||||
if (parameterContext.getInheritedParameterContexts() != null) {
|
||||
parameterContextRefs.addAll(parameterContext.getInheritedParameterContexts().stream()
|
||||
.map(pc -> entityFactory.createParameterReferenceEntity(createParameterContextReference(pc), createPermissionsDto(pc)))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
dto.setInheritedParameterContexts(parameterContextRefs);
|
||||
|
||||
dto.setParameters(parameterEntities);
|
||||
return dto;
|
||||
}
|
||||
|
||||
public ParameterEntity createParameterEntity(final ParameterContext parameterContext, final Parameter parameter, final RevisionManager revisionManager) {
|
||||
final ParameterDTO dto = createParameterDto(parameterContext, parameter, revisionManager);
|
||||
public ParameterEntity createParameterEntity(final ParameterContext parameterContext, final Parameter parameter, final RevisionManager revisionManager,
|
||||
final ParameterContextLookup parameterContextLookup) {
|
||||
final ParameterDTO dto = createParameterDto(parameterContext, parameter, revisionManager, parameterContextLookup);
|
||||
final ParameterEntity entity = new ParameterEntity();
|
||||
entity.setParameter(dto);
|
||||
|
||||
@ -1484,7 +1497,8 @@ public final class DtoFactory {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public ParameterDTO createParameterDto(final ParameterContext parameterContext, final Parameter parameter, final RevisionManager revisionManager) {
|
||||
public ParameterDTO createParameterDto(final ParameterContext parameterContext, final Parameter parameter,
|
||||
final RevisionManager revisionManager, final ParameterContextLookup parameterContextLookup) {
|
||||
final ParameterDescriptor descriptor = parameter.getDescriptor();
|
||||
|
||||
final ParameterDTO dto = new ParameterDTO();
|
||||
@ -1504,6 +1518,11 @@ public final class DtoFactory {
|
||||
final Set<AffectedComponentEntity> referencingComponentEntities = createAffectedComponentEntities(referencingComponents, revisionManager);
|
||||
dto.setReferencingComponents(referencingComponentEntities);
|
||||
|
||||
final ParameterContext containingParameterContext = (parameter.getParameterContextId() == null)
|
||||
? parameterContext : parameterContextLookup.getParameterContext(parameter.getParameterContextId());
|
||||
ParameterContextReferenceDTO refDto = createParameterContextReference(containingParameterContext);
|
||||
dto.setParameterContext(entityFactory.createParameterReferenceEntity(refDto, createPermissionsDto(containingParameterContext)));
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
@ -17,18 +17,12 @@
|
||||
package org.apache.nifi.web.dao;
|
||||
|
||||
import org.apache.nifi.parameter.ParameterContext;
|
||||
import org.apache.nifi.parameter.ParameterContextLookup;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface ParameterContextDAO {
|
||||
/**
|
||||
* Determines if the specified parameter context exists.
|
||||
*
|
||||
* @param parameterContextId id
|
||||
* @return true if parameter context exists
|
||||
*/
|
||||
boolean hasParameterContext(String parameterContextId);
|
||||
public interface ParameterContextDAO extends ParameterContextLookup {
|
||||
|
||||
/**
|
||||
* Determines whether this parameter context can be created.
|
||||
@ -45,14 +39,6 @@ public interface ParameterContextDAO {
|
||||
*/
|
||||
ParameterContext createParameterContext(ParameterContextDTO parameterContextDto);
|
||||
|
||||
/**
|
||||
* Gets the specified parameter context.
|
||||
*
|
||||
* @param parameterContextId the id of the parameter context
|
||||
* @return the parameter context
|
||||
*/
|
||||
ParameterContext getParameterContext(String parameterContextId);
|
||||
|
||||
/**
|
||||
* Gets all of the parameter contexts.
|
||||
*
|
||||
|
@ -16,6 +16,10 @@
|
||||
*/
|
||||
package org.apache.nifi.web.dao.impl;
|
||||
|
||||
import org.apache.nifi.authorization.Authorizer;
|
||||
import org.apache.nifi.authorization.RequestAction;
|
||||
import org.apache.nifi.authorization.user.NiFiUser;
|
||||
import org.apache.nifi.authorization.user.NiFiUserUtils;
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.controller.ComponentNode;
|
||||
import org.apache.nifi.controller.FlowController;
|
||||
@ -32,19 +36,25 @@ import org.apache.nifi.parameter.ParameterReference;
|
||||
import org.apache.nifi.parameter.ParameterReferenceManager;
|
||||
import org.apache.nifi.web.ResourceNotFoundException;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterEntity;
|
||||
import org.apache.nifi.web.dao.ParameterContextDAO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
private FlowManager flowManager;
|
||||
private Authorizer authorizer;
|
||||
|
||||
@Override
|
||||
public boolean hasParameterContext(final String parameterContextId) {
|
||||
@ -54,16 +64,76 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
@Override
|
||||
public void verifyCreate(final ParameterContextDTO parameterContextDto) {
|
||||
verifyNoNamingConflict(parameterContextDto.getName());
|
||||
verifyInheritedParameterContextRefs(parameterContextDto);
|
||||
}
|
||||
|
||||
private void verifyInheritedParameterContextRefs(final ParameterContextDTO parameterContextDto) {
|
||||
final List<ParameterContextReferenceEntity> inheritedParameterContexts = parameterContextDto.getInheritedParameterContexts();
|
||||
|
||||
if (inheritedParameterContexts != null) {
|
||||
resolveInheritedParameterContexts(parameterContextDto);
|
||||
// This will throw an exception if one is not found
|
||||
inheritedParameterContexts.stream().forEach(entity -> flowManager.getParameterContextManager()
|
||||
.getParameterContext(entity.getComponent().getId()));
|
||||
}
|
||||
authorizeReferences(parameterContextDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterContext createParameterContext(final ParameterContextDTO parameterContextDto) {
|
||||
final Map<String, Parameter> parameters = getParameters(parameterContextDto, null);
|
||||
final ParameterContext parameterContext = flowManager.createParameterContext(parameterContextDto.getId(), parameterContextDto.getName(), parameters);
|
||||
if (parameterContextDto.getDescription() != null) {
|
||||
parameterContext.setDescription(parameterContextDto.getDescription());
|
||||
|
||||
resolveInheritedParameterContexts(parameterContextDto);
|
||||
|
||||
final AtomicReference<ParameterContext> parameterContextReference = new AtomicReference<>();
|
||||
flowManager.withParameterContextResolution(() -> {
|
||||
final ParameterContext parameterContext = flowManager.createParameterContext(parameterContextDto.getId(), parameterContextDto.getName(),
|
||||
parameters, parameterContextDto.getInheritedParameterContexts());
|
||||
if (parameterContextDto.getDescription() != null) {
|
||||
parameterContext.setDescription(parameterContextDto.getDescription());
|
||||
}
|
||||
parameterContextReference.set(parameterContext);
|
||||
});
|
||||
return parameterContextReference.get();
|
||||
}
|
||||
|
||||
private void authorizeReferences(final ParameterContextDTO parameterContextDto) {
|
||||
final NiFiUser nifiUser = NiFiUserUtils.getNiFiUser();
|
||||
if (parameterContextDto.getInheritedParameterContexts() != null) {
|
||||
for (final ParameterContextReferenceEntity ref : parameterContextDto.getInheritedParameterContexts()) {
|
||||
final ParameterContext parameterContext = getParameterContext(ref.getComponent().getId());
|
||||
parameterContext.authorize(authorizer, RequestAction.READ, nifiUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveInheritedParameterContexts(final ParameterContextDTO parameterContextDto) {
|
||||
final List<ParameterContextReferenceEntity> inheritedParameterContexts = parameterContextDto.getInheritedParameterContexts();
|
||||
if (inheritedParameterContexts == null || inheritedParameterContexts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, ParameterContext> paramContextNameMap = flowManager.getParameterContextManager().getParameterContextNameMapping();
|
||||
for (final ParameterContextReferenceEntity ref : inheritedParameterContexts) {
|
||||
if (ref.getComponent() == null || (ref.getComponent().getId() == null && ref.getComponent().getName() == null)) {
|
||||
throw new IllegalStateException(String.format("Could not resolve inherited parameter context references in Parameter Context [%s]",
|
||||
parameterContextDto.getName()));
|
||||
}
|
||||
final ParameterContextReferenceDTO refDto = ref.getComponent();
|
||||
if (refDto.getId() != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If resolving by name only, look up the ids
|
||||
final ParameterContext resolvedParameterContext = paramContextNameMap.get(refDto.getName());
|
||||
if (resolvedParameterContext == null) {
|
||||
throw new IllegalStateException(String.format("Parameter Context [%s] references missing inherited Parameter Context [%s]",
|
||||
parameterContextDto.getName(), refDto.getName()));
|
||||
}
|
||||
|
||||
ref.setId(resolvedParameterContext.getIdentifier());
|
||||
ref.getComponent().setId(resolvedParameterContext.getIdentifier());
|
||||
}
|
||||
return parameterContext;
|
||||
}
|
||||
|
||||
private Map<String, Parameter> getParameters(final ParameterContextDTO parameterContextDto, final ParameterContext context) {
|
||||
@ -149,12 +219,28 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
context.setParameters(parameters);
|
||||
}
|
||||
|
||||
if (parameterContextDto.getInheritedParameterContexts() != null) {
|
||||
final List<ParameterContext> inheritedParameterContexts = getInheritedParameterContexts(parameterContextDto);
|
||||
context.setInheritedParameterContexts(inheritedParameterContexts);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private List<ParameterContext> getInheritedParameterContexts(final ParameterContextDTO parameterContextDto) {
|
||||
resolveInheritedParameterContexts(parameterContextDto);
|
||||
|
||||
final List<ParameterContext> inheritedParameterContexts = new ArrayList<>();
|
||||
inheritedParameterContexts.addAll(parameterContextDto.getInheritedParameterContexts().stream()
|
||||
.map(entity -> flowManager.getParameterContextManager().getParameterContext(entity.getComponent().getId()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return inheritedParameterContexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyUpdate(final ParameterContextDTO parameterContextDto, final boolean verifyComponentStates) {
|
||||
verifyNoNamingConflict(parameterContextDto.getName(), parameterContextDto.getId());
|
||||
verifyInheritedParameterContextRefs(parameterContextDto);
|
||||
|
||||
final ParameterContext currentContext = getParameterContext(parameterContextDto.getId());
|
||||
for (final ParameterEntity parameterEntity : parameterContextDto.getParameters()) {
|
||||
@ -208,8 +294,21 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
}
|
||||
|
||||
if (active && (verifyComponentStates || parameterDeletion)) {
|
||||
throw new IllegalStateException("Cannot update Parameter Context " + contextName + " because it has Parameters that are being referenced by a " +
|
||||
activeExplanation + ".");
|
||||
if (parameterDeletion) {
|
||||
// First check if the actual parameter context is now missing the parameter: it may not be,
|
||||
// if the parameter is inherited from another context
|
||||
final ProcessGroup processGroup = flowManager.getGroup(component.getProcessGroupIdentifier());
|
||||
final ParameterContext parameterContext = processGroup.getParameterContext();
|
||||
final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder()
|
||||
.name(parameterName).build();
|
||||
if (!parameterContext.hasEffectiveValueIfRemoved(parameterDescriptor)) {
|
||||
throw new IllegalStateException("Cannot update Parameter Context " + contextName + " because the " + parameterName + " Parameter is being referenced by a " +
|
||||
activeExplanation + ".");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot update Parameter Context " + contextName + " because it has Parameters that are being referenced by a " +
|
||||
activeExplanation + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -268,6 +367,13 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final ParameterContext parameterContext : flowManager.getParameterContextManager().getParameterContexts()) {
|
||||
if (parameterContext.getInheritedParameterContexts().stream().anyMatch(pc -> pc.getIdentifier().equals(parameterContextId))) {
|
||||
throw new IllegalStateException(String.format("Cannot delete Parameter Context with ID [%s] because it is referenced by at least one Parameter Context [%s]",
|
||||
parameterContextId, parameterContext.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -289,4 +395,8 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
|
||||
final ProcessGroup rootGroup = flowManager.getRootGroup();
|
||||
return rootGroup.findAllProcessGroups(group -> group.getParameterContext() != null && group.getParameterContext().getIdentifier().equals(parameterContextId));
|
||||
}
|
||||
|
||||
public void setAuthorizer(final Authorizer authorizer) {
|
||||
this.authorizer = authorizer;
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +271,7 @@
|
||||
</bean>
|
||||
<bean id="parameterContextDAO" class="org.apache.nifi.web.dao.impl.StandardParameterContextDAO">
|
||||
<property name="flowController" ref="flowController" />
|
||||
<property name="authorizer" ref="authorizer" />
|
||||
</bean>
|
||||
<bean id="controllerSearchService" class="org.apache.nifi.web.controller.ControllerSearchService">
|
||||
<property name="flowController" ref="flowController" />
|
||||
|
@ -71,8 +71,8 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -1538,6 +1538,9 @@
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '../nifi-api/parameter-contexts/' + encodeURIComponent(parameterContext.id),
|
||||
data: {
|
||||
includeInheritedParameters: 'true'
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var sensitive = nfCommon.isSensitiveProperty(propertyDescriptor);
|
||||
|
@ -174,6 +174,13 @@
|
||||
var sortParameters = function (sortDetails, data) {
|
||||
// defines a function for sorting
|
||||
var comparer = function (a, b) {
|
||||
// direct parameters always come above inherited ones
|
||||
if (a.isInherited === false && b.isInherited === true) {
|
||||
return -1;
|
||||
}
|
||||
if (a.isInherited === true && b.isInherited === false) {
|
||||
return 1;
|
||||
}
|
||||
if (sortDetails.columnId === 'name') {
|
||||
var aString = _.get(a, '[' + sortDetails.columnId + ']', '');
|
||||
var bString = _.get(b, '[' + sortDetails.columnId + ']', '');
|
||||
@ -544,6 +551,8 @@
|
||||
// set to pending
|
||||
$('<div class="referencing-component-container"><span class="unset">Pending Apply</span></div>').appendTo(parameterReferencingComponentsContainer);
|
||||
} else {
|
||||
$('#parameter-referencing-components-container').empty();
|
||||
|
||||
// bin the referencing components according to their type
|
||||
$.each(referencingComponents, function (_, referencingComponentEntity) {
|
||||
if (referencingComponentEntity.permissions.canRead === true && referencingComponentEntity.permissions.canWrite === true) {
|
||||
@ -809,6 +818,13 @@
|
||||
|
||||
if (isValid) {
|
||||
|
||||
var permissions = {
|
||||
canRead: true,
|
||||
canWrite: true
|
||||
};
|
||||
var parameterContext = {
|
||||
permissions: permissions
|
||||
};
|
||||
var parameter = _.extend({}, param, {
|
||||
id: _.defaultTo(param.id, parameterCount),
|
||||
hidden: false,
|
||||
@ -819,11 +835,18 @@
|
||||
isModified: true,
|
||||
hasValueChanged: false,
|
||||
isNew: true,
|
||||
isInherited: false,
|
||||
parameterContext: parameterContext
|
||||
});
|
||||
|
||||
if (_.isNil(param.id)) {
|
||||
// add a row for the new parameter
|
||||
parameterData.addItem(parameter);
|
||||
var matchingParameter = _.find(parameterData.getItems(), {name: parameter.name});
|
||||
if (_.isNil(matchingParameter)) {
|
||||
// add a row for the new parameter
|
||||
parameterData.addItem(parameter);
|
||||
} else {
|
||||
parameterData.updateItem(matchingParameter.id, parameter);
|
||||
}
|
||||
} else {
|
||||
parameterData.updateItem(param.id, parameter);
|
||||
}
|
||||
@ -918,8 +941,10 @@
|
||||
// validate the parameter is not a duplicate
|
||||
var matchingParameter = _.find(existingParameters, {name: parameter.name});
|
||||
|
||||
// Valid if no duplicate is found or it is edit mode and a matching parameter was found
|
||||
if (_.isNil(matchingParameter) || (editMode === true && !_.isNil(matchingParameter))) {
|
||||
// Valid if no duplicate is found or it is edit mode and a matching parameter was found, or it's
|
||||
// an inherited parameter
|
||||
if (_.isNil(matchingParameter) || (editMode === true && !_.isNil(matchingParameter))
|
||||
|| matchingParameter.isInherited === true) {
|
||||
return true;
|
||||
} else {
|
||||
var matchingParamIsHidden = _.get(matchingParameter, 'hidden', false);
|
||||
@ -1009,7 +1034,9 @@
|
||||
hasValueChanged: serializedParam.hasValueChanged,
|
||||
hasDescriptionChanged: serializedParam.hasDescriptionChanged,
|
||||
value: serializedParam.value,
|
||||
isModified: serializedParam.hasValueChanged || serializedParam.hasDescriptionChanged
|
||||
isModified: serializedParam.hasValueChanged || serializedParam.hasDescriptionChanged,
|
||||
isInherited: originalParameter.isInherited,
|
||||
parameterContext: originalParameter.parameterContext
|
||||
});
|
||||
|
||||
// update row for the parameter
|
||||
@ -1448,6 +1475,10 @@
|
||||
|
||||
var parameters = [];
|
||||
$.each(parameterContext.component.parameters, function (i, parameterEntity) {
|
||||
var containingParameterContext = {
|
||||
id: parameterEntity.parameter.parameterContext.component.id,
|
||||
permissions: parameterEntity.parameter.parameterContext.permissions
|
||||
};
|
||||
var parameter = {
|
||||
id: parameterCount++,
|
||||
hidden: false,
|
||||
@ -1462,7 +1493,9 @@
|
||||
previousValue: parameterEntity.parameter.value,
|
||||
previousDescription: parameterEntity.parameter.description,
|
||||
isEditable: _.defaultTo(readOnly, false) ? false : parameterEntity.canWrite,
|
||||
referencingComponents: parameterEntity.parameter.referencingComponents
|
||||
referencingComponents: parameterEntity.parameter.referencingComponents,
|
||||
parameterContext: containingParameterContext,
|
||||
isInherited: (containingParameterContext.id !== parameterContext.component.id)
|
||||
};
|
||||
|
||||
parameters.push({
|
||||
@ -1584,7 +1617,9 @@
|
||||
var parameterActionFormatter = function (row, cell, value, columnDef, dataContext) {
|
||||
var markup = '';
|
||||
|
||||
if (dataContext.isEditable === true) {
|
||||
if (dataContext.isInherited === true && dataContext.parameterContext.permissions.canRead) {
|
||||
markup += '<div title="Go To" class="pointer go-to-parameter fa fa-long-arrow-right"></div>';
|
||||
} else if (dataContext.isEditable === true) {
|
||||
markup += '<div title="Edit" class="edit-parameter pointer fa fa-pencil"></div>';
|
||||
markup += '<div title="Delete" class="delete-parameter pointer fa fa-trash"></div>';
|
||||
}
|
||||
@ -1789,7 +1824,15 @@
|
||||
|
||||
// prevents standard edit logic
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
} else if (target.hasClass('go-to-parameter')) {
|
||||
if (parameter.parameterContext.permissions.canRead === true) {
|
||||
// close the dialog since we are sending the user to the parameter context
|
||||
close();
|
||||
resetDialog();
|
||||
|
||||
nfParameterContexts.showParameterContext(parameter.parameterContext.id, parameter.parameterContext.permissions.canWrite === false, parameter.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
parametersGrid.onSelectedRowsChanged.subscribe(function (e, args) {
|
||||
@ -2490,6 +2533,9 @@
|
||||
var reloadContext = $.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.parameterContexts + '/' + encodeURIComponent(id),
|
||||
data: {
|
||||
includeInheritedParameters: 'true'
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
@ -2582,6 +2628,7 @@
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
// show the context
|
||||
$('#parameter-context-dialog')
|
||||
.modal('setHeaderText', canWrite ? 'Update Parameter Context' : 'View Parameter Context')
|
||||
@ -2660,6 +2707,9 @@
|
||||
var getContext = $.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.parameterContexts + '/' + encodeURIComponent(parameterContextId),
|
||||
data: {
|
||||
includeInheritedParameters: 'true'
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
|
@ -639,6 +639,9 @@
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '../nifi-api/parameter-contexts/' + encodeURIComponent(parameterContext.id),
|
||||
data: {
|
||||
includeInheritedParameters: 'true'
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function (response) {
|
||||
var sensitive = nfCommon.isSensitiveProperty(propertyDescriptor);
|
||||
|
@ -18,6 +18,7 @@ package org.apache.nifi.registry.flow;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class VersionedParameterContext {
|
||||
@ -25,6 +26,7 @@ public class VersionedParameterContext {
|
||||
private String name;
|
||||
private String description;
|
||||
private Set<VersionedParameter> parameters;
|
||||
private List<String> inheritedParameterContexts;
|
||||
|
||||
@ApiModelProperty("The name of the context")
|
||||
public String getName() {
|
||||
@ -52,4 +54,13 @@ public class VersionedParameterContext {
|
||||
public void setParameters(Set<VersionedParameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
@ApiModelProperty("The names of additional parameter contexts from which to inherit parameters")
|
||||
public List<String> getInheritedParameterContexts() {
|
||||
return inheritedParameterContexts;
|
||||
}
|
||||
|
||||
public void setInheritedParameterContexts(List<String> parameterContextNames) {
|
||||
this.inheritedParameterContexts = parameterContextNames;
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +176,7 @@ public class StandardStatelessEngine implements StatelessEngine<VersionedFlowSna
|
||||
|
||||
// Map existing parameter contexts by name
|
||||
final Set<ParameterContext> parameterContexts = flowManager.getParameterContextManager().getParameterContexts();
|
||||
final Map<String, ParameterContext> parameterContextMap = parameterContexts.stream()
|
||||
.collect(Collectors.toMap(ParameterContext::getName, context -> context));
|
||||
final Map<String, ParameterContext> parameterContextMap = flowManager.getParameterContextManager().getParameterContextNameMapping();
|
||||
|
||||
// Update Parameters to match those that are provided in the flow configuration, plus those overrides provided
|
||||
final List<ParameterContextDefinition> parameterContextDefinitions = dataflowDefinition.getParameterContexts();
|
||||
|
@ -173,10 +173,16 @@ public class NiFiClientUtil {
|
||||
}
|
||||
|
||||
public ParameterContextEntity createParameterContextEntity(final String name, final String description, final Set<ParameterEntity> parameters) {
|
||||
return createParameterContextEntity(name, description, parameters, Collections.emptyList());
|
||||
}
|
||||
|
||||
public ParameterContextEntity createParameterContextEntity(final String name, final String description, final Set<ParameterEntity> parameters,
|
||||
final List<ParameterContextReferenceEntity> inheritedParameterContexts) {
|
||||
final ParameterContextDTO contextDto = new ParameterContextDTO();
|
||||
contextDto.setName(name);
|
||||
contextDto.setDescription(description);
|
||||
contextDto.setParameters(parameters);
|
||||
contextDto.setInheritedParameterContexts(inheritedParameterContexts);
|
||||
|
||||
final ParameterContextEntity entity = new ParameterContextEntity();
|
||||
entity.setComponent(contextDto);
|
||||
|
@ -215,7 +215,7 @@ public class JoinClusterWithDifferentFlow extends NiFiSystemIT {
|
||||
currentState = generateFlowFileEntity.getComponent().getState();
|
||||
}
|
||||
|
||||
final ParameterContextDTO contextDto = node2Client.getParamContextClient().getParamContext(paramContextReference.getId()).getComponent();
|
||||
final ParameterContextDTO contextDto = node2Client.getParamContextClient().getParamContext(paramContextReference.getId(), false).getComponent();
|
||||
assertEquals(2, contextDto.getBoundProcessGroups().size());
|
||||
assertEquals(1, contextDto.getParameters().size());
|
||||
final ParameterEntity parameterEntity = contextDto.getParameters().iterator().next();
|
||||
|
@ -20,11 +20,13 @@ import org.apache.nifi.tests.system.NiFiSystemIT;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.ParamContextClient;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterDTO;
|
||||
import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
|
||||
import org.apache.nifi.web.api.entity.AffectedComponentEntity;
|
||||
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextUpdateRequestEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterEntity;
|
||||
import org.apache.nifi.web.api.entity.ProcessGroupEntity;
|
||||
@ -34,6 +36,7 @@ import org.junit.Test;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -61,7 +64,7 @@ public class ParameterContextIT extends NiFiSystemIT {
|
||||
assertSingleFooCreation(returned);
|
||||
|
||||
final String contextId = returned.getId();
|
||||
final ParameterContextEntity fetched = paramContextClient.getParamContext(contextId);
|
||||
final ParameterContextEntity fetched = paramContextClient.getParamContext(contextId, false);
|
||||
assertSingleFooCreation(fetched);
|
||||
}
|
||||
|
||||
@ -89,7 +92,7 @@ public class ParameterContextIT extends NiFiSystemIT {
|
||||
assertSensitiveParametersNotReturned(returned);
|
||||
|
||||
final String contextId = returned.getId();
|
||||
final ParameterContextEntity fetched = paramContextClient.getParamContext(contextId);
|
||||
final ParameterContextEntity fetched = paramContextClient.getParamContext(contextId, false);
|
||||
assertSensitiveParametersNotReturned(fetched);
|
||||
}
|
||||
|
||||
@ -154,6 +157,30 @@ public class ParameterContextIT extends NiFiSystemIT {
|
||||
waitForValidProcessor(processorId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationWithNestedParameterContexts() throws NiFiClientException, IOException, InterruptedException {
|
||||
final ProcessorEntity generate = getClientUtil().createProcessor("GenerateFlowFile");
|
||||
getClientUtil().updateProcessorProperties(generate, Collections.singletonMap("File Size", "#{foo}"));
|
||||
getClientUtil().setAutoTerminatedRelationships(generate, "success");
|
||||
|
||||
final String processorId = generate.getId();
|
||||
|
||||
waitForInvalidProcessor(processorId);
|
||||
|
||||
final ParameterEntity fooKB = createParameterEntity("foo", null, false, "1 KB");
|
||||
final Set<ParameterEntity> parameters = new HashSet<>();
|
||||
parameters.add(fooKB);
|
||||
final ParameterContextEntity contextEntity = createParameterContextEntity(getTestName(), null, parameters);
|
||||
final ParameterContextEntity createdContextEntity = getNifiClient().getParamContextClient().createParamContext(contextEntity);
|
||||
|
||||
final ParameterContextEntity parentContextEntity = createParameterContextEntity(getTestName() + " Parent", null,
|
||||
null, Arrays.asList(createdContextEntity));
|
||||
final ParameterContextEntity createdParentContextEntity = getNifiClient().getParamContextClient().createParamContext(parentContextEntity);
|
||||
|
||||
setParameterContext("root", createdParentContextEntity);
|
||||
waitForValidProcessor(processorId);
|
||||
}
|
||||
|
||||
@Test(timeout=30000)
|
||||
public void testValidationWithRequiredPropertiesAndNoDefault() throws NiFiClientException, IOException, InterruptedException {
|
||||
final ProcessorEntity generate = getClientUtil().createProcessor("DependOnProperties");
|
||||
@ -609,8 +636,25 @@ public class ParameterContextIT extends NiFiSystemIT {
|
||||
return getClientUtil().createParameterEntity(name, description, sensitive, value);
|
||||
}
|
||||
|
||||
public ParameterContextEntity createParameterContextEntity(final String name, final String description, final Set<ParameterEntity> parameters,
|
||||
final List<ParameterContextEntity> parameterContextRefs) {
|
||||
final List<ParameterContextReferenceEntity> refs = new ArrayList<>();
|
||||
if (parameterContextRefs != null) {
|
||||
refs.addAll(parameterContextRefs.stream().map(pce -> {
|
||||
ParameterContextReferenceEntity ref = new ParameterContextReferenceEntity();
|
||||
ref.setId(pce.getId());
|
||||
ParameterContextReferenceDTO refDto = new ParameterContextReferenceDTO();
|
||||
refDto.setId(pce.getComponent().getId());
|
||||
refDto.setName(pce.getComponent().getName());
|
||||
ref.setComponent(refDto);
|
||||
return ref;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
return getClientUtil().createParameterContextEntity(name, description, parameters, refs);
|
||||
}
|
||||
|
||||
public ParameterContextEntity createParameterContextEntity(final String name, final String description, final Set<ParameterEntity> parameters) {
|
||||
return getClientUtil().createParameterContextEntity(name, description, parameters);
|
||||
return createParameterContextEntity(name, description, parameters, Collections.emptyList());
|
||||
}
|
||||
|
||||
private ProcessGroupEntity setParameterContext(final String groupId, final ParameterContextEntity parameterContext) throws NiFiClientException, IOException {
|
||||
|
@ -26,7 +26,7 @@ public interface ParamContextClient {
|
||||
|
||||
ParameterContextsEntity getParamContexts() throws NiFiClientException, IOException;
|
||||
|
||||
ParameterContextEntity getParamContext(String id) throws NiFiClientException, IOException;
|
||||
ParameterContextEntity getParamContext(String id, boolean includeInheritedParameters) throws NiFiClientException, IOException;
|
||||
|
||||
ParameterContextEntity createParamContext(ParameterContextEntity paramContext) throws NiFiClientException, IOException;
|
||||
|
||||
|
@ -53,14 +53,15 @@ public class JerseyParamContextClient extends AbstractJerseyClient implements Pa
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterContextEntity getParamContext(final String id) throws NiFiClientException, IOException {
|
||||
public ParameterContextEntity getParamContext(final String id, final boolean includeInheritedParameters) throws NiFiClientException, IOException {
|
||||
if (StringUtils.isBlank(id)) {
|
||||
throw new IllegalArgumentException("Parameter context id cannot be null or blank");
|
||||
}
|
||||
|
||||
return executeAction("Error retrieving parameter context", () -> {
|
||||
final WebTarget target = paramContextTarget.path("{id}")
|
||||
.resolveTemplate("id", id);
|
||||
.resolveTemplate("id", id)
|
||||
.queryParam("includeInheritedParameters", String.valueOf(includeInheritedParameters));
|
||||
return getRequestBuilder(target).get(ParameterContextEntity.class);
|
||||
});
|
||||
}
|
||||
|
@ -115,6 +115,8 @@ public enum CommandOption {
|
||||
PARAM_CONTEXT_ID("pcid", "paramContextId", "The id of a parameter context", true),
|
||||
PARAM_CONTEXT_NAME("pcn", "paramContextName", "The name of a parameter context", true),
|
||||
PARAM_CONTEXT_DESC("pcd", "paramContextDescription", "The description of a parameter context", true),
|
||||
PARAM_CONTEXT_INCLUDE_INHERITED("pcin", "paramContextIncludeInherited", "Indicates that all inherited parameters should be included", false),
|
||||
PARAM_CONTEXT_INHERITED_IDS("pcii", "paramContextInheritedIds", "A comma-separated list of parameter context IDs to inherit", true),
|
||||
|
||||
PARAM_NAME("pn", "paramName", "The name of the parameter", true),
|
||||
PARAM_DESC("pd", "paramDescription", "The description of the parameter", true),
|
||||
|
@ -42,12 +42,14 @@ import org.apache.nifi.toolkit.cli.impl.command.nifi.nodes.GetNode;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.nodes.GetNodes;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.ExportParamContext;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.ImportParamContext;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.RemoveInheritedParamContexts;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.SetParam;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.DeleteParam;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.DeleteParamContext;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.GetParamContext;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.ListParamContexts;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.MergeParamContext;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.params.SetInheritedParamContexts;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.pg.PGChangeVersion;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.pg.PGCreateControllerService;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.nifi.pg.PGDisableControllerServices;
|
||||
@ -154,6 +156,8 @@ public class NiFiCommandGroup extends AbstractCommandGroup {
|
||||
commands.add(new GetParamContext());
|
||||
commands.add(new CreateParamContext());
|
||||
commands.add(new DeleteParamContext());
|
||||
commands.add(new SetInheritedParamContexts());
|
||||
commands.add(new RemoveInheritedParamContexts());
|
||||
commands.add(new SetParam());
|
||||
commands.add(new DeleteParam());
|
||||
commands.add(new ExportParamContext());
|
||||
|
@ -63,7 +63,7 @@ public class DeleteParam extends AbstractUpdateParamContextCommand<VoidResult> {
|
||||
|
||||
// Ensure the context exists...
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingEntity = paramContextClient.getParamContext(paramContextId);
|
||||
final ParameterContextEntity existingEntity = paramContextClient.getParamContext(paramContextId, false);
|
||||
|
||||
// Determine if this is an existing param or a new one...
|
||||
final Optional<ParameterDTO> existingParam = existingEntity.getComponent().getParameters().stream()
|
||||
|
@ -53,7 +53,7 @@ public class DeleteParamContext extends AbstractNiFiCommand<StringResult> {
|
||||
final String paramContextId = getRequiredArg(properties, CommandOption.PARAM_CONTEXT_ID);
|
||||
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingParamContext = paramContextClient.getParamContext(paramContextId);
|
||||
final ParameterContextEntity existingParamContext = paramContextClient.getParamContext(paramContextId, false);
|
||||
|
||||
final String version = String.valueOf(existingParamContext.getRevision().getVersion());
|
||||
paramContextClient.deleteParamContext(paramContextId, version);
|
||||
|
@ -30,6 +30,7 @@ import org.apache.nifi.toolkit.cli.impl.util.JacksonUtils;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterEntity;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
@ -66,7 +67,7 @@ public class ExportParamContext extends AbstractNiFiCommand<ExportParamContext.E
|
||||
|
||||
// retrieve the context by id
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity parameterContextEntity = paramContextClient.getParamContext(paramContextId);
|
||||
final ParameterContextEntity parameterContextEntity = paramContextClient.getParamContext(paramContextId, false);
|
||||
|
||||
// clear out values that don't make sense for importing to next environment
|
||||
final ParameterContextDTO parameterContext = parameterContextEntity.getComponent();
|
||||
@ -80,6 +81,16 @@ public class ExportParamContext extends AbstractNiFiCommand<ExportParamContext.E
|
||||
parameterDTO.setValue(null);
|
||||
}
|
||||
parameterEntity.setCanWrite(null);
|
||||
|
||||
parameterDTO.setParameterContext(null);
|
||||
}
|
||||
|
||||
if (parameterContext.getInheritedParameterContexts() != null) {
|
||||
for (final ParameterContextReferenceEntity ref : parameterContext.getInheritedParameterContexts()) {
|
||||
ref.setId(null);
|
||||
ref.setPermissions(null);
|
||||
ref.getComponent().setId(null);
|
||||
}
|
||||
}
|
||||
|
||||
// sort the entities so that each export is in consistent order
|
||||
|
@ -44,14 +44,16 @@ public class GetParamContext extends AbstractNiFiCommand<ParamContextResult> {
|
||||
@Override
|
||||
protected void doInitialize(Context context) {
|
||||
addOption(CommandOption.PARAM_CONTEXT_ID.createOption());
|
||||
addOption(CommandOption.PARAM_CONTEXT_INCLUDE_INHERITED.createOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParamContextResult doExecute(final NiFiClient client, final Properties properties)
|
||||
throws NiFiClientException, IOException, MissingOptionException, CommandException {
|
||||
final String paramContextId = getRequiredArg(properties, CommandOption.PARAM_CONTEXT_ID);
|
||||
final boolean includeInheritedParameters = hasArg(properties, CommandOption.PARAM_CONTEXT_INCLUDE_INHERITED);
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity parameterContext = paramContextClient.getParamContext(paramContextId);
|
||||
return new ParamContextResult(getResultType(properties), parameterContext);
|
||||
final ParameterContextEntity parameterContext = paramContextClient.getParamContext(paramContextId, includeInheritedParameters);
|
||||
return new ParamContextResult(getResultType(properties), parameterContext, includeInheritedParameters);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ public class ImportParamContext extends AbstractNiFiCommand<StringResult> {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Imports a parameter context using the output from the export-param-context command as the context to import. " +
|
||||
"If the context name and context description arguments are specified, they will override what is in the context json. ";
|
||||
"If the context name and context description arguments are specified, they will override what is in the context json. " +
|
||||
"All inherited parameter contexts are expected to have been imported already, otherwise the operation will fail.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +46,8 @@ public class MergeParamContext extends AbstractUpdateParamContextCommand<VoidRes
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Adds any parameters that exist in the exported context that don't exist in the existing context.";
|
||||
return "Adds any parameters that exist in the exported context that don't exist in the existing context. Overwrites any " +
|
||||
"existing inherited parameter contexts with the provided list.";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,7 +76,7 @@ public class MergeParamContext extends AbstractUpdateParamContextCommand<VoidRes
|
||||
|
||||
// retrieve the existing context by id
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingContextEntity = paramContextClient.getParamContext(existingContextId);
|
||||
final ParameterContextEntity existingContextEntity = paramContextClient.getParamContext(existingContextId, false);
|
||||
|
||||
final ParameterContextDTO existingContext = existingContextEntity.getComponent();
|
||||
if (existingContext.getParameters() == null) {
|
||||
@ -110,6 +111,10 @@ public class MergeParamContext extends AbstractUpdateParamContextCommand<VoidRes
|
||||
updatedContextEntity.setComponent(updatedContextDto);
|
||||
updatedContextEntity.setRevision(existingContextEntity.getRevision());
|
||||
|
||||
if (incomingContext.getInheritedParameterContexts() != null) {
|
||||
updatedContextDto.setInheritedParameterContexts(incomingContext.getInheritedParameterContexts());
|
||||
}
|
||||
|
||||
// Submit the update request...
|
||||
final ParameterContextUpdateRequestEntity updateRequestEntity = paramContextClient.updateParamContext(updatedContextEntity);
|
||||
performUpdate(paramContextClient, updatedContextEntity, updateRequestEntity);
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.toolkit.cli.impl.command.nifi.params;
|
||||
|
||||
import org.apache.commons.cli.MissingOptionException;
|
||||
import org.apache.nifi.toolkit.cli.api.CommandException;
|
||||
import org.apache.nifi.toolkit.cli.api.Context;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.ParamContextClient;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.CommandOption;
|
||||
import org.apache.nifi.toolkit.cli.impl.result.VoidResult;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextUpdateRequestEntity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class RemoveInheritedParamContexts extends AbstractUpdateParamContextCommand<VoidResult> {
|
||||
|
||||
public RemoveInheritedParamContexts() {
|
||||
super("remove-inherited-param-contexts", VoidResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Removes all inherited parameter contexts from the given parameter context";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInitialize(Context context) {
|
||||
super.doInitialize(context);
|
||||
addOption(CommandOption.PARAM_CONTEXT_ID.createOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoidResult doExecute(final NiFiClient client, final Properties properties)
|
||||
throws NiFiClientException, IOException, MissingOptionException, CommandException {
|
||||
|
||||
// Required args...
|
||||
final String paramContextId = getRequiredArg(properties, CommandOption.PARAM_CONTEXT_ID);
|
||||
|
||||
// Ensure the context exists...
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingParameterContextEntity = paramContextClient.getParamContext(paramContextId, false);
|
||||
|
||||
final ParameterContextDTO parameterContextDTO = new ParameterContextDTO();
|
||||
parameterContextDTO.setId(existingParameterContextEntity.getId());
|
||||
parameterContextDTO.setParameters(existingParameterContextEntity.getComponent().getParameters());
|
||||
|
||||
final ParameterContextEntity updatedParameterContextEntity = new ParameterContextEntity();
|
||||
updatedParameterContextEntity.setId(paramContextId);
|
||||
updatedParameterContextEntity.setComponent(parameterContextDTO);
|
||||
updatedParameterContextEntity.setRevision(existingParameterContextEntity.getRevision());
|
||||
|
||||
final List<ParameterContextReferenceEntity> referenceEntities = new ArrayList<>();
|
||||
parameterContextDTO.setInheritedParameterContexts(referenceEntities);
|
||||
|
||||
// Submit the update request...
|
||||
final ParameterContextUpdateRequestEntity updateRequestEntity = paramContextClient.updateParamContext(updatedParameterContextEntity);
|
||||
performUpdate(paramContextClient, updatedParameterContextEntity, updateRequestEntity);
|
||||
|
||||
if (isInteractive()) {
|
||||
println();
|
||||
}
|
||||
|
||||
return VoidResult.getInstance();
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.toolkit.cli.impl.command.nifi.params;
|
||||
|
||||
import org.apache.commons.cli.MissingOptionException;
|
||||
import org.apache.nifi.toolkit.cli.api.CommandException;
|
||||
import org.apache.nifi.toolkit.cli.api.Context;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClientException;
|
||||
import org.apache.nifi.toolkit.cli.impl.client.nifi.ParamContextClient;
|
||||
import org.apache.nifi.toolkit.cli.impl.command.CommandOption;
|
||||
import org.apache.nifi.toolkit.cli.impl.result.VoidResult;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextDTO;
|
||||
import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
|
||||
import org.apache.nifi.web.api.entity.ParameterContextUpdateRequestEntity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class SetInheritedParamContexts extends AbstractUpdateParamContextCommand<VoidResult> {
|
||||
|
||||
public SetInheritedParamContexts() {
|
||||
super("set-inherited-param-contexts", VoidResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Sets a list of parameter context ids from which the given parameter context should inherit parameters";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInitialize(Context context) {
|
||||
super.doInitialize(context);
|
||||
addOption(CommandOption.PARAM_CONTEXT_ID.createOption());
|
||||
addOption(CommandOption.PARAM_CONTEXT_INHERITED_IDS.createOption());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoidResult doExecute(final NiFiClient client, final Properties properties)
|
||||
throws NiFiClientException, IOException, MissingOptionException, CommandException {
|
||||
|
||||
// Required args...
|
||||
final String paramContextId = getRequiredArg(properties, CommandOption.PARAM_CONTEXT_ID);
|
||||
final String inheritedIds = getRequiredArg(properties, CommandOption.PARAM_CONTEXT_INHERITED_IDS);
|
||||
|
||||
// Ensure the context exists...
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingParameterContextEntity = paramContextClient.getParamContext(paramContextId, false);
|
||||
|
||||
final String[] inheritedIdArray = inheritedIds.split(",");
|
||||
final List<ParameterContextReferenceEntity> referenceEntities = new ArrayList<>();
|
||||
for(final String inheritedId : inheritedIdArray) {
|
||||
final ParameterContextEntity existingInheritedEntity = paramContextClient.getParamContext(inheritedId, false);
|
||||
final ParameterContextReferenceEntity parameterContextReferenceEntity = new ParameterContextReferenceEntity();
|
||||
parameterContextReferenceEntity.setId(existingInheritedEntity.getId());
|
||||
|
||||
final ParameterContextReferenceDTO parameterContextReferenceDTO = new ParameterContextReferenceDTO();
|
||||
parameterContextReferenceDTO.setName(existingInheritedEntity.getComponent().getName());
|
||||
parameterContextReferenceDTO.setId(existingInheritedEntity.getComponent().getId());
|
||||
parameterContextReferenceEntity.setComponent(parameterContextReferenceDTO);
|
||||
|
||||
referenceEntities.add(parameterContextReferenceEntity);
|
||||
}
|
||||
|
||||
final ParameterContextDTO parameterContextDTO = new ParameterContextDTO();
|
||||
parameterContextDTO.setId(existingParameterContextEntity.getId());
|
||||
parameterContextDTO.setParameters(existingParameterContextEntity.getComponent().getParameters());
|
||||
|
||||
final ParameterContextEntity updatedParameterContextEntity = new ParameterContextEntity();
|
||||
updatedParameterContextEntity.setId(paramContextId);
|
||||
updatedParameterContextEntity.setComponent(parameterContextDTO);
|
||||
updatedParameterContextEntity.setRevision(existingParameterContextEntity.getRevision());
|
||||
|
||||
parameterContextDTO.setInheritedParameterContexts(referenceEntities);
|
||||
|
||||
// Submit the update request...
|
||||
final ParameterContextUpdateRequestEntity updateRequestEntity = paramContextClient.updateParamContext(updatedParameterContextEntity);
|
||||
performUpdate(paramContextClient, updatedParameterContextEntity, updateRequestEntity);
|
||||
|
||||
if (isInteractive()) {
|
||||
println();
|
||||
}
|
||||
|
||||
return VoidResult.getInstance();
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ public class SetParam extends AbstractUpdateParamContextCommand<VoidResult> {
|
||||
|
||||
// Ensure the context exists...
|
||||
final ParamContextClient paramContextClient = client.getParamContextClient();
|
||||
final ParameterContextEntity existingParameterContextEntity = paramContextClient.getParamContext(paramContextId);
|
||||
final ParameterContextEntity existingParameterContextEntity = paramContextClient.getParamContext(paramContextId, false);
|
||||
final ParameterContextDTO existingParameterContextDTO = existingParameterContextEntity.getComponent();
|
||||
|
||||
// Determine if this is an existing param or a new one...
|
||||
|
@ -37,10 +37,13 @@ import java.util.stream.Collectors;
|
||||
public class ParamContextResult extends AbstractWritableResult<ParameterContextEntity> {
|
||||
|
||||
private final ParameterContextEntity parameterContext;
|
||||
private final boolean includeParameterContextSource;
|
||||
|
||||
public ParamContextResult(final ResultType resultType, final ParameterContextEntity parameterContext) {
|
||||
public ParamContextResult(final ResultType resultType, final ParameterContextEntity parameterContext,
|
||||
final boolean includeParameterContextSource) {
|
||||
super(resultType);
|
||||
this.parameterContext = parameterContext;
|
||||
this.includeParameterContextSource = includeParameterContextSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,21 +57,34 @@ public class ParamContextResult extends AbstractWritableResult<ParameterContextE
|
||||
.map(p -> p.getParameter())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final List<ParameterDTO> sortedParams =paramDTOs.stream()
|
||||
.sorted(Comparator.comparing(ParameterDTO::getName))
|
||||
final List<ParameterDTO> sortedParams = paramDTOs.stream()
|
||||
.sorted(Comparator
|
||||
.comparing((ParameterDTO param) -> // Direct parameters first
|
||||
param.getParameterContext().getComponent().getId().equals((this.parameterContext.getComponent().getId())))
|
||||
.reversed()
|
||||
.thenComparing(ParameterDTO::getName))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final Table table = new Table.Builder()
|
||||
final Table.Builder tableBuilder = new Table.Builder()
|
||||
.column("#", 3, 3, false)
|
||||
.column("Name", 20, 60, false)
|
||||
.column("Value", 20, 80, false)
|
||||
.column("Sensitive", 10, 10, false)
|
||||
.column("Description", 20, 80, true)
|
||||
.column("Sensitive", 10, 10, false);
|
||||
|
||||
if (includeParameterContextSource) {
|
||||
tableBuilder.column("Source Parameter Context", 25, 40, true);
|
||||
}
|
||||
final Table table = tableBuilder.column("Description", 20, 80, true)
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < sortedParams.size(); i++) {
|
||||
final ParameterDTO r = sortedParams.get(i);
|
||||
table.addRow(String.valueOf(i+1), r.getName(), r.getValue(), r.getSensitive().toString(), r.getDescription());
|
||||
final String[] row = includeParameterContextSource
|
||||
? new String[] { String.valueOf(i+1), r.getName(), r.getValue(), r.getSensitive().toString(),
|
||||
r.getParameterContext().getComponent().getName(), r.getDescription() }
|
||||
: new String[] { String.valueOf(i+1), r.getName(), r.getValue(), r.getSensitive().toString(),
|
||||
r.getDescription() };
|
||||
table.addRow(row);
|
||||
}
|
||||
|
||||
final TableWriter tableWriter = new DynamicTableWriter();
|
||||
|
@ -40,6 +40,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ParamContextsResult extends AbstractWritableResult<ParameterContextsEntity> implements Referenceable {
|
||||
|
||||
@ -75,12 +76,15 @@ public class ParamContextsResult extends AbstractWritableResult<ParameterContext
|
||||
.column("#", 3, 3, false)
|
||||
.column("Id", 36, 36, false)
|
||||
.column("Name", 20, 60, true)
|
||||
.column("Inherited Param Contexts", 20, 60, true)
|
||||
.column("Description", 40, 60, true)
|
||||
.build();
|
||||
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
final ParameterContextDTO r = results.get(i);
|
||||
table.addRow("" + (i+1), r.getId(), r.getName(), r.getDescription());
|
||||
final String inheritedParamContexts = r.getInheritedParameterContexts() == null ? ""
|
||||
: r.getInheritedParameterContexts().stream().map(pc -> pc.getComponent().getName()).collect(Collectors.joining(", "));
|
||||
table.addRow("" + (i+1), r.getId(), r.getName(), inheritedParamContexts, r.getDescription());
|
||||
}
|
||||
|
||||
final TableWriter tableWriter = new DynamicTableWriter();
|
||||
|
Loading…
x
Reference in New Issue
Block a user