Skip to content

CAMEL-24589: Fix platform-http shared path consumer removal on route stop - #26054

Merged
Croway merged 4 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-24589-platform-http-shared-path-stop
Sep 4, 2026
Merged

CAMEL-24589: Fix platform-http shared path consumer removal on route stop#26054
Croway merged 4 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-24589-platform-http-shared-path-stop

Conversation

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor

Summary

Fixes CAMEL-24589: stopping one platform-http consumer on a shared path no longer unregisters sibling consumers registered for different HTTP methods.

Problem

With two consumers on the same path (e.g. GET and POST on /shared), stopping the route registered second caused the first consumer to be unregistered from the component registry. Spring Boot's CamelRequestHandlerMapping listens to these registrations, so the surviving GET route returned HTTP 405 after stopping the POST route.

Root causes in camel-platform-http:

  1. HttpEndpointModel used URI-only equals/hashCode, so only one model per path could be tracked reliably.
  2. DefaultPlatformHttpConsumer.doStop() called removeHttpEndpoint(path), removing all endpoints on that path.

Solution

  • Include the registered consumer reference in HttpEndpointModel identity (equals, hashCode).
  • Switch endpoint registry from TreeSet to LinkedHashSet so multiple consumers on the same path coexist.
  • Add removeHttpEndpoint(Consumer) / removeHttpManagementEndpoint(Consumer) with null-safe removal.
  • Call removeHttpEndpoint(platformHttpConsumer) from DefaultPlatformHttpConsumer.doStop().
  • Keep removeHttpEndpoint(String uri) for callers that intentionally remove all endpoints on a path (e.g. rest-openapi).

Tests

  • HttpEndpointModelTest — set retains multiple consumers on the same path; identity is consumer-based.
  • PlatformHttpSharedPathRouteLifecycleTest — stopping GET or POST preserves the other consumer, route restart re-registers, URI-based bulk removal, null-consumer guard.

Notes

The Spring Boot starter integration test lives in apache/camel-spring-boot; this PR fixes the core component behavior that the starter depends on.


AI-generated PR description on behalf of atiaomar1978-hub

@atiaomar1978-hub
atiaomar1978-hub marked this pull request as ready for review September 2, 2026 22:40

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix, @atiaomar1978-hub — the root-cause analysis is spot-on and the change is well-tested. I checked out the branch and ran the full camel-platform-http suite: 36 tests pass (1 skipped), including your 7 new tests. Mockito resolves transitively via camel-test-junit6, and using JUnit assertions is the right call here since the module is entirely JUnit (no AssertJ), so that follows convention.

The core fix is correct and nicely targeted: consumer-identity equals/hashCode + LinkedHashSet lets sibling consumers coexist on a shared path, and doStop() now removes only the stopping consumer's model (matching the platformHttpConsumer reference registered in doStart()). Registration/removal stay symmetric.

A couple of points to consider (non-blocking):

Visible behavior changegetHttpEndpoints() can now hold multiple entries with the same URI, so the startup log (MainHttpServerUtil) and dev console (PlatformHttpConsole) will show a shared path once per verb/consumer instead of a single merged line, and ordering changes from URI-sorted (TreeSet) to insertion order (LinkedHashSet). This is arguably more correct, but it's user-visible — worth confirming no downstream code assumes URI-uniqueness of that set, and possibly a short upgrade-guide note. (I verified nothing in apache/camel does toMap/dedup on it.)

See the two inline comments below. Overall this is close — the main thing I'd like clarified is the Comparable removal.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

@Croway Croway left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of Croway — findings from reviewing this branch, verified with local reproducers. Inline comments below cover what's touched by this diff; two more findings sit in files this PR doesn't modify, so noting them here instead:

  • DefaultRestOpenapiProcessorStrategy.doStop() (rest-openapi, line 456) and VertxMcpServerEngine.doStop() (mcp-server, line 139) still call PlatformHttpComponent.removeHttpEndpoint(String), which removes every consumer sharing that uri. That's the exact bug class this PR fixes for DefaultPlatformHttpConsumer — still reachable through these two callers. If a rest-openapi or MCP route shares a path with another platform-http route, stopping one still wipes the other's registration. Worth switching both to remove by identity (a captured Consumer for rest-openapi, or the returned HttpEndpointModel for mcp-server, since it registers with a null consumer).
  • MainHttpServerUtil's "log the endpoints summary only if changed" check (last.containsAll(endpoints)) now depends on HttpEndpointModel#equals(), which includes consumer identity. A route reload creates a fresh inner consumer, so the rebuilt model is never .equals() to the previous one even when uri/verbs are unchanged — the summary will re-log on every camel run --dev reload instead of only real changes.

…stop

When multiple platform-http consumers share the same path with different
HTTP methods, stopping one route must not unregister siblings. Track
HttpEndpointModel identity by consumer reference and remove endpoints by
consumer on doStop instead of by path alone.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use LinkedHashSet instead of TreeSet for endpoint registry, guard null
consumer removal, and add restart/null-consumer lifecycle tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Restore HttpEndpointModel Comparable with consumer-aware compareTo
- Refactor endpoint removal to a shared Predicate-based helper
- Add removeHttpEndpoint(String, Consumer) for null-consumer registrations
- Guard doStart registration when platformHttpConsumer is null
- Fix rest-openapi and MCP server to remove by consumer identity
- Stabilize MainHttpServerUtil startup summary across route reloads
- Document registry behavior change in the 4.23 upgrade guide

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor
cursor Bot force-pushed the feature/CAMEL-24589-platform-http-shared-path-stop branch from c0ec871 to c9208fa Compare September 3, 2026 15:07
@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (312f6757a89). All review feedback addressed in c9208fa. Tests: 41 passed, 1 skipped.

Cursor Agent on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Replying to @Croway's review notes on callers outside the original diff — all addressed in c9208fa:

  • DefaultRestOpenapiProcessorStrategy.doStop() — now removes by stored Consumer reference via removeHttpEndpoint(consumer) instead of removeHttpEndpoint(String).
  • VertxMcpServerEngine.doStop() — now calls removeHttpEndpoint(info.path(), null) so only the MCP registration (null consumer) is removed, not sibling routes on the same path.
  • MainHttpServerUtil — startup summary now compares uri/verbs signatures instead of full HttpEndpointModel equality, so route reloads no longer re-log when only the consumer instance changed.

Cursor Agent on behalf of atiaomar1978-hub

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

✅ Generated files have been updated

A regen commit was automatically pushed to this branch. CI will re-run shortly.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-ai/camel-mcp-server
  • components/camel-platform-http-main
  • components/camel-platform-http
  • components/camel-rest-openapi
  • docs

🔬 Scalpel shadow comparison — Scalpel: 24 tested, 26 compile-only — current: 23 all tested

Maveniverse Scalpel detected 50 affected modules (current approach: 23).

⚠️ Modules only in Scalpel (27)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 24 modules (5 direct + 19 downstream), skip tests for 26 (generated code, meta-modules)

Modules Scalpel would test (24)
  • camel-a2a
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jsonpath
  • camel-knative-http
  • camel-launcher-container
  • camel-mcp-server
  • camel-micrometer-prometheus
  • camel-oauth
  • camel-observability-services
  • camel-openapi-validator
  • camel-platform-http
  • camel-platform-http-jolokia
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-rest-openapi
  • camel-rest-postman
  • camel-restdsl-openapi-plugin
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • docs
Modules with tests skipped (26)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-ai/camel-mcp-server: 1 test(s) disabled on GitHub Actions
All tested modules (50 modules)
  • Camel :: AI :: A2A
  • Camel :: AI :: MCP Server
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JSon Path
  • Camel :: Kamelet Main
  • Camel :: Knative HTTP
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Maven Plugins :: OpenApi REST DSL Generator
  • Camel :: Micrometer :: Prometheus
  • Camel :: OAuth
  • Camel :: Observability Services
  • Camel :: OpenAPI :: Validator
  • Camel :: Platform HTTP
  • Camel :: Platform HTTP :: Jolokia
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: REST OpenApi
  • Camel :: REST Postman
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@etzel-mes

Copy link
Copy Markdown

Thanks everyone ! 👍

@Croway
Croway merged commit 840c566 into apache:main Sep 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants