This is an automated email from the ASF dual-hosted git repository.

markap14 pushed a commit to branch support/nifi-1.13
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/support/nifi-1.13 by this push:
     new d12ac9c  NIFI-8266: Fix NPE when validating supported properties 
against validation context - Removed schema properties from 
FreeFormTextRecordSetWriter causing validation issues
d12ac9c is described below

commit d12ac9cb95182bb6a4bff9ac89d5c913d81211c6
Author: Matthew Burgess <[email protected]>
AuthorDate: Fri Feb 26 10:57:09 2021 -0500

    NIFI-8266: Fix NPE when validating supported properties against validation 
context
    - Removed schema properties from FreeFormTextRecordSetWriter causing 
validation issues
    
    This closes #4851.
    
    Signed-off-by: Mark Payne <[email protected]>
---
 .../components/AbstractConfigurableComponent.java  | 53 +++++++++++-----------
 .../nifi/text/FreeFormTextRecordSetWriter.java     | 19 ++++----
 .../nifi/text/TestFreeFormTextRecordSetWriter.java |  7 ---
 .../jetty/ControllerServiceTestContext.java        | 11 ++++-
 4 files changed, 44 insertions(+), 46 deletions(-)

diff --git 
a/nifi-api/src/main/java/org/apache/nifi/components/AbstractConfigurableComponent.java
 
