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

mayur mohan updated CAMEL-24516:
--------------------------------
    Description: 
h2. Problem

{{AbstractCamelContext.forceStopLazyInitialization()}} sets {{typeConverter}}, 
{{typeConverterRegistry}} and {{injector}} to {{null}} at the tail of 
{{doStop()}}. Any async work still running on the reactive executor at that 
point (e.g. a Multicast continuation, parallel Splitter task, or Quartz SFTP 
poll) hits a bare {{NullPointerException}} at one of the ~200 unguarded 
{{getTypeConverter()}} call sites across {{core/}}.

{{DefaultReactiveExecutor.doStop()}} does no draining, so async continuations 
are not guaranteed to have finished when the tail of {{doStop()}} runs -- even 
when graceful route shutdown reports success.

h2. Stack Trace Examples

*Example 1 -- Quartz SFTP poll calling ExchangeHelper.convertToType():*

{noformat}
java.lang.NullPointerException: Cannot invoke 
"org.apache.camel.TypeConverter.convertTo(java.lang.Class, 
org.apache.camel.Exchange, Object)"
    because the return value of 
"org.apache.camel.CamelContext.getTypeConverter()" is null
    at 
org.apache.camel.support.ExchangeHelper.convertToType(ExchangeHelper.java:261)
    at 
org.apache.camel.support.AbstractExchange.getProperty(AbstractExchange.java:321)
    at 
org.apache.camel.support.DefaultExchange.getProperty(DefaultExchange.java:27)
    at 
com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.isStopOnExceptionEnabled(SapSftpConsumer.java:189)
    at 
com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.processBatch(SapSftpConsumer.java:172)
    at 
org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:206)
    at 
com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.poll(SapSftpConsumer.java:134)
    at 
org.apache.camel.support.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:202)
    at 
org.apache.camel.support.ScheduledPollConsumer.run(ScheduledPollConsumer.java:116)
    at 
org.apache.camel.pollconsumer.quartz.QuartzScheduledPollConsumerJob.execute(QuartzScheduledPollConsumerJob.java:61)
    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
    at 
org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
{noformat}

*Example 2 -- Multicast async continuation calling AbstractExchange.getOut() 
via BeanProcessor:*

{noformat}
java.lang.NullPointerException: Cannot invoke 
"org.apache.camel.TypeConverter.convertTo(java.lang.Class, 
org.apache.camel.Exchange, Object)"
    because the return value of 
"org.apache.camel.CamelContext.getTypeConverter()" is null
    at 
org.apache.camel.support.AbstractExchange.getOut(AbstractExchange.java:548)
    at org.apache.camel.support.DefaultExchange.getOut(DefaultExchange.java:27)
    at 
org.apache.camel.support.AbstractExchange.getMessage(AbstractExchange.java:569)
    at 
org.apache.camel.support.DefaultExchange.getMessage(DefaultExchange.java:27)
    at 
com.sap.gateway.ip.core.customdev.processor.IGWScriptProcessor.setAllAttachments(IGWScriptProcessor.java:595)
    at 
com.sap.gateway.ip.core.customdev.processor.IGWScriptProcessor.process(IGWScriptProcessor.java:305)
    at jdk.internal.reflect.GeneratedMethodAccessor3818.invoke(Unknown Source)
    at 
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:569)
    at 
org.apache.camel.support.ObjectHelper.invokeMethodSafe(ObjectHelper.java:403)
    at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:494)
    at 
org.apache.camel.component.bean.MethodInfo$1.doProceed(MethodInfo.java:316)
    at org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:286)
    at 
org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:146)
    at 
org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:81)
    at 
org.apache.camel.support.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:104)
    at 
com.sap.it.op.agent.collector.camel.MplInterceptor$MplAsyncProcessor.process(MplInterceptor.java:290)
    at 
org.apache.camel.support.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:104)
    at 
org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
    at 
org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.executeFromQueue(DefaultReactiveExecutor.java:224)
    at 
org.apache.camel.impl.engine.DefaultReactiveExecutor.executeFromQueue(DefaultReactiveExecutor.java:82)
    at 
org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.await(DefaultAsyncProcessorAwaitManager.java:96)
    at 
org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:85)
    at 
org.apache.camel.processor.MulticastProcessor$MulticastReactiveTask.lambda$run$1(MulticastProcessor.java:664)
    at 
org.apache.camel.util.concurrent.AsyncCompletionService$Task.run(AsyncCompletionService.java:162)
    at 
org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:193)
    at 
org.apache.camel.impl.engine.DefaultReactiveExecutor.schedule(DefaultReactiveExecutor.java:59)
    at 
org.apache.camel.processor.MulticastProcessor.lambda$schedule$1(MulticastProcessor.java:392)
    at 
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at 
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at 
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:840)
{noformat}

h2. Root Cause

{{AbstractCamelContext.forceStopLazyInitialization()}} 
({{core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java}}):

{code:java}
protected void forceStopLazyInitialization() {
    camelContextExtension.resetInjector();
    camelContextExtension.resetTypeConverterRegistry();
    camelContextExtension.resetTypeConverter(); // sets field to null
}
{code}

h2. Fix

Move the three null-and-recreate calls from {{forceStopLazyInitialization()}} 
to the start of {{forceLazyInitialization()}}, guarded by {{firstStartDone}}. 
The fields are nulled synchronously at the beginning of the next {{doStart()}} 
instead of at the end of {{doStop()}}:

- {{getTypeConverter()}} is never {{null}} during the stopped/idle window
- All ~200 unguarded call sites fixed at once with no null-checks or sentinels
- Restart-in-place ({{stop()}}/{{start()}} on the same instance) preserved

h2. Related

Supersedes CAMEL-24510 and CAMEL-24515 which attempted per-call-site fixes.

h2. PR

https://github.com/apache/camel/pull/25775

  was:
h2. Problem

{{AbstractCamelContext.forceStopLazyInitialization()}} sets {{typeConverter}}, 
{{typeConverterRegistry}} and {{injector}} to {{null}} at the tail of 
{{doStop()}}. Any async work still running on the reactive executor at that 
point (e.g. a Multicast continuation, parallel Splitter task, or Quartz SFTP 
poll) hits a bare {{NullPointerException}} at one of the ~200 unguarded 
{{getTypeConverter()}} call sites across {{core/}}.

{{DefaultReactiveExecutor.doStop()}} does no draining, so async continuations 
are not guaranteed to have finished when the tail of {{doStop()}} runs -- even 
when graceful route shutdown reports success.

h2. Root Cause

{{AbstractCamelContext.forceStopLazyInitialization()}} 
({{core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java}}):

{code:java}
protected void forceStopLazyInitialization() {
    camelContextExtension.resetInjector();
    camelContextExtension.resetTypeConverterRegistry();
    camelContextExtension.resetTypeConverter(); // sets field to null
}
{code}

h2. Fix

Move the three null-and-recreate calls from {{forceStopLazyInitialization()}} 
to the start of {{forceLazyInitialization()}}, guarded by {{firstStartDone}}. 
The fields are nulled synchronously at the beginning of the next {{doStart()}} 
instead of at the end of {{doStop()}}:

- {{getTypeConverter()}} is never {{null}} during the stopped/idle window
- All ~200 unguarded call sites fixed at once with no null-checks or sentinels
- Restart-in-place ({{stop()}}/{{start()}} on the same instance) preserved

h2. Related

Supersedes CAMEL-24510 and CAMEL-24515 which attempted per-call-site fixes.

h2. PR

https://github.com/apache/camel/pull/25775


