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

pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new aec21031161 NIFI-15729 Fixed Script reloading in 
ScriptedRecordSetWriter (#11022)
aec21031161 is described below

commit aec2103116150b71ed320952b2e0c44c186c0c89
Author: David Handermann <[email protected]>
AuthorDate: Thu Mar 19 03:35:51 2026 -0500

    NIFI-15729 Fixed Script reloading in ScriptedRecordSetWriter (#11022)
    
    - Set ScriptRunner to null on modification to Script File and Script Body 
properties
---
 .../script/AbstractScriptedControllerService.java  |   6 +-
 .../record/script/ScriptedRecordSetWriterTest.java | 162 +++++++++++----------
 .../groovy/test_record_writer_inline.groovy        |  10 +-
 3 files changed, 87 insertions(+), 91 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/AbstractScriptedControllerService.java
 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/AbstractScriptedControllerService.java
index da79cc676fc..3bfb6c3629d 100644
--- 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/AbstractScriptedControllerService.java
+++ 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/main/java/org/apache/nifi/script/AbstractScriptedControllerService.java
@@ -109,7 +109,6 @@ public abstract class AbstractScriptedControllerService 
extends AbstractControll
      */
     @Override
     public void onPropertyModified(final PropertyDescriptor descriptor, final 
String oldValue, final String newValue) {
-
         validationResults.set(new HashSet<>());
 
         if (ScriptingComponentUtils.SCRIPT_FILE.equals(descriptor)
@@ -117,10 +116,7 @@ public abstract class AbstractScriptedControllerService 
extends AbstractControll
                 || ScriptingComponentUtils.MODULES.equals(descriptor)
                 || scriptingComponentHelper.scriptEngine.equals(descriptor)) {
             scriptNeedsReload.set(true);
-            // Need to reset scriptEngine if the value has changed
-            if (scriptingComponentHelper.scriptEngine.equals(descriptor) || 
ScriptingComponentUtils.MODULES.equals(descriptor)) {
-                scriptRunner = null;
-            }
+            scriptRunner = null;
         }
     }
 
diff --git 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/record/script/ScriptedRecordSetWriterTest.java
 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/record/script/ScriptedRecordSetWriterTest.java
index 6e643a940d3..a7b6f620a0b 100644
--- 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/record/script/ScriptedRecordSetWriterTest.java
+++ 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/java/org/apache/nifi/record/script/ScriptedRecordSetWriterTest.java
@@ -16,115 +16,123 @@
  */
 package org.apache.nifi.record.script;
 
-import org.apache.nifi.processor.AbstractProcessor;
-import org.apache.nifi.processor.ProcessContext;
-import org.apache.nifi.processor.ProcessSession;
-import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processors.script.AccessibleScriptingComponentHelper;
 import org.apache.nifi.script.ScriptingComponentHelper;
 import org.apache.nifi.script.ScriptingComponentUtils;
 import org.apache.nifi.serialization.RecordSetWriter;
 import org.apache.nifi.serialization.SimpleRecordSchema;
+import org.apache.nifi.serialization.WriteResult;
 import org.apache.nifi.serialization.record.MapRecord;
 import org.apache.nifi.serialization.record.RecordField;
 import org.apache.nifi.serialization.record.RecordFieldType;
 import org.apache.nifi.serialization.record.RecordSchema;
 import org.apache.nifi.serialization.record.RecordSet;
-import org.apache.nifi.util.MockComponentLog;
+import org.apache.nifi.util.NoOpProcessor;
 import org.apache.nifi.util.TestRunner;
 import org.apache.nifi.util.TestRunners;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
 import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathFactory;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-/**
- * Unit tests for the ScriptedReader class
- */
-public class ScriptedRecordSetWriterTest {
-    @TempDir
-    private static Path targetPath;
+class ScriptedRecordSetWriterTest {
+    private static final Path GROOVY_SCRIPT_LOCATION = 
Paths.get("src/test/resources/groovy/test_record_writer_inline.groovy");
+    private static final String GROOVY_SCRIPT_ENGINE = "Groovy";
 
-    @BeforeAll
-    public static void setUpOnce() throws Exception {
-        
Files.copy(Paths.get("src/test/resources/groovy/test_record_writer_inline.groovy"),
 targetPath, StandardCopyOption.REPLACE_EXISTING);
-    }
+    private static final String SERVICE_ID = 
ScriptedRecordSetWriterTest.class.getSimpleName();
+
+    private static final String ID_FIELD = "id";
+    private static final String LABEL_FIELD = "label";
+    private static final RecordSchema RECORD_SCHEMA = new SimpleRecordSchema(
+            List.of(
+                    new RecordField(ID_FIELD, 
RecordFieldType.INT.getDataType()),
+                    new RecordField(LABEL_FIELD, 
RecordFieldType.STRING.getDataType())
+            )
+    );
+    private static final MapRecord[] RECORDS = new MapRecord[]{
+            new MapRecord(RECORD_SCHEMA, Map.of(
+                    ID_FIELD, 1,
+                    LABEL_FIELD, "First Record"
+            )),
+            new MapRecord(RECORD_SCHEMA, Map.of(
+                    ID_FIELD, 2,
+                    LABEL_FIELD, "Second Record"
+            ))
+    };
+    private static final RecordSet RECORD_SET = RecordSet.of(RECORD_SCHEMA, 
RECORDS);
+    private static final String RECORD_TAG = "record";
+
+    private static final String APPLICATION_XML = "application/xml";
+    private static final String TEXT_XML = "text/xml";
+
+    private final TestRunner runner = 
TestRunners.newTestRunner(NoOpProcessor.class);
 
     @Test
     void testRecordWriterGroovyScript() throws Exception {
-        final TestRunner runner = TestRunners.newTestRunner(new 
AbstractProcessor() {
-            @Override
-            public void onTrigger(final ProcessContext context, final 
ProcessSession session) throws ProcessException {
-            }
-        });
-
-        MockScriptedWriter recordSetWriterFactory = new MockScriptedWriter();
-        runner.addControllerService("writer", recordSetWriterFactory);
-        runner.setProperty(recordSetWriterFactory, "Script Engine", "Groovy");
-        runner.setProperty(recordSetWriterFactory, 
ScriptingComponentUtils.SCRIPT_FILE, targetPath.toString());
-        runner.setProperty(recordSetWriterFactory, 
ScriptingComponentUtils.SCRIPT_BODY, (String) null);
-        runner.setProperty(recordSetWriterFactory, 
ScriptingComponentUtils.MODULES, (String) null);
-        runner.enableControllerService(recordSetWriterFactory);
-
-        RecordSchema schema = 
recordSetWriterFactory.getSchema(Collections.emptyMap(), null);
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        RecordSetWriter recordSetWriter = 
recordSetWriterFactory.createWriter(new MockComponentLog("id", 
recordSetWriterFactory), schema, outputStream, Collections.emptyMap());
-        assertNotNull(recordSetWriter);
-
-        SimpleRecordSchema recordSchema = new 
SimpleRecordSchema(Arrays.asList(new RecordField("id", 
RecordFieldType.INT.getDataType()),
-                new RecordField("name", RecordFieldType.STRING.getDataType()),
-                new RecordField("code", RecordFieldType.INT.getDataType())));
-        MapRecord[] records = createMapRecords(recordSchema);
-
-        recordSetWriter.write(RecordSet.of(recordSchema, records));
-
-        DocumentBuilder documentBuilder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();
-        Document document = documentBuilder.parse(new 
ByteArrayInputStream(outputStream.toByteArray()));
-        XPathFactory xpathfactory = XPathFactory.newInstance();
-        XPath xpath = xpathfactory.newXPath();
-        assertEquals("1", xpath.evaluate("//record[1]/id/text()", document));
-        assertEquals("200", xpath.evaluate("//record[2]/code/text()", 
document));
-        assertEquals("Ramon", xpath.evaluate("//record[3]/name/text()", 
document));
+        final String scriptBody = Files.readString(GROOVY_SCRIPT_LOCATION);
+        final ScriptedRecordSetWriter scriptedRecordSetWriter = 
addScriptedRecordSetWriter(scriptBody);
+
+        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        try (
+                RecordSetWriter recordSetWriter = 
scriptedRecordSetWriter.createWriter(runner.getLogger(), RECORD_SCHEMA, 
outputStream, Collections.emptyMap())
+        ) {
+            assertEquals(APPLICATION_XML, recordSetWriter.getMimeType());
+
+            final WriteResult writeResult = recordSetWriter.write(RECORD_SET);
+            assertEquals(RECORDS.length, writeResult.getRecordCount());
+        }
+
+        assertRecordsFound(outputStream);
     }
 
-    private static MapRecord[] createMapRecords(SimpleRecordSchema 
recordSchema) {
-        Map<String, Object> map = new LinkedHashMap<>(3);
-        map.put("id", 1);
-        map.put("name", "John");
-        map.put("code", 100);
-        Map<String, Object> map1 = new LinkedHashMap<>(3);
-        map1.put("id", 2);
-        map1.put("name", "Mary");
-        map1.put("code", 200);
-        Map<String, Object> map2 = new LinkedHashMap<>(3);
-        map2.put("id", 3);
-        map2.put("name", "Ramon");
-        map2.put("code", 300);
-
-        return new MapRecord[]{new MapRecord(recordSchema, map), new 
MapRecord(recordSchema, map1), new MapRecord(recordSchema, map2)};
+    @Test
+    void testScriptReloaded() throws Exception {
+        final String scriptBody = Files.readString(GROOVY_SCRIPT_LOCATION);
+        final ScriptedRecordSetWriter scriptedRecordSetWriter = 
addScriptedRecordSetWriter(scriptBody);
+
+        final RecordSetWriter recordSetWriter = 
scriptedRecordSetWriter.createWriter(runner.getLogger(), RECORD_SCHEMA, new 
ByteArrayOutputStream(), Collections.emptyMap());
+        assertEquals(APPLICATION_XML, recordSetWriter.getMimeType());
+
+        runner.disableControllerService(scriptedRecordSetWriter);
+        final String scriptBodyUpdated = scriptBody.replace(APPLICATION_XML, 
TEXT_XML);
+        runner.setProperty(scriptedRecordSetWriter, 
ScriptingComponentUtils.SCRIPT_BODY, scriptBodyUpdated);
+        runner.enableControllerService(scriptedRecordSetWriter);
+
+        final RecordSetWriter recordSetWriterReload = 
scriptedRecordSetWriter.createWriter(runner.getLogger(), RECORD_SCHEMA, new 
ByteArrayOutputStream(), Collections.emptyMap());
+        assertEquals(TEXT_XML, recordSetWriterReload.getMimeType());
     }
-    public static class MockScriptedWriter extends ScriptedRecordSetWriter 
implements AccessibleScriptingComponentHelper {
-        @Override
-        public ScriptingComponentHelper getScriptingComponentHelper() {
-            return this.scriptingComponentHelper;
-        }
+
+    private void assertRecordsFound(final ByteArrayOutputStream outputStream) 
throws Exception {
+        final Document document = getDocument(outputStream);
+        final NodeList recordNodes = document.getElementsByTagName(RECORD_TAG);
+
+        assertEquals(RECORDS.length, recordNodes.getLength());
+    }
+
+    private Document getDocument(final ByteArrayOutputStream outputStream) 
throws Exception {
+        final byte[] bytes = outputStream.toByteArray();
+        final DocumentBuilder documentBuilder = 
DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        return documentBuilder.parse(new ByteArrayInputStream(bytes));
+    }
+
+    private ScriptedRecordSetWriter addScriptedRecordSetWriter(final String 
scriptBody) throws Exception {
+        final ScriptedRecordSetWriter scriptedRecordSetWriter = new 
ScriptedRecordSetWriter();
+        runner.addControllerService(SERVICE_ID, scriptedRecordSetWriter);
+        runner.setProperty(scriptedRecordSetWriter, 
ScriptingComponentHelper.getScriptEnginePropertyBuilder().build().getName(), 
GROOVY_SCRIPT_ENGINE);
+        runner.setProperty(scriptedRecordSetWriter, 
ScriptingComponentUtils.SCRIPT_BODY, scriptBody);
+        runner.enableControllerService(scriptedRecordSetWriter);
+
+        return scriptedRecordSetWriter;
     }
 }
diff --git 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/groovy/test_record_writer_inline.groovy
 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/groovy/test_record_writer_inline.groovy
index 99cb1df80a9..34d006d151e 100644
--- 
a/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/groovy/test_record_writer_inline.groovy
+++ 
b/nifi-extension-bundles/nifi-scripting-bundle/nifi-scripting-processors/src/test/resources/groovy/test_record_writer_inline.groovy
@@ -19,7 +19,6 @@ import groovy.xml.MarkupBuilder
 
 import org.apache.nifi.controller.AbstractControllerService
 import org.apache.nifi.controller.ConfigurationContext
-import org.apache.nifi.flowfile.FlowFile
 import org.apache.nifi.logging.ComponentLog
 import org.apache.nifi.schema.access.SchemaNotFoundException
 import org.apache.nifi.serialization.RecordSetWriter
@@ -30,7 +29,6 @@ import org.apache.nifi.serialization.record.RecordSchema
 import org.apache.nifi.serialization.record.RecordSet
 import org.apache.nifi.stream.io.NonCloseableOutputStream
 
-
 class GroovyRecordSetWriter implements RecordSetWriter {
     private int recordCount = 0;
     private final OutputStream out;
@@ -99,14 +97,8 @@ class GroovyRecordSetWriter implements RecordSetWriter {
 
 class GroovyRecordSetWriterFactory extends AbstractControllerService 
implements RecordSetWriterFactory {
 
-    ComponentLog logger;
-
-    void setLogger(ComponentLog logger) {
-        this.logger = logger
-    }
-
     void onEnabled(final ConfigurationContext context) {
-        logger.info("in onEnabled")
+
     }
 
     @Override

Reply via email to