mirror of https://github.com/apache/nifi.git
NIFI-7380 - fix for controller service validation in NiFi Stateless
This closes #4264. Signed-off-by: Matthieu Cauffiez <matthieu.cauffiez@bell.ca> Signed-off-by: Mark Payne <markap14@hotmail.com>
This commit is contained in:
parent
a3cc2c58ff
commit
179675f0b4
|
@ -16,7 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.nifi.stateless.core;
|
package org.apache.nifi.stateless.core;
|
||||||
|
|
||||||
import org.apache.nifi.parameter.ParameterLookup;
|
import org.apache.nifi.controller.PropertyConfiguration;
|
||||||
|
import org.apache.nifi.parameter.ParameterContext;
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
import org.apache.nifi.components.PropertyValue;
|
import org.apache.nifi.components.PropertyValue;
|
||||||
import org.apache.nifi.controller.ConfigurationContext;
|
import org.apache.nifi.controller.ConfigurationContext;
|
||||||
|
@ -24,43 +25,56 @@ import org.apache.nifi.controller.ControllerService;
|
||||||
import org.apache.nifi.controller.ControllerServiceLookup;
|
import org.apache.nifi.controller.ControllerServiceLookup;
|
||||||
import org.apache.nifi.registry.VariableRegistry;
|
import org.apache.nifi.registry.VariableRegistry;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class StatelessConfigurationContext implements ConfigurationContext {
|
public class StatelessConfigurationContext implements ConfigurationContext {
|
||||||
|
|
||||||
private final Map<PropertyDescriptor, String> properties;
|
private final Map<PropertyDescriptor, PropertyConfiguration> properties;
|
||||||
private final ControllerServiceLookup serviceLookup;
|
private final ControllerServiceLookup serviceLookup;
|
||||||
private final ControllerService service;
|
private final ControllerService service;
|
||||||
private final VariableRegistry variableRegistry;
|
private final VariableRegistry variableRegistry;
|
||||||
private final ParameterLookup parameterLookup;
|
private final ParameterContext parameterContext;
|
||||||
|
|
||||||
public StatelessConfigurationContext(final ControllerService service,
|
public StatelessConfigurationContext(final ControllerService service,
|
||||||
final Map<PropertyDescriptor, String> properties,
|
final Map<PropertyDescriptor, PropertyConfiguration> properties,
|
||||||
final ControllerServiceLookup serviceLookup,
|
final ControllerServiceLookup serviceLookup,
|
||||||
final VariableRegistry variableRegistry,
|
final VariableRegistry variableRegistry,
|
||||||
final ParameterLookup parameterLookup) {
|
final ParameterContext parameterLookup) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.serviceLookup = serviceLookup;
|
this.serviceLookup = serviceLookup;
|
||||||
this.variableRegistry = variableRegistry;
|
this.variableRegistry = variableRegistry;
|
||||||
this.parameterLookup = parameterLookup;
|
this.parameterContext = parameterLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertyValue getProperty(final PropertyDescriptor property) {
|
public PropertyValue getProperty(final PropertyDescriptor property) {
|
||||||
String value = properties.get(property);
|
final PropertyConfiguration setPropertyValue = properties.get(property);
|
||||||
if (value == null) {
|
final String propValue = (setPropertyValue == null) ? getActualDescriptor(property).getDefaultValue() : setPropertyValue.getEffectiveValue(parameterContext);
|
||||||
value = getActualDescriptor(property).getDefaultValue();
|
return new StatelessPropertyValue(propValue, serviceLookup, parameterContext, variableRegistry);
|
||||||
}
|
|
||||||
return new StatelessPropertyValue(value, serviceLookup, parameterLookup, variableRegistry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<PropertyDescriptor, String> getProperties() {
|
public Map<PropertyDescriptor, String> getProperties() {
|
||||||
return new HashMap<>(this.properties);
|
final List<PropertyDescriptor> supported = service.getPropertyDescriptors();
|
||||||
|
|
||||||
|
final Map<PropertyDescriptor, String> effectiveValues = new LinkedHashMap<>();
|
||||||
|
for (final PropertyDescriptor descriptor : supported) {
|
||||||
|
effectiveValues.put(descriptor, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Map.Entry<PropertyDescriptor, PropertyConfiguration> entry : properties.entrySet()) {
|
||||||
|
final PropertyDescriptor descriptor = entry.getKey();
|
||||||
|
final PropertyConfiguration configuration = entry.getValue();
|
||||||
|
final String value = configuration.getEffectiveValue(parameterContext);
|
||||||
|
|
||||||
|
effectiveValues.put(descriptor, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return effectiveValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.nifi.stateless.core;
|
||||||
|
|
||||||
import org.apache.nifi.components.PropertyDescriptor;
|
import org.apache.nifi.components.PropertyDescriptor;
|
||||||
import org.apache.nifi.controller.ControllerService;
|
import org.apache.nifi.controller.ControllerService;
|
||||||
|
import org.apache.nifi.controller.PropertyConfiguration;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -31,7 +32,7 @@ public class StatelessControllerServiceConfiguration {
|
||||||
|
|
||||||
private final AtomicBoolean enabled = new AtomicBoolean(false);
|
private final AtomicBoolean enabled = new AtomicBoolean(false);
|
||||||
private String annotationData;
|
private String annotationData;
|
||||||
private Map<PropertyDescriptor, String> properties = new HashMap<>();
|
private Map<PropertyDescriptor, PropertyConfiguration> properties = new HashMap<>();
|
||||||
|
|
||||||
public StatelessControllerServiceConfiguration(final ControllerService service, final String name) {
|
public StatelessControllerServiceConfiguration(final ControllerService service, final String name) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
|
@ -50,20 +51,20 @@ public class StatelessControllerServiceConfiguration {
|
||||||
return this.enabled.get();
|
return this.enabled.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperties(final Map<PropertyDescriptor, String> props) {
|
public void setProperties(final Map<PropertyDescriptor, PropertyConfiguration> props) {
|
||||||
this.properties = new HashMap<>(props);
|
this.properties = new HashMap<>(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setProperty(final PropertyDescriptor key, final String value) {
|
public void setProperty(final PropertyDescriptor key, final PropertyConfiguration value) {
|
||||||
this.properties.put(key, value);
|
this.properties.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getProperty(final PropertyDescriptor descriptor) {
|
public String getProperty(final PropertyDescriptor descriptor) {
|
||||||
final String value = properties.get(descriptor);
|
final PropertyConfiguration value = properties.get(descriptor);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return descriptor.getDefaultValue();
|
return descriptor.getDefaultValue();
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value.getRawValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ public class StatelessControllerServiceConfiguration {
|
||||||
return annotationData;
|
return annotationData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<PropertyDescriptor, String> getProperties() {
|
public Map<PropertyDescriptor, PropertyConfiguration> getProperties() {
|
||||||
return Collections.unmodifiableMap(properties);
|
return Collections.unmodifiableMap(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,12 @@ import org.apache.nifi.components.state.StateManager;
|
||||||
import org.apache.nifi.controller.ConfigurationContext;
|
import org.apache.nifi.controller.ConfigurationContext;
|
||||||
import org.apache.nifi.controller.ControllerService;
|
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.parameter.ExpressionLanguageAgnosticParameterParser;
|
||||||
|
import org.apache.nifi.parameter.ExpressionLanguageAwareParameterParser;
|
||||||
import org.apache.nifi.parameter.ParameterContext;
|
import org.apache.nifi.parameter.ParameterContext;
|
||||||
|
import org.apache.nifi.parameter.ParameterParser;
|
||||||
|
import org.apache.nifi.parameter.ParameterTokenList;
|
||||||
import org.apache.nifi.registry.VariableRegistry;
|
import org.apache.nifi.registry.VariableRegistry;
|
||||||
import org.apache.nifi.reporting.InitializationException;
|
import org.apache.nifi.reporting.InitializationException;
|
||||||
|
|
||||||
|
@ -128,7 +133,7 @@ public class StatelessControllerServiceLookup implements ControllerServiceLookup
|
||||||
public void enableControllerServices(final VariableRegistry variableRegistry) {
|
public void enableControllerServices(final VariableRegistry variableRegistry) {
|
||||||
for (final StatelessControllerServiceConfiguration config : controllerServiceMap.values()) {
|
for (final StatelessControllerServiceConfiguration config : controllerServiceMap.values()) {
|
||||||
final ControllerService service = config.getService();
|
final ControllerService service = config.getService();
|
||||||
final Collection<ValidationResult> validationResults = validate(service, config.getName(), variableRegistry);
|
final Collection<ValidationResult> validationResults = validate(service, config, variableRegistry);
|
||||||
if (!validationResults.isEmpty()) {
|
if (!validationResults.isEmpty()) {
|
||||||
throw new RuntimeException("Failed to enable Controller Service {id=" + service.getIdentifier() + ", name=" + config.getName() + ", type=" + service.getClass() + "} because " +
|
throw new RuntimeException("Failed to enable Controller Service {id=" + service.getIdentifier() + ", name=" + config.getName() + ", type=" + service.getClass() + "} because " +
|
||||||
"validation failed: " + validationResults);
|
"validation failed: " + validationResults);
|
||||||
|
@ -142,10 +147,11 @@ public class StatelessControllerServiceLookup implements ControllerServiceLookup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ValidationResult> validate(final ControllerService service, final String serviceName, final VariableRegistry variableRegistry) {
|
public Collection<ValidationResult> validate(final ControllerService service, final StatelessControllerServiceConfiguration serviceName, final VariableRegistry variableRegistry) {
|
||||||
final StateManager stateManager = controllerServiceStateManagers.get(service.getIdentifier());
|
final StateManager stateManager = controllerServiceStateManagers.get(service.getIdentifier());
|
||||||
final SLF4JComponentLog logger = controllerServiceLoggers.get(service.getIdentifier());
|
final SLF4JComponentLog logger = controllerServiceLoggers.get(service.getIdentifier());
|
||||||
final StatelessProcessContext processContext = new StatelessProcessContext(service, this, serviceName, logger, stateManager, variableRegistry, parameterContext);
|
final StatelessProcessContext processContext = new StatelessProcessContext(service, this, serviceName.getName(), logger, stateManager, variableRegistry, parameterContext);
|
||||||
|
serviceName.getProperties().forEach((k,v) -> processContext.setProperty(k,v.getRawValue()));
|
||||||
final StatelessValidationContext validationContext = new StatelessValidationContext(processContext, this, stateManager, variableRegistry, parameterContext);
|
final StatelessValidationContext validationContext = new StatelessValidationContext(processContext, this, stateManager, variableRegistry, parameterContext);
|
||||||
return service.validate(validationContext);
|
return service.validate(validationContext);
|
||||||
}
|
}
|
||||||
|
@ -192,18 +198,27 @@ public class StatelessControllerServiceLookup implements ControllerServiceLookup
|
||||||
throw new IllegalStateException("Controller service " + service + " has not been added to this TestRunner via the #addControllerService method");
|
throw new IllegalStateException("Controller service " + service + " has not been added to this TestRunner via the #addControllerService method");
|
||||||
}
|
}
|
||||||
|
|
||||||
final ValidationContext validationContext = new StatelessValidationContext(context, this, serviceStateManager, registry, parameterContext).getControllerServiceValidationContext(service);
|
final ValidationContext validationContext = new StatelessValidationContext(context, this, serviceStateManager, registry, parameterContext);
|
||||||
final ValidationResult validationResult = property.validate(value, validationContext);
|
final ValidationResult validationResult = property.validate(value, validationContext);
|
||||||
|
|
||||||
final StatelessControllerServiceConfiguration configuration = getControllerServiceConfigToUpdate(service);
|
final StatelessControllerServiceConfiguration configuration = getControllerServiceConfigToUpdate(service);
|
||||||
final String oldValue = configuration.getProperties().get(property);
|
final PropertyConfiguration oldValue = configuration.getProperties().get(property);
|
||||||
configuration.setProperty(property, value);
|
final PropertyConfiguration propertyConfiguration = createPropertyConfiguration(value, property.isExpressionLanguageSupported());
|
||||||
|
configuration.setProperty(property, propertyConfiguration);
|
||||||
|
|
||||||
if ((value == null && oldValue != null) || (value != null && !value.equals(oldValue))) {
|
if (oldValue == null && value != null) {
|
||||||
service.onPropertyModified(property, oldValue, value);
|
service.onPropertyModified(property, null, value);
|
||||||
|
} else if ((value == null && oldValue.getRawValue() != null) || (value != null && !value.equals(oldValue.getRawValue()))) {
|
||||||
|
service.onPropertyModified(property, oldValue.getRawValue(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return validationResult;
|
return validationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PropertyConfiguration createPropertyConfiguration(final String value, final boolean supportsEl) {
|
||||||
|
final ParameterParser parameterParser = supportsEl ? new ExpressionLanguageAwareParameterParser() : new ExpressionLanguageAgnosticParameterParser();
|
||||||
|
final ParameterTokenList parameterTokenList = parameterParser.parseTokens(value);
|
||||||
|
return new PropertyConfiguration(value, parameterTokenList, parameterTokenList.toReferenceList());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue