etzel-mes opened a new pull request, #29263:
URL: https://github.com/apache/camel/pull/29263

   # Description
   
   JIRA: CAMEL-26645 (filed by me as mardonius; it has the reproducer).
   
   **What goes wrong.** A consumer creates its threads when it is started, and 
they inherit the thread context class loader (TCCL) of the thread starting the 
route. `AbstractCamelContext` sets the application class loader as TCCL in 
`doLifecycleChange()`, which covers `doStart()`, so routes started there have 
it. `AbstractCamelContext.start()` calls `onCamelContextFullyStarted` after 
that scope has closed, and two things happen outside it:
   
   - The supervising route controller starts its routes from that callback.
   - camel-kafka creates its consumer threads from that callback, so its TCCL 
is wrong even with the controller off.
   
   A route started with `getRouteController().startRoute(id)` later on gets the 
TCCL of the calling thread, whatever the controller.
   
   Under `camel run` the downloaded libraries are visible only through the 
application class loader, so lookups through the TCCL on those threads see only 
the parent class path. The visible case is camel-mail with 
`camel.routecontroller.enabled=true`: the IMAP consumer gets the message, the 
body is a raw stream, the attachment list is empty, and nothing is logged. 
`MailcapCommandMap` finds no `MailcapRegistryProvider` and no handler for 
multipart, so `Message.getContent()` returns the stream.
   
   **The change.** `doLifecycleChange()`, the scope `AbstractCamelContext` 
already has, is used in two more places:
   
   - `InternalRouteStartupManager.safelyStartRouteServices`, which every route 
start passes through.
   - The `onCamelContextFullyStarted` loop in `AbstractCamelContext.start()`.
   
   It restores the previous TCCL afterwards and changes nothing when no 
application class loader is set. With the deprecated `useMDCLogging` on, these 
two places also get the context id in the MDC, as `doStart()` does.
   
   Why not in `MailConsumer`, as `MailProducer` does (CAMEL-8339): a timer 
route shows the same wrong TCCL, so that would fix one symptom only. 
CAMEL-22476 solved the same cause inside camel-plc4x by passing the application 
class loader to its driver manager; that code can stay.
   
   No upgrade guide entry: there is nothing to migrate, and these routes now 
see what routes started by the context already see.
   
   **Verification.**
   
   - `RouteStartApplicationClassLoaderTest`: 8 tests. On main, 6 fail: 
supervised route, with an initial delay, excluded from supervision, restarted 
after a failed start, started manually after the context started, and a 
listener of `onCamelContextFullyStarted`. The 2 that pass on main are the 
controls: a route started by the context, and no application class loader.
   - Each of the two places is needed: without the one in 
`safelyStartRouteServices` the manual start test fails; without the one in 
`start()` the listener test fails.
   - `*Supervising*Test`, `*RouteController*Test`, `*Startup*Test`, 
`RouteAutoStartupTest`, `RouteSuspendResume*Test`, `*MDC*Test`, 
`*Lifecycle*Test`, `*Reload*Test`, `DefaultCamelContext*Test` of camel-core 
with the new test: 219 tests, no failures, 3 skipped. The new test class five 
runs in a row with `-Dsurefire.rerunFailingTestsCount=0`.
   - camel-kafka (4.24.0-SNAPSHOT, no broker needed), reading the TCCL of its 
`KafkaConsumer` threads with the application class loader set: on main not the 
application class loader, with the controller on and off; with this change the 
application class loader in both.
   - End to end with `camel run` 4.23.0 with the same change applied, Java 25, 
GreenMail 2.1.15 as the IMAP server, and a timer route next to the mail route 
(same TCCL in each run):
   
   | Route controller | Route started on | TCCL before | Attachments before | 
TCCL with this change | Attachments with this change |
   | --- | --- | --- | --- | --- | --- |
   | off | main | DependencyDownloaderClassLoader | 1 | 
DependencyDownloaderClassLoader | 1 |
   | on, `initialDelay=0` | main | AppClassLoader | 0 | 
DependencyDownloaderClassLoader | 1 |
   | on, `initialDelay=1000` | controller thread | AppClassLoader | 0 | 
DependencyDownloaderClassLoader | 1 |
   | on, route in `excludeRoutes` | main | AppClassLoader | 0 | 
DependencyDownloaderClassLoader | 1 |
   
   - `-Psourcecheck` on camel-base-engine and camel-core; the formatter and 
impsort leave no changes. No root build.
   
   @davsclaus @gnodet could you have a look? (I cannot request reviewers.)
   
   # Target
   
   - [x] I checked that the commit is targeting the correct branch (Camel 4 
uses the `main` branch)
   
   # Tracking
   - [x] If this is a large change, bug fix, or code improvement, I checked 
there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for 
the change (usually before you start working on it).
   
   # Apache Camel coding standards and style
   
   - [x] I checked that each commit in the pull request has a meaningful 
subject line and body.
   
   - [ ] I have run `mvn clean install -DskipTests` locally from root folder 
and I have committed all auto-generated changes.
   
   # AI-assisted contributions
   
   - [x] If this PR includes AI-generated code, commits have proper 
co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR 
description identifies the AI tool used.
   
   The code and tests were written with Claude Code (Claude Opus 5.5) under my 
direction; the commit carries the `Co-authored-by` trailer.
   
   _Claude Code on behalf of etzel-mes_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to