gresockj commented on a change in pull request #5113:
URL: https://github.com/apache/nifi/pull/5113#discussion_r657886548



##########
File path: 
nifi-stateless/nifi-stateless-bundle/nifi-stateless-engine/src/main/java/org/apache/nifi/stateless/engine/StandardStatelessEngine.java
##########
@@ -182,6 +197,78 @@ public StatelessDataflow createFlow(final 
DataflowDefinition<VersionedFlowSnapsh
         return dataflow;
     }
 
+    private ParameterProvider createParameterProvider(final 
DataflowDefinition<?> dataflowDefinition) {
+        // Create a Provider for each definition
+        final List<ParameterProvider> providers = new ArrayList<>();
+        for (final ParameterProviderDefinition definition : 
dataflowDefinition.getParameterProviderDefinitions()) {
+            providers.add(createParameterProvider(definition));
+        }
+
+        // Create a Composite Parameter Provider that wraps all of the others.
+        final CompositeParameterProvider provider = new 
CompositeParameterProvider(providers);
+        final ParameterProviderInitializationContext initializationContext = 
new StandardParameterProviderInitializationContext(provider, 
Collections.emptyMap(), UUID.randomUUID().toString());
+        provider.initialize(initializationContext);
+        return provider;
+    }
+
+    private ParameterProvider createParameterProvider(final 
ParameterProviderDefinition definition) {
+        final BundleCoordinate bundleCoordinate = 
determineBundleCoordinate(definition, "Parameter Provider");
+        final Bundle bundle = extensionManager.getBundle(bundleCoordinate);
+        if (bundle == null) {
+            throw new IllegalStateException("Unable to find bundle for 
coordinate " + bundleCoordinate.getCoordinate());
+        }
+
+        final String providerType = definition.getType();
+
+        final String providerId = UUID.randomUUID().toString();
+        final InstanceClassLoader classLoader = 
extensionManager.createInstanceClassLoader(providerType, providerId, bundle, 
Collections.emptySet());
+
+        try {
+            final Class<?> rawClass = Class.forName(providerType, true, 
classLoader);
+            Thread.currentThread().setContextClassLoader(classLoader);
+
+            final ParameterProvider parameterProvider = (ParameterProvider) 
rawClass.newInstance();
+
+            // Initialize the provider
+            final Map<String, String> properties = 
resolveProperties(definition.getPropertyValues(), parameterProvider, 
parameterProvider.getPropertyDescriptors());
+            final ParameterProviderInitializationContext initializationContext 
= new StandardParameterProviderInitializationContext(parameterProvider, 
properties, providerId);
+            parameterProvider.initialize(initializationContext);
+
+            // Ensure that the Parameter Provider is valid.
+            final List<ValidationResult> validationResults = 
validate(parameterProvider, properties, providerId);
+            if (!validationResults.isEmpty()) {
+                throw new IllegalStateException("Parameter Provider with name 
<" + definition.getName() + "> is not valid: " + validationResults);
+            }
+
+            return parameterProvider;
+        } catch (final Exception e) {
+            throw new IllegalStateException("Could not create Parameter 
Provider " + definition.getName() + " of type " + definition.getType(), e);
+        }
+    }
+
+    private List<ValidationResult> validate(final ConfigurableComponent 
component, final Map<String, String> properties, final String componentId) {
+        final Map<PropertyDescriptor, PropertyConfiguration> propertyMap = new 
HashMap<>();
+
+        for (final Map.Entry<String, String> property : properties.entrySet()) 
{
+            final String propertyName = property.getKey();
+            final String propertyValue = property.getValue();
+
+            final PropertyDescriptor descriptor = 
component.getPropertyDescriptor(propertyName);
+            final ParameterTokenList tokenList = new 
StandardParameterTokenList(null, Collections.emptyList());
+            final PropertyConfiguration propertyConfiguration = new 
PropertyConfiguration(propertyValue, tokenList, Collections.emptyList());
+
+            propertyMap.put(descriptor, propertyConfiguration);
+        }
+
+        final ValidationContext validationContext = new 
StandardValidationContext(controllerServiceProvider, propertyMap,

Review comment:
       Something fishy is going on with the validation here.  I added a 
required property:
   ```
       public static final PropertyDescriptor MESSAGE = new 
PropertyDescriptor.Builder()
               .displayName("Message")
               .name("message")
               .required(true)
               .addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
   ```
   And I configured it via:
   ```
   nifi.stateless.parameter.provider.Custom Property Provider.name=My Custom 
Provider
   nifi.stateless.parameter.provider.Custom Property 
Provider.type=org.apache.nifi.stateless.parameter.gresock.MyCustomProvider
   nifi.stateless.parameter.provider.Custom Property 
Provider.bundle=org.apache.nifi:nifi-gresock-nar:1.14.0-SNAPSHOT
   nifi.stateless.parameter.provider.Custom Property 
Provider.properties.allowed-context-name=Context
   nifi.stateless.parameter.provider.Custom Property 
Provider.properties.message=A custom parameter:
   ```
   And I get this error:
   ```
   Exception in thread "main" java.lang.IllegalStateException: Could not create 
Parameter Provider Custom Property Provider of type 
org.apache.nifi.stateless.parameter.gresock.MyCustomProvider
        at 
org.apache.nifi.stateless.engine.StandardStatelessEngine.createParameterProvider(StandardStatelessEngine.java:245)
        at 
org.apache.nifi.stateless.engine.StandardStatelessEngine.createParameterProvider(StandardStatelessEngine.java:204)
        at 
org.apache.nifi.stateless.engine.StandardStatelessEngine.createFlow(StandardStatelessEngine.java:175)
        at 
org.apache.nifi.stateless.flow.StandardStatelessDataflowFactory.createDataflow(StandardStatelessDataflowFactory.java:223)
        at 
org.apache.nifi.stateless.bootstrap.StatelessBootstrap.createDataflow(StatelessBootstrap.java:66)
        at 
org.apache.nifi.stateless.bootstrap.RunStatelessFlow.createDataflow(RunStatelessFlow.java:94)
        at 
org.apache.nifi.stateless.bootstrap.RunStatelessFlow.main(RunStatelessFlow.java:56)
   Caused by: java.lang.IllegalStateException: Parameter Provider with name 
<Custom Property Provider> is not valid: ['Message' is invalid because Message 
is required]
        at 
org.apache.nifi.stateless.engine.StandardStatelessEngine.createParameterProvider(StandardStatelessEngine.java:240)
        ... 6 more
   ```
   Digging into the validation code, I notice that in 
`PropertyConfiguration.getEffectiveValue(...)`, the `rawValue` is correctly 
set, but the following are also true:
   
   - parameterTokenList is not null, but it is empty
   - parameterLookup passed in is null, because the supplied parameterContext 
here is null
   - Therefore, the effectiveValue appears to always be set to null
   - The effectiveValue then overrides the rawValue, resulting in the 
validation context to always think the value is null for configured properties




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to