NIFI-6382: Allow Parameters to have null values

Signed-off-by: Bryan Bende <bbende@apache.org>
This commit is contained in:
Mark Payne 2019-08-08 10:54:03 -04:00 committed by Bryan Bende
parent 9c8f40415e
commit bcf373a049
No known key found for this signature in database
GPG Key ID: A0DDA9ED50711C39
25 changed files with 530 additions and 153 deletions

View File

@ -106,4 +106,12 @@ public interface ValidationContext extends PropertyContext {
* @return <code>true</code> if a Parameter with the given name is defined in the currently selected Parameter Context * @return <code>true</code> if a Parameter with the given name is defined in the currently selected Parameter Context
*/ */
boolean isParameterDefined(String parameterName); boolean isParameterDefined(String parameterName);
/**
* Returns <code>true</code> if a Parameter with the given name is defined and has a non-null value, <code>false</code> if either the Parameter
* is not defined or the Parameter is defined but has a value of <code>null</code>.
* @param parameterName the name of the parameter
* @return <code>true</code> if the Parameter is defined and has a non-null value, false otherwise
*/
boolean isParameterSet(String parameterName);
} }

View File

@ -133,4 +133,9 @@ public class NotificationValidationContext implements ValidationContext {
public boolean isParameterDefined(final String parameterName) { public boolean isParameterDefined(final String parameterName) {
return false; return false;
} }
@Override
public boolean isParameterSet(final String parameterName) {
return false;
}
} }

View File

@ -181,8 +181,12 @@ public class MockValidationContext extends MockControllerServiceLookup implement
@Override @Override
public boolean isParameterDefined(final String parameterName) { public boolean isParameterDefined(final String parameterName) {
// TODO: Implement return true;
return false; }
@Override
public boolean isParameterSet(final String parameterName) {
return true;
} }
} }

View File

@ -16,13 +16,26 @@
*/ */
package org.apache.nifi.util.db; package org.apache.nifi.util.db;
import static org.junit.Assert.assertEquals; import org.apache.avro.Conversions;
import static org.junit.Assert.assertNotNull; import org.apache.avro.LogicalType;
import static org.junit.Assert.assertNull; import org.apache.avro.LogicalTypes;
import static org.junit.Assert.assertTrue; import org.apache.avro.Schema;
import static org.mockito.ArgumentMatchers.anyInt; import org.apache.avro.file.DataFileStream;
import static org.mockito.Mockito.mock; import org.apache.avro.generic.GenericData;
import static org.mockito.Mockito.when; import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.util.Utf8;
import org.apache.commons.io.input.ReaderInputStream;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -63,26 +76,13 @@ import java.util.function.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import org.apache.avro.Conversions; import static org.junit.Assert.assertEquals;
import org.apache.avro.LogicalType; import static org.junit.Assert.assertNotNull;
import org.apache.avro.LogicalTypes; import static org.junit.Assert.assertNull;
import org.apache.avro.Schema; import static org.junit.Assert.assertTrue;
import org.apache.avro.file.DataFileStream; import static org.mockito.ArgumentMatchers.anyInt;
import org.apache.avro.generic.GenericData; import static org.mockito.Mockito.mock;
import org.apache.avro.generic.GenericDatumReader; import static org.mockito.Mockito.when;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.util.Utf8;
import org.apache.commons.io.input.ReaderInputStream;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestJdbcCommon { public class TestJdbcCommon {

View File

@ -659,6 +659,14 @@ public abstract class AbstractComponentNode implements ComponentNode {
.explanation("Property references Parameter '" + paramName + "' but the currently selected Parameter Context does not have a Parameter with that name") .explanation("Property references Parameter '" + paramName + "' but the currently selected Parameter Context does not have a Parameter with that name")
.build()); .build());
} }
if (!validationContext.isParameterSet(paramName)) {
results.add(new ValidationResult.Builder()
.subject(propertyDescriptor.getDisplayName())
.valid(false)
.explanation("Property references Parameter '" + paramName + "' but the currently selected Parameter Context does not have a value set for that Parameter")
.build());
}
} }
} }

View File

@ -36,6 +36,7 @@ import org.apache.nifi.web.api.dto.FlowSnippetDTO;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@ -322,7 +323,7 @@ public interface FlowManager {
void removeRootControllerService(final ControllerServiceNode service); void removeRootControllerService(final ControllerServiceNode service);
ParameterContext createParameterContext(String id, String name, Set<Parameter> parameters); ParameterContext createParameterContext(String id, String name, Map<String, Parameter> parameters);
ParameterContextManager getParameterContextManager(); ParameterContextManager getParameterContextManager();
} }

View File

