[
https://issues.apache.org/jira/browse/CAMEL-24403?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
mayur mohan updated CAMEL-24403:
--------------------------------
Component/s: camel-mail
Description:
h2. Problem
When an IMAP message is expunged (deleted by another client or server-side
policy) between the time it is fetched by the MailConsumer and when the
on-completion commit callback fires, {code}IMAPMessage.setFlag(){code} throws
{code}jakarta.mail.MessageRemovedException{code}. This exception is constructed
without a message string so {code}getMessage(){code} returns {code}null{code},
which surfaces in the Camel error log as:
{noformat}
Error occurred during committing mail message:
com.sun.mail.imap.IMAPMessage@542a494d.
Exchange[B5882D23412732A-0000000000000013]. Caused by:
[javax.mail.MessageRemovedException - null]
{noformat}
The trailing {code}- null{code} is confusing and unhelpful to operators
diagnosing the issue.
h2. Stack Trace
{noformat}
javax.mail.MessageRemovedException
at com.sun.mail.imap.IMAPMessage.checkExpunged(IMAPMessage.java:280)
at com.sun.mail.imap.IMAPMessage.setFlags(IMAPMessage.java:1110)
at javax.mail.Message.setFlag(Message.java:596)
at
org.apache.camel.component.mail.MailConsumer.processCommit(MailConsumer.java:506)
at
org.apache.camel.component.mail.MailConsumer$1.onComplete(MailConsumer.java:237)
at
org.apache.camel.support.UnitOfWorkHelper.doneSynchronization(UnitOfWorkHelper.java:104)
at
org.apache.camel.support.UnitOfWorkHelper.doneSynchronizations(UnitOfWorkHelper.java:89)
at
org.apache.camel.impl.engine.DefaultUnitOfWork.done(DefaultUnitOfWork.java:238)
at org.apache.camel.support.UnitOfWorkHelper.doneUow(UnitOfWorkHelper.java:61)
at
org.apache.camel.impl.engine.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:770)
at
org.apache.camel.impl.engine.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:705)
at
org.apache.camel.impl.engine.CamelInternalProcessor$AsyncAfterTask.done(CamelInternalProcessor.java:263)
at org.apache.camel.AsyncCallback.run(AsyncCallback.java:44)
at
org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:193)
at
org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:185)
at
org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
at
org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
at
org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41)
at
org.apache.camel.component.mail.MailConsumer.processExchange(MailConsumer.java:449)
at
org.apache.camel.component.mail.MailConsumer.processBatch(MailConsumer.java:258)
at org.apache.camel.component.mail.MailConsumer.poll(MailConsumer.java:165)
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}
h2. Root Cause
{code}MessageRemovedException{code} extends {code}MessagingException{code} but
is constructed without a message string, so {code}e.getMessage(){code} returns
{code}null{code}. The existing {code}catch (MessagingException e){code} block
in {code}processCommit(){code} passes it directly to the exception handler,
which includes the null in the formatted log output.
h2. Fix
Catch {code}MessageRemovedException{code} before the generic
{code}MessagingException{code} handler in {code}processCommit(){code} and wrap
it with an explicit description:
{code:java}
} catch (MessageRemovedException e) {
MessagingException wrapped = new MessagingException(
"Message already removed/expunged on server (no flag update
possible)", e);
getExceptionHandler().handleException(
"Error occurred during committing mail message: " + mail, exchange,
wrapped);
} catch (MessagingException e) {
getExceptionHandler().handleException(
"Error occurred during committing mail message: " + mail, exchange,
e);
}
{code}
Expected log output after fix:
{noformat}
Caused by: [javax.mail.MessagingException - Message already removed/expunged on
server (no flag update possible)]
{noformat}
h2. Files Changed
*
{code}components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java{code}
** Added {code}jakarta.mail.MessageRemovedException{code} import
** Added dedicated {code}catch (MessageRemovedException e){code} block before
the generic {code}MessagingException{code} handler in
{code}processCommit(){code}
*
{code}components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerCommitExpungedMessageTest.java{code}
(new file)
** {code}testCommitWithExpungedMessageProducesNonNullCause{code}: verifies
{code}MessageRemovedException{code} is wrapped in a
{code}MessagingException{code} with a non-null message and root cause preserved
** {code}testCommitWithOtherMessagingExceptionPassedThroughAsIs{code}: verifies
other {code}MessagingException{code} types pass through unchanged
h2. Pull Request
https://github.com/apache/camel/pull/25553
h2. Test Results
{noformat}
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [JDK 21 / Maven 3.9]
BUILD SUCCESS
{noformat}
was:test update
> camel-mail: MessageRemovedException in processCommit causes null in error log
> -----------------------------------------------------------------------------
>
> Key: CAMEL-24403
> URL: https://issues.apache.org/jira/browse/CAMEL-24403
> Project: Camel
> Issue Type: Bug
> Components: camel-mail
> Reporter: mayur mohan
> Priority: Major
>
> h2. Problem
> When an IMAP message is expunged (deleted by another client or server-side
> policy) between the time it is fetched by the MailConsumer and when the
> on-completion commit callback fires, {code}IMAPMessage.setFlag(){code} throws
> {code}jakarta.mail.MessageRemovedException{code}. This exception is
> constructed without a message string so {code}getMessage(){code} returns
> {code}null{code}, which surfaces in the Camel error log as:
> {noformat}
> Error occurred during committing mail message:
> com.sun.mail.imap.IMAPMessage@542a494d.
> Exchange[B5882D23412732A-0000000000000013]. Caused by:
> [javax.mail.MessageRemovedException - null]
> {noformat}
> The trailing {code}- null{code} is confusing and unhelpful to operators
> diagnosing the issue.
> h2. Stack Trace
> {noformat}
> javax.mail.MessageRemovedException
> at com.sun.mail.imap.IMAPMessage.checkExpunged(IMAPMessage.java:280)
> at com.sun.mail.imap.IMAPMessage.setFlags(IMAPMessage.java:1110)
> at javax.mail.Message.setFlag(Message.java:596)
> at
> org.apache.camel.component.mail.MailConsumer.processCommit(MailConsumer.java:506)
> at
> org.apache.camel.component.mail.MailConsumer$1.onComplete(MailConsumer.java:237)
> at
> org.apache.camel.support.UnitOfWorkHelper.doneSynchronization(UnitOfWorkHelper.java:104)
> at
> org.apache.camel.support.UnitOfWorkHelper.doneSynchronizations(UnitOfWorkHelper.java:89)
> at
> org.apache.camel.impl.engine.DefaultUnitOfWork.done(DefaultUnitOfWork.java:238)
> at
> org.apache.camel.support.UnitOfWorkHelper.doneUow(UnitOfWorkHelper.java:61)
> at
> org.apache.camel.impl.engine.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:770)
> at
> org.apache.camel.impl.engine.CamelInternalProcessor$UnitOfWorkProcessorAdvice.after(CamelInternalProcessor.java:705)
> at
> org.apache.camel.impl.engine.CamelInternalProcessor$AsyncAfterTask.done(CamelInternalProcessor.java:263)
> at org.apache.camel.AsyncCallback.run(AsyncCallback.java:44)
> at
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:193)
> at
> org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)
> at org.apache.camel.processor.Pipeline.process(Pipeline.java:185)
> at
> org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:398)
> at
> org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83)
> at
> org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41)
> at
> org.apache.camel.component.mail.MailConsumer.processExchange(MailConsumer.java:449)
> at
> org.apache.camel.component.mail.MailConsumer.processBatch(MailConsumer.java:258)
> at org.apache.camel.component.mail.MailConsumer.poll(MailConsumer.java:165)
> 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}
> h2. Root Cause
> {code}MessageRemovedException{code} extends {code}MessagingException{code}
> but is constructed without a message string, so {code}e.getMessage(){code}
> returns {code}null{code}. The existing {code}catch (MessagingException
> e){code} block in {code}processCommit(){code} passes it directly to the
> exception handler, which includes the null in the formatted log output.
> h2. Fix
> Catch {code}MessageRemovedException{code} before the generic
> {code}MessagingException{code} handler in {code}processCommit(){code} and
> wrap it with an explicit description:
> {code:java}
> } catch (MessageRemovedException e) {
> MessagingException wrapped = new MessagingException(
> "Message already removed/expunged on server (no flag update
> possible)", e);
> getExceptionHandler().handleException(
> "Error occurred during committing mail message: " + mail,
> exchange, wrapped);
> } catch (MessagingException e) {
> getExceptionHandler().handleException(
> "Error occurred during committing mail message: " + mail,
> exchange, e);
> }
> {code}
> Expected log output after fix:
> {noformat}
> Caused by: [javax.mail.MessagingException - Message already removed/expunged
> on server (no flag update possible)]
> {noformat}
> h2. Files Changed
> *
> {code}components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java{code}
> ** Added {code}jakarta.mail.MessageRemovedException{code} import
> ** Added dedicated {code}catch (MessageRemovedException e){code} block before
> the generic {code}MessagingException{code} handler in
> {code}processCommit(){code}
> *
> {code}components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerCommitExpungedMessageTest.java{code}
> (new file)
> ** {code}testCommitWithExpungedMessageProducesNonNullCause{code}: verifies
> {code}MessageRemovedException{code} is wrapped in a
> {code}MessagingException{code} with a non-null message and root cause
> preserved
> ** {code}testCommitWithOtherMessagingExceptionPassedThroughAsIs{code}:
> verifies other {code}MessagingException{code} types pass through unchanged
> h2. Pull Request
> https://github.com/apache/camel/pull/25553
> h2. Test Results
> {noformat}
> Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [JDK 21 / Maven 3.9]
> BUILD SUCCESS
> {noformat}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)