b/nifi-api/src/main/java/org/apache/nifi/components/AbstractConfigurableComponent.java
index 4758802..1daeb43 100644
--- 
a/nifi-api/src/main/java/org/apache/nifi/components/AbstractConfigurableComponent.java
+++ 
b/nifi-api/src/main/java/org/apache/nifi/components/AbstractConfigurableComponent.java
@@ -90,40 +90,39 @@ public abstract class AbstractConfigurableComponent 
implements ConfigurableCompo
 
     @Override
     public final Collection<ValidationResult> validate(final ValidationContext 
context) {
-        // goes through supported properties
+        // goes through context properties, should match supported properties 
+ supported dynamic properties
         final Collection<ValidationResult> results = new ArrayList<>();
+        final Set<PropertyDescriptor> contextDescriptors = 
context.getProperties().keySet();
         final List<PropertyDescriptor> supportedDescriptors = 
getSupportedPropertyDescriptors();
 
-        if (null != supportedDescriptors) {
-            for (final PropertyDescriptor descriptor : supportedDescriptors) {
-                // If the property descriptor's dependency is not satisfied, 
the property does not need to be considered, as it's not relevant to the
-                // component's functionality.
-                final boolean dependencySatisfied = 
context.isDependencySatisfied(descriptor, this::getPropertyDescriptor);
-                if (!dependencySatisfied) {
-                    continue;
-                }
+        for (final PropertyDescriptor descriptor : contextDescriptors) {
+            // If the property descriptor's dependency is not satisfied, the 
property does not need to be considered, as it's not relevant to the
+            // component's functionality.
+            final boolean dependencySatisfied = 
context.isDependencySatisfied(descriptor, this::getPropertyDescriptor);
+            if (!dependencySatisfied) {
+                continue;
+            }
 
-                validateDependencies(descriptor, context, results);
+            validateDependencies(descriptor, context, results);
 
-                String value = context.getProperty(descriptor).getValue();
-                if (value == null) {
-                    value = descriptor.getDefaultValue();
-                }
+            String value = context.getProperty(descriptor).getValue();
+            if (value == null) {
+                value = descriptor.getDefaultValue();
+            }
 
-                if (value == null && descriptor.isRequired()) {
-                    String displayName = descriptor.getDisplayName();
-                    ValidationResult.Builder builder = new 
ValidationResult.Builder().valid(false).input(null).subject(displayName != null 
? displayName : descriptor.getName());
-                    builder = (displayName != null) ? 
builder.explanation(displayName + " is required") : 
builder.explanation(descriptor.getName() + " is required");
-                    results.add(builder.build());
-                    continue;
-                } else if (value == null) {
-                    continue;
-                }
+            if (value == null && descriptor.isRequired()) {
+                String displayName = descriptor.getDisplayName();
+                ValidationResult.Builder builder = new 
ValidationResult.Builder().valid(false).input(null).subject(displayName != null 
? displayName : descriptor.getName());
+                builder = (displayName != null) ? 
builder.explanation(displayName + " is required") : 
builder.explanation(descriptor.getName() + " is required");
+                results.add(builder.build());
+                continue;
+            } else if (value == null) {
+                continue;
+            }
 
-                final ValidationResult result = descriptor.validate(value, 
context);
-                if (!result.isValid()) {
-                    results.add(result);
-                }
+            final ValidationResult result = descriptor.validate(value, 
context);
+            if (!result.isValid()) {
+                results.add(result);
             }
         }
 
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/text/FreeFormTextRecordSetWriter.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/text/FreeFormTextRecordSetWriter.java
index 4ebc19f..f91eb0c 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/text/FreeFormTextRecordSetWriter.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/text/FreeFormTextRecordSetWriter.java
@@ -22,19 +22,17 @@ import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.annotation.lifecycle.OnEnabled;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.PropertyValue;
-import org.apache.nifi.context.PropertyContext;
+import org.apache.nifi.controller.AbstractControllerService;
 import org.apache.nifi.controller.ConfigurationContext;
 import org.apache.nifi.expression.ExpressionLanguageScope;
 import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.processor.util.StandardValidators;
-import org.apache.nifi.schema.access.InheritSchemaFromRecord;
-import org.apache.nifi.schema.access.SchemaAccessStrategy;
-import org.apache.nifi.schemaregistry.services.SchemaRegistry;
+import org.apache.nifi.schema.access.SchemaNotFoundException;
 import org.apache.nifi.serialization.RecordSetWriter;
 import org.apache.nifi.serialization.RecordSetWriterFactory;
-import org.apache.nifi.serialization.SchemaRegistryRecordSetWriter;
 import org.apache.nifi.serialization.record.RecordSchema;
 
+import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -46,7 +44,7 @@ import java.util.Map;
         + "text is able to make use of the Expression Language to reference 
each of the fields that are available "
         + "in a Record, as well as the attributes in the FlowFile and 
variables. If there is a name collision, the field name/value is used before 
attributes or variables. "
         + "Each record in the RecordSet will be separated by a single newline 
character.")
-public class FreeFormTextRecordSetWriter extends SchemaRegistryRecordSetWriter 
implements RecordSetWriterFactory {
+public class FreeFormTextRecordSetWriter extends AbstractControllerService 
implements RecordSetWriterFactory {
     static final PropertyDescriptor TEXT = new PropertyDescriptor.Builder()
         .name("Text")
         .description("The text to use when writing the results. This property 
will evaluate the Expression Language using any of the fields available in a 
Record.")
@@ -81,13 +79,12 @@ public class FreeFormTextRecordSetWriter extends 
SchemaRegistryRecordSetWriter i
     }
 
     @Override
-    public RecordSetWriter createWriter(final ComponentLog logger, final 
RecordSchema schema, final OutputStream out, final Map<String, String> 
variables) {
-        return new FreeFormTextWriter(textValue, characterSet, out, variables);
+    public RecordSchema getSchema(Map<String, String> variables, RecordSchema 
readSchema) throws SchemaNotFoundException, IOException {
+        return readSchema;
     }
 
     @Override
-    protected SchemaAccessStrategy getSchemaAccessStrategy(String strategy, 
SchemaRegistry schemaRegistry, PropertyContext context) {
-        return new InheritSchemaFromRecord();
+    public RecordSetWriter createWriter(final ComponentLog logger, final 
RecordSchema schema, final OutputStream out, final Map<String, String> 
variables) {
+        return new FreeFormTextWriter(textValue, characterSet, out, variables);
     }
-
 }
diff --git 
a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/test/java/org/apache/nifi/text/TestFreeFormTextRecordSetWriter.java
 
b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/test/java/org/apache/nifi/text/TestFreeFormTextRecordSetWriter.java
index 581a0db..f6abbca 100644
--- 
a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/test/java/org/apache/nifi/text/TestFreeFormTextRecordSetWriter.java
+++ 
b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/test/java/org/apache/nifi/text/TestFreeFormTextRecordSetWriter.java
@@ -17,14 +17,11 @@
 package org.apache.nifi.text;
 
 import org.apache.nifi.reporting.InitializationException;
-import org.apache.nifi.schema.access.SchemaAccessUtils;
 import org.apache.nifi.util.TestRunner;
 import org.apache.nifi.util.TestRunners;
 import org.junit.Test;
 
 import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -35,13 +32,9 @@ public class TestFreeFormTextRecordSetWriter {
     private TestRunner setup(FreeFormTextRecordSetWriter writer) throws 
InitializationException, IOException {
         TestRunner runner = 
TestRunners.newTestRunner(TestFreeFormTextRecordSetWriterProcessor.class);
 
-        final String outputSchemaText = new 
String(Files.readAllBytes(Paths.get("src/test/resources/text/testschema")));
-
         runner.addControllerService("writer", writer);
         runner.setProperty(TestFreeFormTextRecordSetWriterProcessor.WRITER, 
"writer");
 
-        runner.setProperty(writer, SchemaAccessUtils.SCHEMA_ACCESS_STRATEGY, 
SchemaAccessUtils.SCHEMA_TEXT_PROPERTY);
-        runner.setProperty(writer, SchemaAccessUtils.SCHEMA_TEXT, 
outputSchemaText);
         runner.setProperty(writer, FreeFormTextRecordSetWriter.TEXT, "ID: 
${ID}, Name: ${NAME}, Age: ${AGE}, Country: ${COUNTRY}, Username: 
${user.name}");
 
         return runner;
diff --git 
a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/jetty/ControllerServiceTestContext.java
 
b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/jetty/ControllerServiceTestContext.java
index 04cccdb..2e29437 100644
--- 
a/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/jetty/ControllerServiceTestContext.java
+++ 
b/nifi-nar-bundles/nifi-websocket-bundle/nifi-websocket-services-jetty/src/test/java/org/apache/nifi/websocket/jetty/ControllerServiceTestContext.java
@@ -23,6 +23,8 @@ import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.util.MockControllerServiceInitializationContext;
 import org.apache.nifi.util.MockPropertyValue;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.function.Function;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -44,7 +46,14 @@ public class ControllerServiceTestContext {
         doAnswer(invocation -> 
configurationContext.getProperty(invocation.getArgument(0)))
                 
.when(validationContext).getProperty(any(PropertyDescriptor.class));
         
doReturn(true).when(validationContext).isDependencySatisfied(any(PropertyDescriptor.class),
 any(Function.class));
-        controllerService.getPropertyDescriptors().forEach(prop -> 
setDefaultValue(prop));
+        // Return the service's properties as the context's
+        final Map<PropertyDescriptor,String> propDescriptors = new HashMap<>();
+        controllerService.getPropertyDescriptors().forEach(prop -> {
+            setDefaultValue(prop);
+            propDescriptors.put(prop, prop.getName());
+        });
+
+        doReturn(propDescriptors).when(validationContext).getProperties();
     }
 
     public MockControllerServiceInitializationContext 
getInitializationContext() {

Reply via email to