@ -20,7 +20,6 @@ import org.apache.nifi.authorization.resource.Authorizable;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
public interface ParameterContext extends ParameterLookup, Authorizable { public interface ParameterContext extends ParameterLookup, Authorizable {
@ -52,19 +51,22 @@ public interface ParameterContext extends ParameterLookup, Authorizable {
void setDescription(String description); void setDescription(String description);
/** /**
* Updates the Parameters within this context to match the given set of Parameters. * Updates the Parameters within this context to match the given set of Parameters. If the Parameter Context contains any parameters that are not in
* @param updatedParameters the updated set of parameters * the given set of updated Parameters, those parameters are unaffected. However, if the Map contains any key with a <code>null</code> value, the
* parameter whose name is given by the key will be removed
*
* @param updatedParameters the updated set of parameters, keyed by Parameter name
* @throws IllegalStateException if any parameter is modified or removed and that parameter is being referenced by a running Processor or an enabled Controller Service, or if * @throws IllegalStateException if any parameter is modified or removed and that parameter is being referenced by a running Processor or an enabled Controller Service, or if
* an update would result in changing the sensitivity of any parameter * an update would result in changing the sensitivity of any parameter
*/ */
void setParameters(Set<Parameter> updatedParameters); void setParameters(Map<String, Parameter> updatedParameters);
/** /**
* Ensures that it is legal to update the Parameters for this Parameter Context to match the given set of Parameters * Ensures that it is legal to update the Parameters for this Parameter Context to match the given set of Parameters
* @param parameters the Set of Parameters that are to become the new Parameters for this Parameter Context * @param parameters the updated set of parameters, keyed by Parameter name
* @throws IllegalStateException if setting the given set of Parameters is not legal * @throws IllegalStateException if setting the given set of Parameters is not legal
*/ */
void verifyCanSetParameters(Set<Parameter> parameters); void verifyCanSetParameters(Map<String, Parameter> parameters);
/** /**

View File

@ -131,6 +131,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@ -547,10 +548,10 @@ public class StandardFlowSynchronizer implements FlowSynchronizer {
} }
private ParameterContext createParameterContext(final ParameterContextDTO dto, final FlowManager flowManager) { private ParameterContext createParameterContext(final ParameterContextDTO dto, final FlowManager flowManager) {
final Set<Parameter> parameters = dto.getParameters().stream() final Map<String, Parameter> parameters = dto.getParameters().stream()
.map(ParameterEntity::getParameter) .map(ParameterEntity::getParameter)
.map(this::createParameter) .map(this::createParameter)
.collect(Collectors.toSet()); .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);
context.setDescription(dto.getDescription()); context.setDescription(dto.getDescription());

View File

@ -736,7 +736,7 @@ public class StandardFlowManager implements FlowManager {
} }
@Override @Override
public ParameterContext createParameterContext(final String id, final String name, final Set<Parameter> parameters) { public ParameterContext createParameterContext(final String id, final String name, final Map<String, Parameter> parameters) {
final boolean namingConflict = parameterContextManager.getParameterContexts().stream() final boolean namingConflict = parameterContextManager.getParameterContexts().stream()
.anyMatch(paramContext -> paramContext.getName().equals(name)); .anyMatch(paramContext -> paramContext.getName().equals(name));

View File

@ -34,7 +34,6 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
@ -97,32 +96,26 @@ public class StandardParameterContext implements ParameterContext {
return description; return description;
} }
public void setParameters(final Set<Parameter> updatedParameters) { public void setParameters(final Map<String, Parameter> updatedParameters) {
writeLock.lock(); writeLock.lock();
try { try {
this.version++; this.version++;
verifyCanSetParameters(updatedParameters); verifyCanSetParameters(updatedParameters);
boolean changeAffectingComponents = false; boolean changeAffectingComponents = false;
for (final Parameter parameter : updatedParameters) { for (final Map.Entry<String, Parameter> entry : updatedParameters.entrySet()) {
if (parameter.getValue() == null && parameter.getDescriptor().getDescription() == null) { final String parameterName = entry.getKey();
parameters.remove(parameter.getDescriptor()); final Parameter parameter = entry.getValue();
changeAffectingComponents = true;
} else if (parameter.getValue() == null) {
// Value is null but description is not. Just update the description of the existing Parameter.
final Parameter existingParameter = parameters.get(parameter.getDescriptor());
final ParameterDescriptor existingDescriptor = existingParameter.getDescriptor();
final ParameterDescriptor replacementDescriptor = new ParameterDescriptor.Builder()
.from(existingDescriptor)
.description(parameter.getDescriptor().getDescription())
.build();
final Parameter replacementParameter = new Parameter(replacementDescriptor, existingParameter.getValue()); if (parameter == null) {
parameters.put(parameter.getDescriptor(), replacementParameter); final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder().name(parameterName).build();
} else { parameters.remove(parameterDescriptor);
parameters.put(parameter.getDescriptor(), parameter);
changeAffectingComponents = true; changeAffectingComponents = true;
} else {
final Parameter oldParameter = parameters.put(parameter.getDescriptor(), parameter);
if (oldParameter == null || !Objects.equals(oldParameter.getValue(), parameter.getValue())) {
changeAffectingComponents = true;
}
} }
} }
@ -195,25 +188,23 @@ public class StandardParameterContext implements ParameterContext {
} }
@Override @Override
public void verifyCanSetParameters(final Set<Parameter> updatedParameters) { public void verifyCanSetParameters(final Map<String, Parameter> updatedParameters) {
// Ensure that the updated parameters will not result in changing the sensitivity flag of any parameter. // Ensure that the updated parameters will not result in changing the sensitivity flag of any parameter.
for (final Parameter updatedParameter : updatedParameters) { for (final Map.Entry<String, Parameter> entry : updatedParameters.entrySet()) {
validateSensitiveFlag(updatedParameter); final String parameterName = entry.getKey();
final Parameter parameter = entry.getValue();
// Parameters' names and sensitivity flags are immutable. However, the description and value are mutable. If both value and description are if (parameter == null) {
// set to `null`, this is the indication that the Parameter should be removed. If the value is `null` but the Description is supplied, the user // parameter is being deleted.
// is indicating that only the description is to be changed. validateReferencingComponents(parameterName, null,"remove");
if (updatedParameter.getValue() == null && updatedParameter.getDescriptor().getDescription() == null) { continue;
validateReferencingComponents(updatedParameter, "remove");
} else if (updatedParameter.getValue() != null) {
validateReferencingComponents(updatedParameter, "update");
} else {
// Only parameter is changing. No value is set. This means that the Parameter must already exist.
final Optional<Parameter> existing = getParameter(updatedParameter.getDescriptor());
if (!existing.isPresent()) {
throw new IllegalStateException("Cannot add Parameter '" + updatedParameter.getDescriptor().getName() + "' without providing a value");
}
} }
if (!Objects.equals(parameterName, parameter.getDescriptor().getName())) {
throw new IllegalArgumentException("Parameter '" + parameterName + "' was specified with the wrong key in the Map");
}
validateSensitiveFlag(parameter);
validateReferencingComponents(parameterName, parameter, "update");
} }
} }
@ -236,25 +227,27 @@ public class StandardParameterContext implements ParameterContext {
} }
private void validateReferencingComponents(final Parameter updatedParameter, final String parameterAction) { private void validateReferencingComponents(final String parameterName, final Parameter parameter, final String parameterAction) {
final String paramName = updatedParameter.getDescriptor().getName(); for (final ProcessorNode procNode : parameterReferenceManager.getProcessorsReferencing(this, parameterName)) {
for (final ProcessorNode procNode : parameterReferenceManager.getProcessorsReferencing(this, paramName)) {
if (procNode.isRunning()) { if (procNode.isRunning()) {
throw new IllegalStateException("Cannot " + parameterAction + " parameter '" + paramName + "' because it is referenced by " + procNode + ", which is currently running"); throw new IllegalStateException("Cannot " + parameterAction + " parameter '" + parameterName + "' because it is referenced by " + procNode + ", which is currently running");
} }
validateParameterSensitivity(updatedParameter, procNode); if (parameter != null) {
validateParameterSensitivity(parameter, procNode);
}
} }
for (final ControllerServiceNode serviceNode : parameterReferenceManager.getControllerServicesReferencing(this, paramName)) { for (final ControllerServiceNode serviceNode : parameterReferenceManager.getControllerServicesReferencing(this, parameterName)) {
final ControllerServiceState serviceState = serviceNode.getState(); final ControllerServiceState serviceState = serviceNode.getState();
if (serviceState != ControllerServiceState.DISABLED) { if (serviceState != ControllerServiceState.DISABLED) {
throw new IllegalStateException("Cannot " + parameterAction + " parameter '" + paramName + "' because it is referenced by " throw new IllegalStateException("Cannot " + parameterAction + " parameter '" + parameterName + "' because it is referenced by "
+ serviceNode + ", which currently has a state of " + serviceState); + serviceNode + ", which currently has a state of " + serviceState);
} }
validateParameterSensitivity(updatedParameter, serviceNode); if (parameter != null) {
validateParameterSensitivity(parameter, serviceNode);
}
} }
} }

View File

@ -33,6 +33,7 @@ import org.apache.nifi.controller.service.ControllerServiceProvider;
import org.apache.nifi.controller.service.ControllerServiceState; import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.expression.ExpressionLanguageCompiler; import org.apache.nifi.expression.ExpressionLanguageCompiler;
import org.apache.nifi.groups.ProcessGroup; import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterContext; import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterReference; import org.apache.nifi.parameter.ParameterReference;
import org.apache.nifi.registry.VariableRegistry; import org.apache.nifi.registry.VariableRegistry;
@ -43,6 +44,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -216,6 +218,21 @@ public class StandardValidationContext implements ValidationContext {
return parameterContext.getParameter(parameterName).isPresent(); return parameterContext.getParameter(parameterName).isPresent();
} }
@Override
public boolean isParameterSet(final String parameterName) {
if (parameterContext == null) {
return false;
}
final Optional<Parameter> parameterOption = parameterContext.getParameter(parameterName);
if (!parameterOption.isPresent()) {
return false;
}
final String value = parameterOption.get().getValue();
return value != null;
}
@Override @Override
public String toString() { public String toString() {
return "StandardValidationContext[componentId=" + componentId + ", properties=" + properties + "]"; return "StandardValidationContext[componentId=" + componentId + ", properties=" + properties + "]";

View File

@ -550,6 +550,11 @@ public class TestStandardProcessorNode {
public boolean isParameterDefined(final String parameterName) { public boolean isParameterDefined(final String parameterName) {
return false; return false;
} }
@Override
public boolean isParameterSet(final String parameterName) {
return false;
}
}; };
} }

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.integration.auth;
import org.apache.nifi.authentication.AuthenticationResponse;
import org.apache.nifi.authentication.LoginCredentials;
import org.apache.nifi.authentication.LoginIdentityProvider;
import org.apache.nifi.authentication.LoginIdentityProviderConfigurationContext;
import org.apache.nifi.authentication.LoginIdentityProviderInitializationContext;
import org.apache.nifi.authentication.exception.IdentityAccessException;
import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import org.apache.nifi.authentication.exception.ProviderDestructionException;
public class AlwaysAuthenticate implements LoginIdentityProvider {
@Override
public AuthenticationResponse authenticate(final LoginCredentials credentials) throws InvalidLoginCredentialsException, IdentityAccessException {
return new AuthenticationResponse(credentials.getUsername(), credentials.getUsername(), 1_000_000L, "unit-test-issuer");
}
@Override
public void initialize(final LoginIdentityProviderInitializationContext initializationContext) throws ProviderCreationException {
}
@Override
public void onConfigured(final LoginIdentityProviderConfigurationContext configurationContext) throws ProviderCreationException {
}
@Override
public void preDestruction() throws ProviderDestructionException {
}
}

View File

@ -0,0 +1,118 @@
/*
* 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.integration.auth;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.AccessPolicyProvider;
import org.apache.nifi.authorization.AccessPolicyProviderInitializationContext;
import org.apache.nifi.authorization.AuthorizerConfigurationContext;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class VolatileAccessPolicyProvider implements AccessPolicyProvider {
private final VolatileUserGroupProvider userGroupProvider = new VolatileUserGroupProvider();
private Set<AccessPolicy> accessPolicies = new HashSet<>();
public synchronized void grantAccess(final String user, final String resourceIdentifier, final RequestAction action) {
final AccessPolicy existingPolicy = getAccessPolicy(resourceIdentifier, action);
final AccessPolicy policy;
if (existingPolicy == null) {
policy = new AccessPolicy.Builder()
.addUser(user)
.action(action)
.identifierGenerateRandom()
.resource(resourceIdentifier)
.build();
} else {
policy = new AccessPolicy.Builder()
.addUsers(existingPolicy.getUsers())
.addUser(user)
.action(action)
.identifier(existingPolicy.getIdentifier())
.resource(resourceIdentifier)
.build();
}
accessPolicies.remove(existingPolicy);
accessPolicies.add(policy);
}
public synchronized void revokeAccess(final String user, final String resourceIdentifier, final RequestAction action) {
final AccessPolicy existingPolicy = getAccessPolicy(resourceIdentifier, action);
if (existingPolicy == null) {
return;
}
final AccessPolicy policy= new AccessPolicy.Builder()
.addUsers(existingPolicy.getUsers())
.removeUser(user)
.action(action)
.identifier(existingPolicy.getIdentifier())
.resource(resourceIdentifier)
.build();
accessPolicies.remove(existingPolicy);
accessPolicies.add(policy);
}
@Override
public synchronized Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
return new HashSet<>(accessPolicies);
}
@Override
public synchronized AccessPolicy getAccessPolicy(final String identifier) throws AuthorizationAccessException {
return accessPolicies.stream()
.filter(policy -> policy.getIdentifier().equals(identifier))
.findAny()
.orElse(null);
}
@Override
public synchronized AccessPolicy getAccessPolicy(final String resourceIdentifier, final RequestAction action) throws AuthorizationAccessException {
return accessPolicies.stream()
.filter(policy -> Objects.equals(policy.getResource(), resourceIdentifier))
.filter(policy -> Objects.equals(policy.getAction(), action))
.findAny()
.orElse(null);
}
@Override
public synchronized VolatileUserGroupProvider getUserGroupProvider() {
return userGroupProvider;
}
@Override
public void initialize(final AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
}
@Override
public void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
}
}

View File

@ -0,0 +1,111 @@
/*
* 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.integration.auth;
import org.apache.nifi.authorization.AuthorizerConfigurationContext;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.UserAndGroups;
import org.apache.nifi.authorization.UserGroupProvider;
import org.apache.nifi.authorization.UserGroupProviderInitializationContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class VolatileUserGroupProvider implements UserGroupProvider {
private final Map<String, User> users = new HashMap<>();
private final Map<String, Group> groups = new HashMap<>();
private final Map<User, Set<Group>> userGroupMapping = new HashMap<>();
public void addUser(final User user) {
this.users.put(user.getIdentifier(), user);
}
public void addGroup(final Group group) {
this.groups.put(group.getIdentifier(), group);
}
public void addUserToGroup(final User user, final Group group) {
userGroupMapping.computeIfAbsent(user, i -> new HashSet<>()).add(group);
}
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
return new HashSet<>(users.values());
}
@Override
public User getUser(final String identifier) throws AuthorizationAccessException {
return users.get(identifier);
}
@Override
public User getUserByIdentity(final String identity) throws AuthorizationAccessException {
return users.values().stream()
.filter(user -> Objects.equals(identity, user.getIdentity()))
.findFirst()
.orElse(null);
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
return new HashSet<>(groups.values());
}
@Override
public Group getGroup(final String identifier) throws AuthorizationAccessException {
return groups.get(identifier);
}
@Override
public UserAndGroups getUserAndGroups(final String identity) throws AuthorizationAccessException {
final User user = getUserByIdentity(identity);
final Set<Group> groups = userGroupMapping.get(user);
final Set<Group> groupCopy = groups == null ? Collections.emptySet() : new HashSet<>(groups);
return new UserAndGroups() {
@Override
public User getUser() {
return user;
}
@Override
public Set<Group> getGroups() {
return groupCopy;
}
};
}
@Override
public void initialize(final UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException {
}
@Override
public void onConfigured(final AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
}
}

View File

@ -58,7 +58,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
updateAttribute.setProperties(Collections.singletonMap("test", "#{test}")); updateAttribute.setProperties(Collections.singletonMap("test", "#{test}"));
@ -83,7 +83,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
updateAttribute.setProperties(Collections.singletonMap("test", "${#{test}:toUpper()}")); updateAttribute.setProperties(Collections.singletonMap("test", "${#{test}:toUpper()}"));
@ -108,7 +108,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
updateAttribute.setProperties(Collections.singletonMap("test", "${#{test}:toUpper()}")); updateAttribute.setProperties(Collections.singletonMap("test", "${#{test}:toUpper()}"));
@ -133,7 +133,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -165,7 +165,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -193,7 +193,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -225,7 +225,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -267,7 +267,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -307,7 +307,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
@ -337,7 +337,7 @@ public class ParametersIT extends FrameworkIntegrationTest {
final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager()); final ParameterReferenceManager referenceManager = new StandardParameterReferenceManager(getFlowController().getFlowManager());
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "param-context", referenceManager, null);
parameterContext.setParameters(Collections.singleton(new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit"))); parameterContext.setParameters(Collections.singletonMap("test", new Parameter(new ParameterDescriptor.Builder().name("test").build(), "unit")));
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);

View File

@ -40,7 +40,6 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -77,9 +76,9 @@ public class ProcessorParameterTokenIT extends FrameworkIntegrationTest {
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "testEscapedParameterReference", ParameterReferenceManager.EMPTY, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "testEscapedParameterReference", ParameterReferenceManager.EMPTY, null);
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(new ParameterDescriptor.Builder().name("foo").build(), "bar")); parameters.put("foo", new Parameter(new ParameterDescriptor.Builder().name("foo").build(), "bar"));
parameters.add(new Parameter(new ParameterDescriptor.Builder().name("sensitive").sensitive(true).build(), "*password*")); parameters.put("sensitive", new Parameter(new ParameterDescriptor.Builder().name("sensitive").sensitive(true).build(), "*password*"));
parameterContext.setParameters(parameters); parameterContext.setParameters(parameters);
verifyText(procNode, "hello", "hello"); verifyText(procNode, "hello", "hello");
@ -107,9 +106,9 @@ public class ProcessorParameterTokenIT extends FrameworkIntegrationTest {
final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "testEscapedParameterReference", ParameterReferenceManager.EMPTY, null); final ParameterContext parameterContext = new StandardParameterContext(UUID.randomUUID().toString(), "testEscapedParameterReference", ParameterReferenceManager.EMPTY, null);
getRootGroup().setParameterContext(parameterContext); getRootGroup().setParameterContext(parameterContext);
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(new ParameterDescriptor.Builder().name("foo").build(), "bar")); parameters.put("foo", new Parameter(new ParameterDescriptor.Builder().name("foo").build(), "bar"));
parameters.add(new Parameter(new ParameterDescriptor.Builder().name("sensitive").sensitive(true).build(), "*password*")); parameters.put("sensitive", new Parameter(new ParameterDescriptor.Builder().name("sensitive").sensitive(true).build(), "*password*"));
parameterContext.setParameters(parameters); parameterContext.setParameters(parameters);
verifyCannotSetParameter(procNode, "#{sensitive}", null); verifyCannotSetParameter(procNode, "#{sensitive}", null);

View File

@ -34,6 +34,8 @@ import org.apache.nifi.registry.flow.VersionedControllerService;
import org.apache.nifi.registry.flow.VersionedFlow; import org.apache.nifi.registry.flow.VersionedFlow;
import org.apache.nifi.registry.flow.VersionedFlowSnapshot; import org.apache.nifi.registry.flow.VersionedFlowSnapshot;
import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata; import org.apache.nifi.registry.flow.VersionedFlowSnapshotMetadata;
import org.apache.nifi.registry.flow.VersionedParameter;
import org.apache.nifi.registry.flow.VersionedParameterContext;
import org.apache.nifi.registry.flow.VersionedProcessGroup; import org.apache.nifi.registry.flow.VersionedProcessGroup;
import org.apache.nifi.registry.flow.VersionedProcessor; import org.apache.nifi.registry.flow.VersionedProcessor;
import org.apache.nifi.registry.flow.mapping.NiFiRegistryFlowMapper; import org.apache.nifi.registry.flow.mapping.NiFiRegistryFlowMapper;
@ -44,6 +46,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -70,7 +73,7 @@ public class ImportFlowIT extends FrameworkIntegrationTest {
processor.setAutoTerminatedRelationships(Collections.singleton(REL_SUCCESS)); processor.setAutoTerminatedRelationships(Collections.singleton(REL_SUCCESS));
processor.setProperties(Collections.singletonMap(NopServiceReferencingProcessor.SERVICE.getName(), controllerService.getIdentifier())); processor.setProperties(Collections.singletonMap(NopServiceReferencingProcessor.SERVICE.getName(), controllerService.getIdentifier()));
final VersionedFlowSnapshot proposedFlow = createFlowSnapshot(Collections.singletonList(controllerService), Collections.singletonList(processor)); final VersionedFlowSnapshot proposedFlow = createFlowSnapshot(Collections.singletonList(controllerService), Collections.singletonList(processor), null);
// Create an Inner Process Group and update it to match the Versioned Flow. // Create an Inner Process Group and update it to match the Versioned Flow.
final ProcessGroup innerGroup = getFlowController().getFlowManager().createProcessGroup("inner-group-id"); final ProcessGroup innerGroup = getFlowController().getFlowManager().createProcessGroup("inner-group-id");
@ -107,7 +110,7 @@ public class ImportFlowIT extends FrameworkIntegrationTest {
} }
private VersionedFlowSnapshot createFlowSnapshot(final List<ControllerServiceNode> controllerServices, final List<ProcessorNode> processors) { private VersionedFlowSnapshot createFlowSnapshot(final List<ControllerServiceNode> controllerServices, final List<ProcessorNode> processors, final Map<String, String> parameters) {
final VersionedFlowSnapshotMetadata snapshotMetadata = new VersionedFlowSnapshotMetadata(); final VersionedFlowSnapshotMetadata snapshotMetadata = new VersionedFlowSnapshotMetadata();
snapshotMetadata.setAuthor("unit-test"); snapshotMetadata.setAuthor("unit-test");
snapshotMetadata.setBucketIdentifier("unit-test-bucket"); snapshotMetadata.setBucketIdentifier("unit-test-bucket");
@ -159,6 +162,21 @@ public class ImportFlowIT extends FrameworkIntegrationTest {
versionedFlowSnapshot.setFlow(flow); versionedFlowSnapshot.setFlow(flow);
versionedFlowSnapshot.setFlowContents(flowContents); versionedFlowSnapshot.setFlowContents(flowContents);
if (parameters != null) {
final Set<VersionedParameter> versionedParameters = new HashSet<>();
for (final Map.Entry<String, String> entry : parameters.entrySet()) {
final VersionedParameter versionedParameter = new VersionedParameter();
versionedParameter.setName(entry.getKey());
versionedParameter.setValue(entry.getValue());
versionedParameters.add(versionedParameter);
}
final VersionedParameterContext versionedParameterContext = new VersionedParameterContext();
versionedParameterContext.setName("Unit Test Context");
versionedParameterContext.setParameters(versionedParameters);
versionedFlowSnapshot.setParameterContexts(Collections.singletonMap("unit-test-context", versionedParameterContext));
}
return versionedFlowSnapshot; return versionedFlowSnapshot;
} }
} }

View File

@ -27,7 +27,6 @@ import org.mockito.Mockito;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -47,9 +46,9 @@ public class TestStandardParameterContext {
final ParameterDescriptor xyzDescriptor = new ParameterDescriptor.Builder().name("xyz").build(); final ParameterDescriptor xyzDescriptor = new ParameterDescriptor.Builder().name("xyz").build();
final ParameterDescriptor fooDescriptor = new ParameterDescriptor.Builder().name("foo").description("bar").sensitive(true).build(); final ParameterDescriptor fooDescriptor = new ParameterDescriptor.Builder().name("foo").description("bar").sensitive(true).build();
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
parameters.add(new Parameter(xyzDescriptor, "242526")); parameters.put("xyz", new Parameter(xyzDescriptor, "242526"));
context.setParameters(parameters); context.setParameters(parameters);
@ -63,15 +62,15 @@ public class TestStandardParameterContext {
assertNull(xyzParam.getDescriptor().getDescription()); assertNull(xyzParam.getDescriptor().getDescription());
assertEquals("242526", xyzParam.getValue()); assertEquals("242526", xyzParam.getValue());
final Set<Parameter> secondParameters = new HashSet<>(); final Map<String, Parameter> secondParameters = new HashMap<>();
secondParameters.add(new Parameter(fooDescriptor, "baz")); secondParameters.put("foo", new Parameter(fooDescriptor, "baz"));
context.setParameters(secondParameters); context.setParameters(secondParameters);
assertTrue(context.getParameter("abc").isPresent()); assertTrue(context.getParameter("abc").isPresent());
assertTrue(context.getParameter("xyz").isPresent()); assertTrue(context.getParameter("xyz").isPresent());
secondParameters.add(new Parameter(abcParam.getDescriptor(), null)); secondParameters.put("abc", null);
secondParameters.add(new Parameter(xyzParam.getDescriptor(), null)); secondParameters.put("xyz", null);
context.setParameters(secondParameters); context.setParameters(secondParameters);
@ -86,8 +85,8 @@ public class TestStandardParameterContext {
assertEquals(Collections.singletonMap(fooDescriptor, fooParam), context.getParameters()); assertEquals(Collections.singletonMap(fooDescriptor, fooParam), context.getParameters());
final Set<Parameter> thirdParameters = new HashSet<>(); final Map<String, Parameter> thirdParameters = new HashMap<>();
thirdParameters.add(new Parameter(fooDescriptor, "other")); thirdParameters.put("foo", new Parameter(fooDescriptor, "other"));
context.setParameters(thirdParameters); context.setParameters(thirdParameters);
assertEquals("other", context.getParameter("foo").get().getValue()); assertEquals("other", context.getParameter("foo").get().getValue());
@ -100,8 +99,8 @@ public class TestStandardParameterContext {
final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").description("abc").build(); final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").description("abc").build();
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
context.setParameters(parameters); context.setParameters(parameters);
@ -112,7 +111,7 @@ public class TestStandardParameterContext {
ParameterDescriptor updatedDescriptor = new ParameterDescriptor.Builder().name("abc").description("Updated").build(); ParameterDescriptor updatedDescriptor = new ParameterDescriptor.Builder().name("abc").description("Updated").build();
final Parameter newDescriptionParam = new Parameter(updatedDescriptor, "321"); final Parameter newDescriptionParam = new Parameter(updatedDescriptor, "321");
context.setParameters(Collections.singleton(newDescriptionParam)); context.setParameters(Collections.singletonMap("abc", newDescriptionParam));
abcParam = context.getParameter("abc").get(); abcParam = context.getParameter("abc").get();
assertEquals(abcDescriptor, abcParam.getDescriptor()); assertEquals(abcDescriptor, abcParam.getDescriptor());
@ -121,12 +120,12 @@ public class TestStandardParameterContext {
updatedDescriptor = new ParameterDescriptor.Builder().name("abc").description("Updated Again").build(); updatedDescriptor = new ParameterDescriptor.Builder().name("abc").description("Updated Again").build();
final Parameter paramWithoutValue = new Parameter(updatedDescriptor, null); final Parameter paramWithoutValue = new Parameter(updatedDescriptor, null);
context.setParameters(Collections.singleton(paramWithoutValue)); context.setParameters(Collections.singletonMap("abc", paramWithoutValue));
abcParam = context.getParameter("abc").get(); abcParam = context.getParameter("abc").get();
assertEquals(abcDescriptor, abcParam.getDescriptor()); assertEquals(abcDescriptor, abcParam.getDescriptor());
assertEquals("Updated Again", abcParam.getDescriptor().getDescription()); assertEquals("Updated Again", abcParam.getDescriptor().getDescription());
assertEquals("321", abcParam.getValue()); assertNull(abcParam.getValue());
} }
@Test @Test
@ -139,17 +138,17 @@ public class TestStandardParameterContext {
final ParameterDescriptor xyzDescriptor = new ParameterDescriptor.Builder().name("xyz").build(); final ParameterDescriptor xyzDescriptor = new ParameterDescriptor.Builder().name("xyz").build();
final ParameterDescriptor fooDescriptor = new ParameterDescriptor.Builder().name("foo").description("bar").sensitive(true).build(); final ParameterDescriptor fooDescriptor = new ParameterDescriptor.Builder().name("foo").description("bar").sensitive(true).build();
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
parameters.add(new Parameter(xyzDescriptor, "242526")); parameters.put("xyz", new Parameter(xyzDescriptor, "242526"));
context.setParameters(parameters); context.setParameters(parameters);
final ParameterDescriptor sensitiveXyzDescriptor = new ParameterDescriptor.Builder().name("xyz").sensitive(true).build(); final ParameterDescriptor sensitiveXyzDescriptor = new ParameterDescriptor.Builder().name("xyz").sensitive(true).build();
final Set<Parameter> updatedParameters = new HashSet<>(); final Map<String, Parameter> updatedParameters = new HashMap<>();
updatedParameters.add(new Parameter(fooDescriptor, "baz")); updatedParameters.put("foo", new Parameter(fooDescriptor, "baz"));
updatedParameters.add(new Parameter(sensitiveXyzDescriptor, "242526")); updatedParameters.put("xyz", new Parameter(sensitiveXyzDescriptor, "242526"));
try { try {
context.setParameters(updatedParameters); context.setParameters(updatedParameters);
@ -159,7 +158,7 @@ public class TestStandardParameterContext {
final ParameterDescriptor insensitiveAbcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(false).build(); final ParameterDescriptor insensitiveAbcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(false).build();
updatedParameters.clear(); updatedParameters.clear();
updatedParameters.add(new Parameter(insensitiveAbcDescriptor, "123")); updatedParameters.put("abc", new Parameter(insensitiveAbcDescriptor, "123"));
try { try {
context.setParameters(updatedParameters); context.setParameters(updatedParameters);
@ -179,13 +178,13 @@ public class TestStandardParameterContext {
final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build(); final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build();
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
context.setParameters(parameters); context.setParameters(parameters);
parameters.clear(); parameters.clear();
parameters.add(new Parameter(abcDescriptor, "321")); parameters.put("abc", new Parameter(abcDescriptor, "321"));
context.setParameters(parameters); context.setParameters(parameters);
assertEquals("321", context.getParameter("abc").get().getValue()); assertEquals("321", context.getParameter("abc").get().getValue());
@ -194,7 +193,7 @@ public class TestStandardParameterContext {
Mockito.when(procNode.isRunning()).thenReturn(true); Mockito.when(procNode.isRunning()).thenReturn(true);
parameters.clear(); parameters.clear();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
try { try {
context.setParameters(parameters); context.setParameters(parameters);
@ -202,10 +201,10 @@ public class TestStandardParameterContext {
} catch (final IllegalStateException expected) { } catch (final IllegalStateException expected) {
} }
context.setParameters(Collections.emptySet()); context.setParameters(Collections.emptyMap());
parameters.clear(); parameters.clear();
parameters.add(new Parameter(abcDescriptor, null)); parameters.put("abc", new Parameter(abcDescriptor, null));
try { try {
context.setParameters(parameters); context.setParameters(parameters);
Assert.fail("Was able to remove parameter while referencing processor was running"); Assert.fail("Was able to remove parameter while referencing processor was running");
@ -224,15 +223,15 @@ public class TestStandardParameterContext {
Mockito.when(serviceNode.getState()).thenReturn(ControllerServiceState.ENABLED); Mockito.when(serviceNode.getState()).thenReturn(ControllerServiceState.ENABLED);
final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build(); final ParameterDescriptor abcDescriptor = new ParameterDescriptor.Builder().name("abc").sensitive(true).build();
final Set<Parameter> parameters = new HashSet<>(); final Map<String, Parameter> parameters = new HashMap<>();
parameters.add(new Parameter(abcDescriptor, "123")); parameters.put("abc", new Parameter(abcDescriptor, "123"));
context.setParameters(parameters); context.setParameters(parameters);
referenceManager.addControllerServiceReference("abc", serviceNode); referenceManager.addControllerServiceReference("abc", serviceNode);
parameters.clear(); parameters.clear();
parameters.add(new Parameter(abcDescriptor, "321")); parameters.put("abc", new Parameter(abcDescriptor, "321"));
for (final ControllerServiceState state : EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.ENABLING, ControllerServiceState.DISABLING)) { for (final ControllerServiceState state : EnumSet.of(ControllerServiceState.ENABLED, ControllerServiceState.ENABLING, ControllerServiceState.DISABLING)) {
Mockito.when(serviceNode.getState()).thenReturn(state); Mockito.when(serviceNode.getState()).thenReturn(state);
@ -249,7 +248,7 @@ public class TestStandardParameterContext {
parameters.clear(); parameters.clear();
context.setParameters(parameters); context.setParameters(parameters);
parameters.add(new Parameter(abcDescriptor, null)); parameters.put("abc", new Parameter(abcDescriptor, null));
try { try {
context.setParameters(parameters); context.setParameters(parameters);
Assert.fail("Was able to remove parameter being referenced by Controller Service that is DISABLING"); Assert.fail("Was able to remove parameter being referenced by Controller Service that is DISABLING");

View File

@ -218,7 +218,7 @@ nifi.cluster.flow.election.max.candidates=
# cluster load balancing properties # # cluster load balancing properties #
nifi.cluster.load.balance.host= nifi.cluster.load.balance.host=
nifi.cluster.load.balance.port=6342 nifi.cluster.load.balance.port=0
nifi.cluster.load.balance.connections.per.node=4 nifi.cluster.load.balance.connections.per.node=4
nifi.cluster.load.balance.max.thread.count=8 nifi.cluster.load.balance.max.thread.count=8
nifi.cluster.load.balance.comms.timeout=30 sec nifi.cluster.load.balance.comms.timeout=30 sec

View File

@ -1046,10 +1046,11 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
final Set<ProcessGroup> boundProcessGroups = parameterContext.getParameterReferenceManager().getProcessGroupsBound(parameterContext); 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 Set<Parameter> parameters = parameterContextDto.getParameters().stream() final Map<String, Parameter> parameters = new HashMap<>();
parameterContextDto.getParameters().stream()
.map(ParameterEntity::getParameter) .map(ParameterEntity::getParameter)
.map(this::createParameter) .map(this::createParameter)
.collect(Collectors.toSet()); .forEach(param -> parameters.put(param.getDescriptor().getName(), param));
updatedParameterContext.setParameters(parameters); updatedParameterContext.setParameters(parameters);
final List<ComponentValidationResultEntity> validationResults = new ArrayList<>(); final List<ComponentValidationResultEntity> validationResults = new ArrayList<>();
@ -1089,6 +1090,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
} }
private Parameter createParameter(final ParameterDTO dto) { private Parameter createParameter(final ParameterDTO dto) {
if (dto.getDescription() == null && dto.getSensitive() == null && dto.getValue() == null) {
return null; // null description, sensitivity flag, and value indicates a deletion, which we want to represent as a null Parameter.
}
final ParameterDescriptor descriptor = new ParameterDescriptor.Builder() final ParameterDescriptor descriptor = new ParameterDescriptor.Builder()
.name(dto.getName()) .name(dto.getName())
.description(dto.getDescription()) .description(dto.getDescription())

View File

@ -37,10 +37,10 @@ import org.apache.nifi.web.api.entity.ParameterEntity;
import org.apache.nifi.web.dao.ParameterContextDAO; import org.apache.nifi.web.dao.ParameterContextDAO;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
public class StandardParameterContextDAO implements ParameterContextDAO { public class StandardParameterContextDAO implements ParameterContextDAO {
private FlowManager flowManager; private FlowManager flowManager;
@ -57,7 +57,7 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
@Override @Override
public ParameterContext createParameterContext(final ParameterContextDTO parameterContextDto) { public ParameterContext createParameterContext(final ParameterContextDTO parameterContextDto) {
final Set<Parameter> parameters = getParameters(parameterContextDto); final Map<String, Parameter> parameters = getParameters(parameterContextDto);
final ParameterContext parameterContext = flowManager.createParameterContext(parameterContextDto.getId(), parameterContextDto.getName(), parameters); final ParameterContext parameterContext = flowManager.createParameterContext(parameterContextDto.getId(), parameterContextDto.getName(), parameters);
if (parameterContextDto.getDescription() != null) { if (parameterContextDto.getDescription() != null) {
parameterContext.setDescription(parameterContextDto.getDescription()); parameterContext.setDescription(parameterContextDto.getDescription());
@ -65,16 +65,30 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
return parameterContext; return parameterContext;
} }
private Set<Parameter> getParameters(final ParameterContextDTO parameterContextDto) { private Map<String, Parameter> getParameters(final ParameterContextDTO parameterContextDto) {
final Set<ParameterEntity> parameterDtos = parameterContextDto.getParameters(); final Set<ParameterEntity> parameterEntities = parameterContextDto.getParameters();
if (parameterDtos == null) { if (parameterEntities == null) {
return Collections.emptySet(); return Collections.emptyMap();
} }
return parameterContextDto.getParameters().stream() final Map<String, Parameter> parameterMap = new HashMap<>();
.map(ParameterEntity::getParameter) for (final ParameterEntity parameterEntity : parameterEntities) {
.map(this::createParameter) final ParameterDTO parameterDto = parameterEntity.getParameter();
.collect(Collectors.toSet());
if (parameterDto.getName() == null) {
throw new IllegalArgumentException("Cannot specify a Parameter without a name");
}
final boolean deletion = parameterDto.getDescription() == null && parameterDto.getSensitive() == null && parameterDto.getValue() == null;
if (deletion) {
parameterMap.put(parameterDto.getName(), null);
} else {
final Parameter parameter = createParameter(parameterDto);
parameterMap.put(parameterDto.getName(), parameter);
}
}
return parameterMap;
} }
private Parameter createParameter(final ParameterDTO dto) { private Parameter createParameter(final ParameterDTO dto) {
@ -118,7 +132,7 @@ public class StandardParameterContextDAO implements ParameterContextDAO {
} }
if (parameterContextDto.getParameters() != null) { if (parameterContextDto.getParameters() != null) {
final Set<Parameter> parameters = getParameters(parameterContextDto); final Map<String, Parameter> parameters = getParameters(parameterContextDto);
context.setParameters(parameters); context.setParameters(parameters);
} }

View File

@ -100,6 +100,11 @@ public abstract class ValidationContextAdapter implements ValidationContext {
return innerValidationContext.isParameterDefined(parameterName); return innerValidationContext.isParameterDefined(parameterName);
} }
@Override
public boolean isParameterSet(final String parameterName) {
return innerValidationContext.isParameterSet(parameterName);
}
@Override @Override
public Collection<String> getReferencedParameters(final String propertyName) { public Collection<String> getReferencedParameters(final String propertyName) {
return innerValidationContext.getReferencedParameters(propertyName); return innerValidationContext.getReferencedParameters(propertyName);

View File

@ -61,13 +61,13 @@ public class StatelessParameterContext implements ParameterContext {
} }
@Override @Override
public void setParameters(final Set<Parameter> updatedParameters) { public void setParameters(final Map<String, Parameter> updatedParameters) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); // This parameter context does not support updating - all parameters are provided in the constructor.
} }
@Override @Override
public void verifyCanSetParameters(final Set<Parameter> parameters) { public void verifyCanSetParameters(final Map<String, Parameter> parameters) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException(); // This parameter context does not support updating - all parameters are provided in the constructor.
} }
@Override @Override

View File

@ -26,6 +26,7 @@ import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.ControllerServiceLookup; import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.controller.PropertyConfiguration; import org.apache.nifi.controller.PropertyConfiguration;
import org.apache.nifi.expression.ExpressionLanguageCompiler; import org.apache.nifi.expression.ExpressionLanguageCompiler;
import org.apache.nifi.parameter.Parameter;
import org.apache.nifi.parameter.ParameterContext; import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterReference; import org.apache.nifi.parameter.ParameterReference;
import org.apache.nifi.registry.VariableRegistry; import org.apache.nifi.registry.VariableRegistry;
@ -36,6 +37,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class StatelessValidationContext implements ValidationContext { public class StatelessValidationContext implements ValidationContext {
@ -146,6 +148,22 @@ public class StatelessValidationContext implements ValidationContext {
return parameterContext.getParameter(parameterName).isPresent(); return parameterContext.getParameter(parameterName).isPresent();
} }
@Override
public boolean isParameterSet(final String parameterName) {
if (parameterContext == null) {
return false;
}
final Optional<Parameter> parameterOption = parameterContext.getParameter(parameterName);
if (!parameterOption.isPresent()) {
return false;
}
final String value = parameterOption.get().getValue();
return value != null;
}
@Override @Override
public ControllerServiceLookup getControllerServiceLookup() { public ControllerServiceLookup getControllerServiceLookup() {
return this.lookup; return this.lookup;