> AbstractCamelContext: keep TypeConverter non-null after stop; reset only on 
> restart
> -----------------------------------------------------------------------------------
>
>                 Key: CAMEL-24516
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24516
>             Project: Camel
>          Issue Type: Bug
>            Reporter: mayur mohan
>            Priority: Minor
>              Labels: camel-base-engine, diagnostic
>
> h2. Problem
> {{AbstractCamelContext.forceStopLazyInitialization()}} sets 
> {{typeConverter}}, {{typeConverterRegistry}} and {{injector}} to {{null}} at 
> the tail of {{doStop()}}. Any async work still running on the reactive 
> executor at that point (e.g. a Multicast continuation, parallel Splitter 
> task, or Quartz SFTP poll) hits a bare {{NullPointerException}} at one of the 
> ~200 unguarded {{getTypeConverter()}} call sites across {{core/}}.
> {{DefaultReactiveExecutor.doStop()}} does no draining, so async continuations 
> are not guaranteed to have finished when the tail of {{doStop()}} runs -- 
> even when graceful route shutdown reports success.
> h2. Stack Trace Examples
> *Example 1 -- Quartz SFTP poll calling ExchangeHelper.convertToType():*
> {noformat}
> java.lang.NullPointerException: Cannot invoke 
> "org.apache.camel.TypeConverter.convertTo(java.lang.Class, 
> org.apache.camel.Exchange, Object)"
>     because the return value of 
> "org.apache.camel.CamelContext.getTypeConverter()" is null
>     at 
> org.apache.camel.support.ExchangeHelper.convertToType(ExchangeHelper.java:261)
>     at 
> org.apache.camel.support.AbstractExchange.getProperty(AbstractExchange.java:321)
>     at 
> org.apache.camel.support.DefaultExchange.getProperty(DefaultExchange.java:27)
>     at 
> com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.isStopOnExceptionEnabled(SapSftpConsumer.java:189)
>     at 
> com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.processBatch(SapSftpConsumer.java:172)
>     at 
> org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:206)
>     at 
> com.sap.esb.camel.ftp.sap.sftp.component.SapSftpConsumer.poll(SapSftpConsumer.java:134)
>     at 
> org.apache.camel.support.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:202)
>     at 
> org.apache.camel.support.ScheduledPollConsumer.run(ScheduledPollConsumer.java:116)
>     at 
> org.apache.camel.pollconsumer.quartz.QuartzScheduledPollConsumerJob.execute(QuartzScheduledPollConsumerJob.java:61)
>     at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
>     at 
> org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
> {noformat}
> *Example 2 -- Multicast async continuation calling AbstractExchange.getOut() 
> via BeanProcessor:*
> {noformat}
> java.lang.NullPointerException: Cannot invoke 
> "org.apache.camel.TypeConverter.convertTo(java.lang.Class, 
> org.apache.camel.Exchange, Object)"
>     because the return value of 
> "org.apache.camel.CamelContext.getTypeConverter()" is null
>     at 
> org.apache.camel.support.AbstractExchange.getOut(AbstractExchange.java:548)
>     at 
> org.apache.camel.support.DefaultExchange.getOut(DefaultExchange.java:27)
>     at 
> org.apache.camel.support.AbstractExchange.getMessage(AbstractExchange.java:569)
>     at 
> org.apache.camel.support.DefaultExchange.getMessage(DefaultExchange.java:27)
>     at 
> com.sap.gateway.ip.core.customdev.processor.IGWScriptProcessor.setAllAttachments(IGWScriptProcessor.java:595)
>     at 
> com.sap.gateway.ip.core.customdev.processor.IGWScriptProcessor.process(IGWScriptProcessor.java:305)
>     at jdk.internal.reflect.GeneratedMethodAccessor3818.invoke(Unknown Source)
>     at 
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>     at java.base/java.lang.reflect.Method.invoke(Method.java:569)
>     at 
> org.apache.camel.support.ObjectHelper.invokeMethodSafe(ObjectHelper.java:403)
>     at org.apache.camel.component.bean.MethodInfo.invoke(MethodInfo.java:494)
>     at 
> org.apache.camel.component.bean.MethodInfo$1.doProceed(MethodInfo.java:316)
>     at 
> org.apache.camel.component.bean.MethodInfo$1.proceed(MethodInfo.java:286)
>     at 
> org.apache.camel.component.bean.AbstractBeanProcessor.process(AbstractBeanProcessor.java:146)
>     at 
> org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:81)
>     at 
> org.apache.camel.support.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:104)
>     at 
> com.sap.it.op.agent.collector.camel.MplInterceptor$MplAsyncProcessor.process(MplInterceptor.java:290)
>     at 
> org.apache.camel.support.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:104)
>     at 
> org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
>     at 
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.executeFromQueue(DefaultReactiveExecutor.java:224)
>     at 
> org.apache.camel.impl.engine.DefaultReactiveExecutor.executeFromQueue(DefaultReactiveExecutor.java:82)
>     at 
> org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.await(DefaultAsyncProcessorAwaitManager.java:96)
>     at 
> org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:85)
>     at 
> org.apache.camel.processor.MulticastProcessor$MulticastReactiveTask.lambda$run$1(MulticastProcessor.java:664)
>     at 
> org.apache.camel.util.concurrent.AsyncCompletionService$Task.run(AsyncCompletionService.java:162)
>     at 
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:193)
>     at 
> org.apache.camel.impl.engine.DefaultReactiveExecutor.schedule(DefaultReactiveExecutor.java:59)
>     at 
> org.apache.camel.processor.MulticastProcessor.lambda$schedule$1(MulticastProcessor.java:392)
>     at 
> java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
>     at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
>     at 
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
>     at 
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
>     at java.base/java.lang.Thread.run(Thread.java:840)
> {noformat}
> h2. Root Cause
> {{AbstractCamelContext.forceStopLazyInitialization()}} 
> ({{core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java}}):
> {code:java}
> protected void forceStopLazyInitialization() {
>     camelContextExtension.resetInjector();
>     camelContextExtension.resetTypeConverterRegistry();
>     camelContextExtension.resetTypeConverter(); // sets field to null
> }
> {code}
> h2. Fix
> Move the three null-and-recreate calls from {{forceStopLazyInitialization()}} 
> to the start of {{forceLazyInitialization()}}, guarded by {{firstStartDone}}. 
> The fields are nulled synchronously at the beginning of the next 
> {{doStart()}} instead of at the end of {{doStop()}}:
> - {{getTypeConverter()}} is never {{null}} during the stopped/idle window
> - All ~200 unguarded call sites fixed at once with no null-checks or sentinels
> - Restart-in-place ({{stop()}}/{{start()}} on the same instance) preserved
> h2. Related
> Supersedes CAMEL-24510 and CAMEL-24515 which attempted per-call-site fixes.
> h2. PR
> https://github.com/apache/camel/pull/25775



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to