[ 
https://issues.apache.org/jira/browse/NIFI-8050?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Matt Burgess resolved NIFI-8050.
--------------------------------
    Fix Version/s: 1.10.0
         Assignee: Matt Burgess
       Resolution: Fixed

The RecordSetWriter API was changed to include a Map<String,String> argument in 
the createWriter() method. The Migration Guide 
(https://cwiki.apache.org/confluence/display/NIFI/Migration+Guidance) has been 
updated to include this documentation.

> Custom Groovy writer breaks during upgrade
> ------------------------------------------
>
>                 Key: NIFI-8050
>                 URL: https://issues.apache.org/jira/browse/NIFI-8050
>             Project: Apache NiFi
>          Issue Type: Bug
>          Components: Core Framework
>            Reporter: Pierre Villard
>            Assignee: Matt Burgess
>            Priority: Major
>             Fix For: 1.10.0
>
>
> A couple of issues when upgrading NiFi and using a custom scripted writer 
> with Groovy.
> The scripted writer was something like: 
> {code:java}
> import ...
> class GroovyRecordSetWriter implements RecordSetWriter {
>     ...
>     @Override
>     WriteResult write(Record r) throws IOException {
>         ...
>     }
>     @Override
>     String getMimeType() { ... }
>     @Override
>     WriteResult write(final RecordSet rs) throws IOException {
>         ...
>     }
>     public void beginRecordSet() throws IOException { ... }
>     @Override
>     public WriteResult finishRecordSet() throws IOException { ... }
>     @Override
>     public void close() throws IOException {}
>     @Override
>     public void flush() throws IOException {}
> }
> class GroovyRecordSetWriterFactory extends AbstractControllerService 
> implements RecordSetWriterFactory {
>     @Override
>     RecordSchema getSchema(Map<String, String> variables, RecordSchema 
> readSchema) throws SchemaNotFoundException, IOException {
>        null
>     }
>     @Override
>     RecordSetWriter createWriter(ComponentLog logger, RecordSchema schema, 
> OutputStream out) throws SchemaNotFoundException, IOException {
>        new GroovyRecordSetWriter(out)
>     }
> }
> writer = new GroovyRecordSetWriterFactory()
> {code}
> With NIFI-6318 we changed a method in the interface RecordSetWriterFactory.
> When using the above code in NiFi 1.9.2, it works fine but after an upgrade 
> on 1.11.4, this breaks. The Controller Service, when enabled, is throwing the 
> below message:
> {quote}Can't have an abstract method in a non-abstract class. The class 
> 'GroovyRecordSetWriterFactory' must be declared abstract or the method 
> 'org.apache.nifi.serialization.RecordSetWriter 
> createWriter(org.apache.nifi.logging.ComponentLog, 
> org.apache.nifi.serialization.record.RecordSchema, java.io.OutputStream, 
> java.util.Map)' must be implemented.
> {quote}
> However the controller service is successfully enabled and the processors 
> referencing it can be started. When using the ConvertRecord processor with 
> the problematic controller service, it will throw the below NPE:
> {code:java}
> 2020-11-26 15:46:13,876 ERROR [Timer-Driven Process Thread-25] 
> o.a.n.processors.standard.ConvertRecord 
> ConvertRecord[id=8b5456ae-71dc-3bd3-d0c0-df50d196fc00] Failed to process 
> StandardFlowFileRecord[uuid=adebfcf6-b449-4d01-90a7-0463930aade0,claim=StandardContentClaim
>  [resourceClaim=StandardResourceClaim[id=1606401933295-1, container=default, 
> section=1], offset=80, 
> length=296],offset=0,name=adebfcf6-b449-4d01-90a7-0463930aade0,size=296]; 
> will route to failure: java.lang.NullPointerException 
> java.lang.NullPointerException: null at 
> org.apache.nifi.processors.standard.AbstractRecordProcessor$1.process(AbstractRecordProcessor.java:151)
>  at 
> org.apache.nifi.controller.repository.StandardProcessSession.write(StandardProcessSession.java:2986)
>  at 
> org.apache.nifi.processors.standard.AbstractRecordProcessor.onTrigger(AbstractRecordProcessor.java:122)
>  at 
> org.apache.nifi.processor.AbstractProcessor.onTrigger(AbstractProcessor.java:27)
>  at 
> org.apache.nifi.controller.StandardProcessorNode.onTrigger(StandardProcessorNode.java:1173)
>  at 
> org.apache.nifi.controller.tasks.ConnectableTask.invoke(ConnectableTask.java:214)
>  at 
> org.apache.nifi.controller.scheduling.TimerDrivenSchedulingAgent$1.run(TimerDrivenSchedulingAgent.java:117)
>  at org.apache.nifi.engine.FlowEngine$2.run(FlowEngine.java:110) at 
> java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at 
> java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at 
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
>  at 
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
>  at 
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
>  at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
>  at java.lang.Thread.run(Thread.java:748)
> {code}
> The fix is quite simple, it's just required to add the proper implementation 
> method in the Groovy script. Something like:
> {code:java}
> class GroovyRecordSetWriterFactory extends AbstractControllerService 
> implements RecordSetWriterFactory {
>     @Override
>     RecordSchema getSchema(Map<String, String> variables, RecordSchema 
> readSchema) throws SchemaNotFoundException, IOException {
>        null
>     }
>     @Override
>     RecordSetWriter createWriter(ComponentLog logger, RecordSchema schema, 
> OutputStream out) throws SchemaNotFoundException, IOException {
>        new GroovyRecordSetWriter(out)
>     }
>     @Override
>     RecordSetWriter createWriter(ComponentLog logger, RecordSchema schema, 
> OutputStream out, Map<String, String> variables) throws 
> SchemaNotFoundException, IOException {
>        return createWriter(logger, schema, out)
>     }
> }
> {code}
> However, there are two things to improve:
>  * if possible the controller service should not be successfully enabled - 
> throwing a bulletin is nice but not enough in some environments where flow 
> deployment is completely automated without the access to the UI. Besides the 
> bulletin is only shown for 5 minutes and will then disappear. Besides, 
> enabling/disabling the controller service without making any change to the 
> script body won't perform the validation/compilation again and the bulletin 
> won't be shown. It can make things hard to debug/locate since the NPE is not 
> providing much info.
>  * the NPE should be handled properly to provide a more meaningful message



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to