Skip to content

CAMEL-24638: camel-jdbc/camel-sql implement SecretRotationAware to evict stale pool connections on secret rotation - #26845

Open
gnodet wants to merge 18 commits into
apache:mainfrom
gnodet:camel-24638-secret-rotation-jdbc-sql
Open

gnodet wants to merge 18 commits into
apache:mainfrom
gnodet:camel-24638-secret-rotation-jdbc-sql

Conversation

@gnodet

@gnodet gnodet commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements SecretRotationAware in JdbcComponent (camel-jdbc) and SqlComponent (camel-sql) so that JDBC connection pools evict stale connections when vault-backed database credentials are rotated.

Root Cause

JdbcComponent and SqlComponent both use a DataSource that is typically a registry bean (HikariCP pool, DBCP2 pool, etc.). This bean is not recreated during a vault-triggered context reload: DefaultContextReloadStrategy.reloadAllRoutes() clears the endpoint registry and restarts routes, but the DataSource bean persists with connections authenticated against the old password. New connections checked out from the pool after rotation continue to use the old credentials until the pool discards them naturally (e.g. on expiry or validation failure).

Fix

Both components now implement SecretRotationAware. The onSecretRotation() callback:

  1. Collects all DataSources used by the component: its own dataSource field (if set) plus DataSources held by its active endpoints (e.g. jdbc:myDs, sql:...?dataSource=#myDs), with identity-based deduplication so each pool is evicted at most once.
  2. For each DataSource, attempts HikariCP softEvictConnections() via the HikariPoolMXBean (retrieved through reflection) — this marks existing connections for eviction while allowing in-flight queries to complete.
  3. Falls back gracefully for non-HikariCP pools: logs that connections will be replaced on their natural expiry cycle. No compile-time dependency on HikariCP is added.

The shared eviction logic lives in DataSourceHelper (camel-support) — a reflection-only utility with no vendor dependency. Components pass a Function<Endpoint, DataSource> extractor so the helper stays generic.

Important limitation: eviction only closes existing connections — it does not update the pool's credentials. For pools configured with a static password (e.g. Spring Boot spring.datasource.password), the pool will re-open connections using the old credentials. This feature works out of the box only with pools that resolve credentials dynamically (e.g. HikariCredentialsProvider, the AWS JDBC wrapper secrets plugin). Quarkus uses Agroal by default, not HikariCP, so this eviction does not apply there.

Tests

  • JdbcComponentSecretRotationAwareTest (4 tests) — component-level: interface assertion, component-owned DataSource eviction, endpoint DataSource eviction (jdbc:myDs case), no DataSource configured (no throw).
  • SqlComponentSecretRotationAwareTest (6 tests) — same as above, plus DataSourceHelper-level stub tests.
  • DataSourceHelperHikariIntegrationTest (2 tests) — real HikariCP + h2: started-pool eviction and not-started-pool (null MXBean) handling.

Related

  • CAMEL-24636: SecretRotationAware SPI added to camel-core
  • CAMEL-24639: camel-http — docs only (no SPI needed; credentials flow into per-endpoint configurers cleared by route reload)
  • CAMEL-24637: camel-jms — same pattern, in progress

Hermes Agent (Claude Sonnet 4.6) on behalf of Guillaume Nodet

JdbcComponent and SqlComponent both hold a DataSource that is typically a
registry bean (HikariCP, DBCP2, ...) not recreated during a route reload.
After a vault-triggered context reload the pool still holds connections
authenticated with the old credentials.

Implement SecretRotationAware.onSecretRotation() in both components to
evict stale connections:
- HikariCP: softEvictConnections() called via reflection so that neither
  module needs a compile-time dependency on HikariCP
- Other pools: generic fallback path logs that connections will expire
  naturally (no action needed for pools that validate on borrow)

Both owned (component.setDataSource) and registry-sourced DataSources are
handled: the component iterates over all DataSource beans in the registry
plus its own dataSource field, if set.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@gnodet gnodet added the enhancement New feature or request label Sep 24, 2026
@github-actions

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 24, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-jdbc
  • components/camel-sql
  • core/camel-support

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 565 of 695 tested, 0 compile-only — current: 565 all tested

Maveniverse Scalpel detected 565 affected modules (current approach: 565).

Skip-tests mode would test 565 modules (4 direct + 33 downstream), skip tests for 0 (generated code, meta-modules)

Modules Scalpel would test (565)
  • archetypes ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-a2a ← depends on affected reactor module org.apache.camel:camel-platform-http-vertx
  • camel-activemq ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-activemq6 ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-ai-observability ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ai-observability-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ai-parent ← downstream of org.apache.camel:camel-core-model
  • camel-ai-resource ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ai-tool ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-alibaba-eventbridge ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-fc ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-kms ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-mns ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-oss ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-ots ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-parent ← downstream of org.apache.camel:camel-core-model
  • camel-alibaba-sls ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-alibaba-sms ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-amqp ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-api-component-maven-plugin ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-arangodb ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-archetype-api-component ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-archetype-component ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-archetype-dataformat ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-archetype-java ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-archetype-main ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-as2 ← depends on affected reactor module org.apache.camel:camel-jetty
  • camel-as2-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-as2-parent ← downstream of org.apache.camel:camel-core-model
  • camel-asn1 ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-asterisk ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-atmosphere-websocket ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-atom ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-attachments ← depends on affected reactor module org.apache.camel:camel-bean
  • camel-avro ← depends on affected reactor module org.apache.camel:camel-spring-xml
  • camel-avro-rpc ← depends on affected reactor module org.apache.camel:camel-spring-xml
  • camel-avro-rpc-jetty ← downstream of org.apache.camel:camel-core-model
  • camel-avro-rpc-parent ← downstream of org.apache.camel:camel-core-model
  • camel-avro-rpc-spi ← downstream of org.apache.camel:camel-core-model
  • camel-aws-bedrock ← depends on affected reactor module org.apache.camel:camel-base64
  • camel-aws-cloudtrail ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-aws-config ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-aws-parameter-store ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws-parent ← downstream of org.apache.camel:camel-core-model
  • camel-aws-secrets-manager ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws-security-hub ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-athena ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-comprehend ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-cw ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-ddb ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-ec2 ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-ecs ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-eks ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-eventbridge ← depends on affected reactor module org.apache.camel:camel-aws2-sqs
  • camel-aws2-iam ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-kinesis ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-kms ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-lambda ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-mq ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-msk ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-polly ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-redshift ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-rekognition ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-s3 ← depends on affected reactor module org.apache.camel:camel-zip-deflater
  • camel-aws2-s3-vectors ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-ses ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-sns ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-sqs ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-step-functions ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-sts ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-textract ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-timestream ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-aws2-transcribe ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-aws2-translate ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-azure-common ← downstream of org.apache.camel:camel-core-model
  • camel-azure-cosmosdb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-eventgrid ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-eventhubs ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-files ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-functions ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-azure-key-vault ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-parent ← downstream of org.apache.camel:camel-core-model
  • camel-azure-schema-registry ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-azure-servicebus ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-azure-storage-blob ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-storage-datalake ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-azure-storage-queue ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-barcode ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-base ← depends on affected reactor module org.apache.camel:camel-support
  • camel-base-engine ← depends on affected reactor module org.apache.camel:camel-support
  • camel-base64 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-bean ← depends on affected reactor module org.apache.camel:camel-support
  • camel-bean-validator ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-beanio ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-bindy ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-bonita ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-box ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-box-api ← downstream of org.apache.camel:camel-core-model
  • camel-box-parent ← downstream of org.apache.camel:camel-core-model
  • camel-braintree ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-browse ← depends on affected reactor module org.apache.camel:camel-support
  • camel-caffeine ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-camunda ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cassandraql ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-catalog-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-cbor ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-chatscript ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-chunk ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cli-connector ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cli-debug ← depends on affected reactor module org.apache.camel:camel-cli-connector
  • camel-clickhouse ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-clickup ← depends on affected reactor module org.apache.camel:camel-netty-http
  • camel-cloudevents ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cluster ← depends on affected reactor module org.apache.camel:camel-support
  • camel-cm-sms ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-coap ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cometd ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-console ← depends on affected reactor module org.apache.camel:camel-management
  • camel-consul ← depends on affected reactor module org.apache.camel:camel-spring-main
  • camel-controlbus ← depends on affected reactor module org.apache.camel:camel-support
  • camel-core ← depends on affected reactor module org.apache.camel:camel-yaml-io
  • camel-core-all ← depends on affected reactor module org.apache.camel:camel-xml-jaxp
  • camel-core-engine ← depends on affected reactor module org.apache.camel:camel-support
  • camel-core-languages ← depends on affected reactor module org.apache.camel:camel-support
  • camel-core-model ← depends on affected reactor module org.apache.camel:camel-support
  • camel-core-processor ← depends on affected reactor module org.apache.camel:camel-support
  • camel-core-reifier ← depends on affected reactor module org.apache.camel:camel-core-processor
  • camel-core-xml ← depends on affected reactor module org.apache.camel:camel-core-engine
  • camel-couchbase ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-couchdb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cron ← depends on affected reactor module org.apache.camel:camel-timer
  • camel-crypto ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-crypto-pgp ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-csv ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-cxf-common ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cxf-parent ← downstream of org.apache.camel:camel-core-model
  • camel-cxf-rest ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-cxf-soap ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-cxf-spring-common ← depends on affected reactor module org.apache.camel:camel-http-base
  • camel-cxf-spring-rest ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-cxf-spring-soap ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-cxf-spring-transport ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cxf-transport ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-cyberark-vault ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dapr ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dataformat ← depends on affected reactor module org.apache.camel:camel-support
  • camel-dataset ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-datasonnet ← depends on affected reactor module org.apache.camel:camel-core
  • camel-dataweave ← downstream of org.apache.camel:camel-core-model
  • camel-debezium-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-debezium-common-parent ← depends on affected reactor module org.apache.camel:camel-support
  • camel-debezium-db2 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debezium-maven-plugin ← depends on affected reactor module org.apache.camel:camel-support
  • camel-debezium-mongodb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debezium-mysql ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debezium-oracle ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debezium-parent ← downstream of org.apache.camel:camel-core-model
  • camel-debezium-postgres ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debezium-sqlserver ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-debug ← depends on affected reactor module org.apache.camel:camel-xml-io
  • camel-dfdl ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dhis2 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dhis2-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dhis2-parent ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-diagram ← depends on affected reactor module org.apache.camel:camel-management
  • camel-direct ← depends on affected reactor module org.apache.camel:camel-support
  • camel-disruptor ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-djl ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dns ← depends on affected reactor module org.apache.camel:camel-log
  • camel-docker ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-docling ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-drill ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dropbox ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dsl-modeline ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dsl-support ← depends on affected reactor module org.apache.camel:camel-core-model
  • camel-duckdb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-dynamic-router ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-ehcache ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-elasticsearch ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-elasticsearch-rest-client ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-event ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-exec ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-fastjson ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-fhir ← depends on affected reactor module org.apache.camel:camel-hl7
  • camel-fhir-api ← depends on affected reactor module org.apache.camel:camel-support
  • camel-fhir-parent ← downstream of org.apache.camel:camel-core-model
  • camel-file ← depends on affected reactor module org.apache.camel:camel-core-engine
  • camel-file-watch ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-flatpack ← depends on affected reactor module org.apache.camel:camel-direct
  • camel-flink ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-flowable ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-fop ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-fory ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-freemarker ← depends on affected reactor module org.apache.camel:camel-management
  • camel-ftp ← depends on affected reactor module org.apache.camel:camel-spring-xml
  • camel-ftp-common ← depends on affected reactor module org.apache.camel:camel-health
  • camel-geocoder ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-git ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-github2 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-bigquery ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-calendar ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-common ← depends on affected reactor module org.apache.camel:camel-core
  • camel-google-drive ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-firestore ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-functions ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-mail ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-parent ← downstream of org.apache.camel:camel-core-model
  • camel-google-pubsub ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-secret-manager ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-sheets ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-google-speech-to-text ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-storage ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-text-to-speech ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-vertexai ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-google-vision ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-graphql ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-grok ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-groovy ← depends on affected reactor module org.apache.camel:camel-main
  • camel-grpc ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-gson ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-hashicorp-vault ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-hazelcast ← depends on affected reactor module org.apache.camel:camel-spring-main
  • camel-health ← depends on affected reactor module org.apache.camel:camel-support
  • camel-hivemq ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-hl7 ← depends on affected reactor module org.apache.camel:camel-core
  • camel-http ← depends on affected reactor module org.apache.camel:camel-rest
  • camel-http-base ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-http-common ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-huawei-parent ← downstream of org.apache.camel:camel-core-model
  • camel-huaweicloud-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-huaweicloud-dms ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-huaweicloud-frs ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-huaweicloud-functiongraph ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-huaweicloud-iam ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-huaweicloud-imagerecognition ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-huaweicloud-obs ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-huaweicloud-smn ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-huggingface ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-cos ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-parent ← downstream of org.apache.camel:camel-core-model
  • camel-ibm-secrets-manager ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-watson-discovery ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-watson-language ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-watson-speech-to-text ← depends on affected reactor module org.apache.camel:camel-ibm-watson-text-to-speech
  • camel-ibm-watson-text-to-speech ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ibm-watsonx-ai ← depends on affected reactor module org.apache.camel:camel-vertx-websocket
  • camel-ibm-watsonx-data ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ical ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-iggy ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-ignite ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-infinispan ← depends on affected reactor module org.apache.camel:camel-stub
  • camel-infinispan-common ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-infinispan-embedded ← depends on affected reactor module org.apache.camel:camel-log
  • camel-infinispan-parent ← downstream of org.apache.camel:camel-core-model
  • camel-influxdb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-influxdb2 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-iso8583 ← depends on affected reactor module org.apache.camel:camel-groovy
  • camel-jackson ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jackson-avro ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jackson-protobuf ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jackson3 ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jackson3-avro ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jackson3-protobuf ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jackson3xml ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jacksonxml ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jactl ← depends on affected reactor module org.apache.camel:camel-core
  • camel-jandex ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-jasypt ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-java-io ← depends on affected reactor module org.apache.camel:camel-xml-io
  • camel-java-joor-dsl ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-javascript ← depends on affected reactor module org.apache.camel:camel-core
  • camel-jaxb ← depends on affected reactor module org.apache.camel:camel-spring-xml
  • camel-jbang-console ← depends on affected reactor module org.apache.camel:camel-management
  • camel-jbang-mcp ← depends on affected reactor module org.apache.camel:camel-java-joor-dsl
  • camel-jbang-plugin-mcp ← depends on affected reactor module org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-route-parser ← depends on affected reactor module org.apache.camel:camel-route-parser
  • camel-jbang-plugin-tui ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jbang-plugin-validate ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jcache ← depends on affected reactor module org.apache.camel:camel-core-languages
  • camel-jcr ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jdbc ← components/camel-jdbc/src/main/docs/jdbc-component.adoc, components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcComponent.java, components/camel-jdbc/src/test/java/org/apache/camel/component/jdbc/JdbcComponentSecretRotationAwareTest.java
  • camel-jetty ← depends on affected reactor module org.apache.camel:camel-main
  • camel-jetty-common ← depends on affected reactor module org.apache.camel:camel-jaxb
  • camel-jfr ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-jgroups ← depends on affected reactor module org.apache.camel:camel-master
  • camel-jgroups-raft ← depends on affected reactor module org.apache.camel:camel-master
  • camel-jira ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jms ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-jmx ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jolt ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jooq ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-joor ← depends on affected reactor module org.apache.camel:camel-core
  • camel-jpa ← depends on affected reactor module org.apache.camel:camel-spring-xml
  • camel-jq ← depends on affected reactor module org.apache.camel:camel-core
  • camel-jsch ← depends on affected reactor module org.apache.camel:camel-ssh
  • camel-jslt ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-json-validator ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jsonapi ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jsonata ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jsonb ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-jsonpath ← depends on affected reactor module org.apache.camel:camel-core
  • camel-jsoup ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-jt400 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-jta ← depends on affected reactor module org.apache.camel:camel-sql
  • camel-jte ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-kafka ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-kamelet ← depends on affected reactor module org.apache.camel:camel-main
  • camel-kamelet-main-support ← depends on affected reactor module org.apache.camel:camel-main
  • camel-keycloak ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-knative ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-knative-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-knative-http ← depends on affected reactor module org.apache.camel:camel-http
  • camel-knative-parent ← downstream of org.apache.camel:camel-core-model
  • camel-kserve ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-kubernetes ← depends on affected reactor module org.apache.camel:camel-log
  • camel-kudu ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-langchain4j-agent ← depends on affected reactor module org.apache.camel:camel-telemetry
  • camel-langchain4j-agent-api ← downstream of org.apache.camel:camel-core-model
  • camel-langchain4j-chat ← depends on affected reactor module org.apache.camel:camel-telemetry
  • camel-langchain4j-core ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-langchain4j-embeddings ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-langchain4j-embeddingstore ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-langchain4j-embeddingstore-api ← downstream of org.apache.camel:camel-core-model
  • camel-langchain4j-ingest ← depends on affected reactor module org.apache.camel:camel-docling
  • camel-langchain4j-tokenizer ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-langchain4j-web-search ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-language ← depends on affected reactor module org.apache.camel:camel-support
  • camel-launcher-container ← depends on affected reactor module org.apache.camel:camel-launcher
  • camel-ldap ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ldif ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-log ← depends on affected reactor module org.apache.camel:camel-support
  • camel-lra ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-lucene ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-lumberjack ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-lzf ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-mail ← depends on affected reactor module org.apache.camel:camel-quartz
  • camel-mail-microsoft-oauth ← depends on affected reactor module org.apache.camel:camel-mail
  • camel-main ← depends on affected reactor module org.apache.camel:camel-seda
  • camel-management ← depends on affected reactor module org.apache.camel:camel-core
  • camel-mapstruct ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-master ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-maven-plugin ← depends on affected reactor module org.apache.camel:camel-spring-main
  • camel-mcp-server ← depends on affected reactor module org.apache.camel:camel-openai
  • camel-mcp-server-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-mdc ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-metrics ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-micrometer ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-micrometer-observability ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-micrometer-prometheus ← depends on affected reactor module org.apache.camel:camel-platform-http-main
  • camel-microprofile-config ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-microprofile-fault-tolerance ← depends on affected reactor module org.apache.camel:camel-management
  • camel-microprofile-health ← depends on affected reactor module org.apache.camel:camel-main
  • camel-microprofile-parent ← downstream of org.apache.camel:camel-core-model
  • camel-milo ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-milvus ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-mina ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-mina-sftp ← depends on affected reactor module org.apache.camel:camel-core-languages
  • camel-minio ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-mllp ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-mock ← depends on affected reactor module org.apache.camel:camel-support
  • camel-mongodb ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-mongodb-gridfs ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-mustache ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-mvel ← depends on affected reactor module org.apache.camel:camel-core
  • camel-mybatis ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-nats ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-neo4j ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-netty ← depends on affected reactor module org.apache.camel:camel-main
  • camel-netty-http ← depends on affected reactor module org.apache.camel:camel-jetty
  • camel-oaipmh ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-oauth ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-observability-services ← depends on affected reactor module org.apache.camel:camel-management
  • camel-observation ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-ocsf ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ognl ← depends on affected reactor module org.apache.camel:camel-core
  • camel-olingo2 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-olingo2-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-olingo2-parent ← downstream of org.apache.camel:camel-core-model
  • camel-olingo4 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-olingo4-api ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-olingo4-parent ← downstream of org.apache.camel:camel-core-model
  • camel-once ← depends on affected reactor module org.apache.camel:camel-groovy
  • camel-opa ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-openai ← depends on affected reactor module org.apache.camel:camel-jackson
  • camel-openapi-java ← depends on affected reactor module org.apache.camel:camel-management
  • camel-openapi-rest-dsl-generator ← depends on affected reactor module org.apache.camel:camel-core-engine
  • camel-openapi-validator ← depends on affected reactor module org.apache.camel:camel-platform-http-vertx
  • camel-opensearch ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-openstack ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-opentelemetry ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-opentelemetry-metrics ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-opentelemetry2 ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-optaplanner ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-paho ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-paho-mqtt5 ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-parquet-avro ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pdf ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pg-replication-slot ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pgevent ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pgvector ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pinecone ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-platform-http ← depends on affected reactor module org.apache.camel:camel-http
  • camel-platform-http-jolokia ← depends on affected reactor module org.apache.camel:camel-core
  • camel-platform-http-main ← depends on affected reactor module org.apache.camel:camel-openapi-java
  • camel-platform-http-vertx ← depends on affected reactor module org.apache.camel:camel-vertx-http
  • camel-plc4x ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pqc ← depends on affected reactor module org.apache.camel:camel-crypto
  • camel-printer ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-protobuf ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-pubnub ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-pulsar ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-python ← depends on affected reactor module org.apache.camel:camel-core
  • camel-python3 ← depends on affected reactor module org.apache.camel:camel-core
  • camel-qdrant ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-quartz ← depends on affected reactor module org.apache.camel:camel-management
  • camel-quickfix ← depends on affected reactor module org.apache.camel:camel-jetty
  • camel-quickjs ← depends on affected reactor module org.apache.camel:camel-core
  • camel-reactive-streams ← depends on affected reactor module org.apache.camel:camel-management
  • camel-reactor ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-redis ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-ref ← depends on affected reactor module org.apache.camel:camel-support
  • camel-resilience4j ← depends on affected reactor module org.apache.camel:camel-management
  • camel-resilience4j-micrometer ← depends on affected reactor module org.apache.camel:camel-management
  • camel-resourceresolver-github ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-rest ← depends on affected reactor module org.apache.camel:camel-core-languages
  • camel-rest-openapi ← depends on affected reactor module org.apache.camel:camel-vertx-http
  • camel-rest-postman ← depends on affected reactor module org.apache.camel:camel-vertx-http
  • camel-restdsl-openapi-plugin ← depends on affected reactor module org.apache.camel:camel-jetty
  • camel-robotframework ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-rocketmq ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-rss ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-rxjava ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-saga ← depends on affected reactor module org.apache.camel:camel-support
  • camel-salesforce ← depends on affected reactor module org.apache.camel:camel-csv
  • camel-salesforce-codegen ← depends on affected reactor module org.apache.camel:camel-salesforce
  • camel-salesforce-parent ← downstream of org.apache.camel:camel-core-model
  • camel-sap-netweaver ← depends on affected reactor module org.apache.camel:camel-velocity
  • camel-saxon ← depends on affected reactor module org.apache.camel:camel-core
  • camel-scheduler ← depends on affected reactor module org.apache.camel:camel-support
  • camel-schematron ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-seda ← depends on affected reactor module org.apache.camel:camel-support
  • camel-semantic ← depends on affected reactor module org.apache.camel:camel-main
  • camel-servicenow ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-servicenow-maven-plugin ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-servicenow-parent ← downstream of org.apache.camel:camel-core-model
  • camel-servlet ← depends on affected reactor module org.apache.camel:camel-gson
  • camel-shell ← depends on affected reactor module org.apache.camel:camel-test-junit5
  • camel-shiro ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-sjms ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-sjms2 ← depends on affected reactor module org.apache.camel:camel-test-infra-artemis
  • camel-slack ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-smb ← depends on affected reactor module org.apache.camel:camel-test-infra-smb
  • camel-smooks ← depends on affected reactor module org.apache.camel:camel-attachments
  • camel-smpp ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-snakeyaml ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-snmp ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-soap ← depends on affected reactor module org.apache.camel:camel-cxf-soap
  • camel-solr ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-spiffe ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-splunk-hec ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-spring ← depends on affected reactor module org.apache.camel:camel-cron
  • camel-spring-ai-chat ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-ai-embeddings ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-spring-ai-image ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-spring-ai-parent ← downstream of org.apache.camel:camel-core-model
  • camel-spring-ai-vector-store ← depends on affected reactor module org.apache.camel:camel-spring-ai-embeddings
  • camel-spring-batch ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-cloud-config ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-jdbc ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-ldap ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-main ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-parent ← downstream of org.apache.camel:camel-core-model
  • camel-spring-rabbitmq ← depends on affected reactor module org.apache.camel:camel-http
  • camel-spring-redis ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-spring-security ← depends on affected reactor module org.apache.camel:camel-core-xml
  • camel-spring-ws ← depends on affected reactor module org.apache.camel:camel-jaxb
  • camel-spring-xml ← depends on affected reactor module org.apache.camel:camel-cron
  • camel-sql ← components/camel-sql/src/main/docs/sql-component.adoc, components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlComponent.java, components/camel-sql/src/test/java/org/apache/camel/component/sql/DataSourceHelperAgroalIntegrationTest.java, components/camel-sql/src/test/java/org/apache/camel/component/sql/DataSourceHelperHikariIntegrationTest.java, components/camel-sql/src/test/java/org/apache/camel/component/sql/SqlComponentSecretRotationAwareTest.java, own pom components/camel-sql/pom.xml changed
  • camel-ssh ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-state-store ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-state-store-parent ← downstream of org.apache.camel:camel-core-model
  • camel-stax ← depends on affected reactor module org.apache.camel:camel-jaxb
  • camel-stitch ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-stream ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-streamcaching-test ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-stringtemplate ← depends on affected reactor module org.apache.camel:camel-management
  • camel-stripe ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-stub ← depends on affected reactor module org.apache.camel:camel-seda
  • camel-support ← core/camel-support/src/main/java/org/apache/camel/support/DataSourceHelper.java
  • camel-swift ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-syslog ← depends on affected reactor module org.apache.camel:camel-mina
  • camel-tahu ← depends on affected reactor module org.apache.camel:camel-test-infra-core
  • camel-tarfile ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-telegram ← depends on affected reactor module org.apache.camel:camel-netty-http
  • camel-telemetry ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-telemetry-dev ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-tensorflow-serving ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-test-infra-all ← depends on affected reactor module org.apache.camel:camel-test-infra-smb
  • camel-test-infra-artemis ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-test-infra-cli ← depends on affected reactor module org.apache.camel:camel-support
  • camel-test-infra-core ← depends on affected reactor module org.apache.camel:camel-core
  • camel-test-infra-smb ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-test-junit5 ← depends on affected reactor module org.apache.camel:camel-xml-jaxb
  • camel-test-junit6 ← depends on affected reactor module org.apache.camel:camel-xml-jaxb
  • camel-test-main-junit5 ← depends on affected reactor module org.apache.camel:camel-yaml-io
  • camel-test-main-junit6 ← depends on affected reactor module org.apache.camel:camel-yaml-io
  • camel-test-parent ← downstream of org.apache.camel:camel-core-model
  • camel-test-spring-junit5 ← depends on affected reactor module org.apache.camel:camel-management
  • camel-test-spring-junit6 ← depends on affected reactor module org.apache.camel:camel-management
  • camel-thrift ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-thymeleaf ← depends on affected reactor module org.apache.camel:camel-management
  • camel-tika ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-timer ← depends on affected reactor module org.apache.camel:camel-support
  • camel-tooling-maven ← depends on affected reactor module org.apache.camel:camel-support
  • camel-toon ← depends on affected reactor module org.apache.camel:camel-test-junit5
  • camel-tracing ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-twilio ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-twitter ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-typesafe-ai ← depends on affected reactor module org.apache.camel:camel-xml-io-dsl
  • camel-ubl ← depends on affected reactor module org.apache.camel:camel-test-junit5
  • camel-undertow ← depends on affected reactor module org.apache.camel:camel-openapi-java
  • camel-undertow-spring-security ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-univocity-parsers ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-validator ← depends on affected reactor module org.apache.camel:camel-xml-jaxp
  • camel-velocity ← depends on affected reactor module org.apache.camel:camel-management
  • camel-vertx ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-vertx-common ← depends on affected reactor module org.apache.camel:camel-support
  • camel-vertx-http ← depends on affected reactor module org.apache.camel:camel-undertow
  • camel-vertx-parent ← downstream of org.apache.camel:camel-core-model
  • camel-vertx-websocket ← depends on affected reactor module org.apache.camel:camel-main
  • camel-wal ← depends on affected reactor module org.apache.camel:camel-support
  • camel-wasm ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-weather ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-weaviate ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-web3j ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-webhook ← depends on affected reactor module org.apache.camel:camel-netty-http
  • camel-whatsapp ← depends on affected reactor module org.apache.camel:camel-netty-http
  • camel-wordpress ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-workday ← depends on affected reactor module org.apache.camel:camel-mock
  • camel-xchange ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xj ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xml-io ← depends on affected reactor module org.apache.camel:camel-core-model
  • camel-xml-io-dsl ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xml-jaxb ← depends on affected reactor module org.apache.camel:camel-core-model
  • camel-xml-jaxb-dsl ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xml-jaxb-dsl-test-definition ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xml-jaxb-dsl-test-spring ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xml-jaxp ← depends on affected reactor module org.apache.camel:camel-support
  • camel-xmlsecurity ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xmpp ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-xpath ← depends on affected reactor module org.apache.camel:camel-xml-jaxp
  • camel-xslt ← depends on affected reactor module org.apache.camel:camel-xml-jaxp
  • camel-xslt-saxon ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-yaml-dsl-common ← depends on affected reactor module org.apache.camel:camel-core-engine
  • camel-yaml-dsl-validator ← depends on affected reactor module org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← depends on affected reactor module org.apache.camel:camel-yaml-dsl-validator
  • camel-yaml-io ← depends on affected reactor module org.apache.camel:camel-xml-io
  • camel-zendesk ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-zip-deflater ← depends on affected reactor module org.apache.camel:camel-test-junit6
  • camel-zipfile ← depends on affected reactor module org.apache.camel:camel-test-spring-junit6
  • camel-zookeeper ← depends on affected reactor module org.apache.camel:camel-master
  • camel-zookeeper-master ← depends on affected reactor module org.apache.camel:camel-ftp
  • components ← downstream of org.apache.camel:camel-core-model

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

Build reactor — dependencies compiled but only changed modules were tested (4 modules, 1m 15s total)

Total reactor time: 1m 15s

Module Duration Status
Camel :: SQL 41.6s SUCCESS
Camel :: Catalog :: Camel Catalog 13.5s SUCCESS
Camel :: Support 12.0s SUCCESS
Camel :: JDBC 8.3s SUCCESS

Top 20 slowest modules:

  • Camel :: SQL (41.6s)
  • Camel :: Catalog :: Camel Catalog (13.5s)
  • Camel :: Support (12.0s)
  • Camel :: JDBC (8.3s)

⚙️ View full build and test results

@gnodet
gnodet marked this pull request as ready for review September 24, 2026 11:28

@apupier apupier 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.

the method name used is suspicious, I'm unable to find it.

in test it is creating dummy DataSource class adding this method artificially so i tis not testing a real case.

searching in Hikari whole repository https://github.com/search?q=repo%3Abrettwooldridge%2FHikariCP+softEvictConnections&type=code it seems to be available only on HikaripoolMXBean and HikariPool but as far as I undertand the code it is supposed to be on a DataSource

@apupier

apupier commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

instead of forging a class with softEvictConnections in tests, we could add a test dependency to HikariCP which could allow to test effectively

…ns()

HikariCP's softEvictConnections() lives on HikariPoolMXBean, not on
HikariDataSource itself.  The previous code tried to call it directly on
the DataSource instance, which would always throw NoSuchMethodException
in production.

Fix: retrieve the MXBean via getHikariPoolMXBean() (a public method on
HikariDataSource) using reflection, then invoke softEvictConnections()
on the MXBean.  Updated tests simulate the two-step indirection.
@gnodet

gnodet commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@apupier You're right — softEvictConnections() is on HikariPoolMXBean, not on HikariDataSource directly. The previous code would always hit NoSuchMethodException in production.

Fixed in c1aa008: we now retrieve the MXBean via getHikariPoolMXBean() (a public method on HikariDataSource) using reflection, then call softEvictConnections() on it. Tests were updated to simulate the real two-step indirection correctly.

@gnodet
gnodet requested a review from apupier September 24, 2026 14:11
@gnodet

gnodet commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@apupier Thanks for catching that! You're right that softEvictConnections() is not directly on HikariDataSource — it's on HikariPoolMXBean. The fix in commit c1aa008 uses a two-step reflection approach:

  1. Call getHikariPoolMXBean() on the HikariDataSource (this is a public method on HikariDataSource) — returns a HikariPoolMXBean
  2. Call softEvictConnections() on that MXBean

This matches the standard HikariCP pattern documented in their wiki:

HikariPoolMXBean poolMBean = dataSource.getHikariPoolMXBean();
poolMBean.softEvictConnections();

The tests were also updated to simulate this two-step indirection accurately — the HikariLikeDataSource stub now exposes getHikariPoolMXBean() returning an object with softEvictConnections(), rather than putting softEvictConnections() directly on the DataSource.

@gnodet-bot gnodet-bot 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.

Review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

Two issues to address before merge.


1. Duplicate eviction logic across two components

evictDataSourceConnections is copy-pasted verbatim between JdbcComponent and SqlComponent — same code, same comments, same log messages, even the same // camel-jdbc does not need comment in SqlComponent. Any future fix (a new pool vendor, a behaviour change, a log-level adjustment) will need to be applied twice. Move it to a shared utility in camel-support or camel-core-engine, or at minimum extract it to a JdbcPoolEvictionSupport helper in one of the two modules and have the other delegate to it.

2. this.dataSource may already be in the registry — double-eviction possible

In onSecretRotation():

Set<DataSource> dataSources = getCamelContext().getRegistry().findByType(DataSource.class);
if (this.dataSource != null) {
    dataSources.add(this.dataSource);  // ← may already be in the set
}

findByType scans the full registry. If the component's own dataSource was registered under any name (the typical Spring/Quarkus setup: a @Bean DataSource bound into the Camel registry and then injected into the component via @Autowired), it will already be in dataSources, and softEvictConnections() will be called on it twice. LinkedHashSet.add() does deduplicate by identity, so this is only safe if both references are the exact same object — which they are in the common case, but relies on identity equality rather than explicit logic.

Use an explicit identity-deduplicated set:

Set<DataSource> dataSources = Collections.newSetFromMap(new IdentityHashMap<>());
dataSources.addAll(getCamelContext().getRegistry().findByType(DataSource.class));
if (this.dataSource != null) {
    dataSources.add(this.dataSource);
}

This makes the deduplication explicit and immune to DataSource implementations that override equals/hashCode in unexpected ways.


Confirmed OK

  • HikariCP API: getHikariPoolMXBean() is a public method on HikariDataSource that returns HikariPoolMXBean; softEvictConnections() is declared on the interface and implemented by HikariPool. The two-step reflection chain is correct. Verified against HikariCP 5.0.1 bytecode (javap). apupier's original concern about the method location was valid for the previous commit; the current commit is correct.
  • findByType mutability: SimpleRegistry.findByType() returns a fresh LinkedHashSet — mutation via .add() is safe.
  • Static analysis: semgrep and ast-grep found no issues in the production files.
  • Pre-fix test validation: ⚠️ dynamic check skipped — no worktree available for this PR. Static trace: the tests use hand-rolled stubs that accurately mirror the real HikariCP API shape (two-step indirection via MXBean), so the test coverage is structurally sound. Adding a real HikariCP test-scope dependency (as apupier suggested) would make this watertight, but is not a blocker given the accurate stub design.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@gnodet

gnodet commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

@apupier — addressed in c1aa008.

You're right that softEvictConnections() is not a method on HikariDataSource itself — it's declared on HikariPoolMXBean. The initial commit had the wrong call site. The fix uses the two-step chain that HikariCP exposes:

// Step 1: getHikariPoolMXBean() — public method on HikariDataSource
Method getPoolMXBean = ds.getClass().getMethod("getHikariPoolMXBean");
Object poolMXBean = getPoolMXBean.invoke(ds);

// Step 2: softEvictConnections() — declared on HikariPoolMXBean, implemented by HikariPool
Method softEvict = poolMXBean.getClass().getMethod("softEvictConnections");
softEvict.invoke(poolMXBean);

Both steps use reflection so there's no compile-time dependency on HikariCP. The eviction logic has also been extracted to DataSourceHelper.evictDataSourceConnections() in camel-support so it's no longer duplicated between the two components.

- Extract eviction logic from JdbcComponent/SqlComponent into a shared
  DataSourceHelper utility class in camel-support, eliminating the
  duplicate implementation reported in the review.
- Fix potential double-eviction by replacing findByType() result (a
  plain HashSet) + manual add with Collections.newSetFromMap(new
  IdentityHashMap<>()) so that identity-equality is used for dedup.
  A DataSource wrapper that delegates equals/hashCode to the wrapped
  instance could previously cause the same pool to be evicted twice.
- Update tests to call DataSourceHelper.evictDataSourceConnections()
  directly.
@github-actions github-actions Bot added the core label Sep 24, 2026

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

Checking the previous two findings against the new commit.

Issue 2 (IdentityHashMap for deduplication) — ✅ Fully addressed. Collections.newSetFromMap(new IdentityHashMap<>()) is used in both components, and the comment explains the rationale correctly.

Issue 1 (duplicate eviction logic) — ⚠️ Partially addressed. evictDataSourceConnections() was correctly extracted to DataSourceHelper, which removes the HikariCP reflection code from the components. But the onSecretRotation() method body is still copy-pasted word-for-word between JdbcComponent and SqlComponent — including the three-line comment block and the IdentityHashMap orchestration. Any future change (new pool vendor, different fallback strategy, log-level adjustment) still needs to be applied to both files.

One additional nit: JdbcComponentSecretRotationAwareTest.evictDataSourceConnections_genericPool_doesNotThrow() declares throws Exception, but DataSourceHelper.evictDataSourceConnections() does not throw a checked exception — this is a false throws clause that misleads readers.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@Croway

Croway commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

CAMEL-24638 asks us to refresh the credentials used by the pool and evict old connections. Where does this patch update the existing DataSource with the rotated credential? softEvictConnections() alone can create replacement connections with the original password.

Does this also need to support Agroal? DataSourceHelper only recognizes Hikari’s MXBean. An Agroal pool reaches the logging fallback without a flush. Agroal provides flush(FlushMode.GRACEFUL), while its default configuration does not guarantee replacement through borrow validation or maximum lifetime. Please cover the intended pool types with a test that rotates the credential and verifies a subsequent connection authenticates with it.

AI-generated by Codex on behalf of @Croway.

…er; fix LOG access; fix spurious throws

- Add DataSourceHelper.evictAllDataSourceConnections(Registry, DataSource, Object)
  which centralises the IdentityHashMap deduplication + registry scan + component
  data-source merging logic so both components delegate with a one-liner.
- Add a private LOG field to JdbcComponent to fix the compile error (DefaultComponent.LOG
  is private; the pre-existing createEndpoint() LOG.debug() call could not access it).
- Simplify JdbcComponent.onSecretRotation() and SqlComponent.onSecretRotation() to
  delegate to DataSourceHelper.evictAllDataSourceConnections().
- Remove now-unused imports (Collections, IdentityHashMap, Set) from both components.
- Drop spurious 'throws Exception' from JdbcComponentSecretRotationAwareTest
  .evictDataSourceConnections_genericPool_doesNotThrow() — DataSourceHelper
  .evictDataSourceConnections() does not throw a checked exception.
@Croway

Croway commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Could you explain why JdbcComponent and SqlComponent each scan and evict every DataSource in the registry? Neither component owns those pools or knows which credentials changed. Multiple pools in one application are a supported configuration: if pool A's secret rotates, this callback also acts on pool B, and both components can act on the same pool. Camel already notifies registry beans implementing SecretRotationAware; would a callback registered by the DataSource owner be a better fit? It could obtain the new credential and perform the refresh appropriate to that pool. For example, DBCP2 documents that changing its password after pool initialization has no effect.

Please also add a real rotation test using PostgreSQL with password authentication:

  1. Create an application user with password A. Open two physical pooled connections, keeping one checked out and returning the other to idle.
  2. Change the user's password to B through a separate admin connection. Verify that a new direct connection with A fails and one with B succeeds.
  3. Update the secret source and trigger Camel's normal context reload.
  4. Acquire a connection through a Camel route. Verify the query succeeds and pg_backend_pid() differs from both original connections. This demonstrates that the pool opened a new authenticated connection.
  5. Verify the connection held during rotation can finish its work and is discarded after return.

Run this scenario for each pool the PR claims to support. What behavior should the reload report if the new credentials cannot establish a connection? The current fallback only logs and continues.

AI-generated by Codex on behalf of @Croway.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

All three findings from the previous review are addressed. One new compile-breaking bug was introduced by the import cleanup.

Previous findings — status

Issue 1 (duplicate onSecretRotation() orchestration) — ✅ Fully resolved. DataSourceHelper.evictAllDataSourceConnections(Registry, DataSource, Object) is now the single implementation; both components delegate with a one-liner. The method is well-documented and has identity-based deduplication in the right place.

Issue 2 (potential double-eviction / IdentityHashMap) — ✅ Fully resolved. Centralised in DataSourceHelper, explicit identity-based dedup with a clear comment explaining why.

Nit (spurious throws Exception on _genericPool_doesNotThrow) — ✅ Fixed. evictDataSourceConnections_genericPool_doesNotThrow() no longer declares throws Exception.


New finding — compile failure (breaks CI)

See inline comment.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@gnodet

gnodet commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in bc71bd1: the test failures were caused by IllegalAccessException when invoking reflected methods on anonymous inner classes (the test stubs). Java's reflection API requires setAccessible(true) to invoke a method found via getMethod() when the declaring class is package-private (anonymous classes always are). Added setAccessible(true) on both getHikariPoolMXBean and softEvictConnections before invoke() in DataSourceHelper. This has no impact on production HikariCP usage since HikariDataSource is public.

@gnodet

gnodet commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@Croway Good questions — let me clarify the design.

Credential update: the credentials are updated before onSecretRotation() is called. The reload sequence in DefaultContextReloadStrategy.onReload() is:

  1. reloadProperties() — reloads the vault / properties sources
  2. reloadComponentProperties() — re-resolves placeholders and re-applies them to components (e.g. camel.component.sql.dataSource.password), so by this point the DataSource bean already holds the new password
  3. notifySecretRotation() — calls onSecretRotation() on all SecretRotationAware components
  4. reloadRoutes() — restarts routes

So softEvictConnections() runs after the DataSource has been reconfigured with the rotated credential. It evicts stale pooled connections so the pool opens fresh ones using the already-updated password — it does not need to carry the credential itself.

Agroal: fair point. This PR starts with HikariCP support (by far the most common pool in Camel deployments) and uses a graceful fallback for unknown pools — log and let connections expire naturally. Adding Agroal flush(FlushMode.GRACEFUL) is a natural follow-up but probably belongs in a separate JIRA so we can iterate without blocking the core mechanism. The DataSourceHelper design makes it straightforward to add new pool vendors later — each is a reflection block with a no-match fallthrough.

Integration test with real rotation: that would be valuable, but it requires a database container (Testcontainers + PostgreSQL), which is a significant test-infra addition for what is fundamentally a connection-eviction callback. The unit tests verify the reflection chain works correctly. A full end-to-end rotation test could be added as a follow-up.

@gnodet

gnodet commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@Croway

Why scan all DataSources: the SecretRotationAware callback is advisory — it says "a secret changed somewhere" but does not say which secret. This is by design (see the SecretRotationAware Javadoc: "The callback is advisory: it says that a reload was triggered, not which secrets changed"). Since the component does not know which DataSource had its credentials rotated, it evicts all visible pools. softEvictConnections() is a no-op for connections that are still valid (HikariCP validates on borrow), so over-eviction is harmless — the only cost is that idle connections get replaced slightly earlier.

As for ownership: camel-jdbc and camel-sql are the consumers of those DataSources. They are the components that will fail if stale connections remain in the pool after rotation, so they are the natural place to trigger eviction. The DataSource itself (a pool library class like HikariDataSource) cannot implement SecretRotationAware — it is a third-party class and does not know about Camel's SPI. A wrapper bean could do it, but that pushes the burden onto every user to register a custom SecretRotationAware bean for each DataSource — the whole point of this PR is to make it work out of the box.

DBCP2: you are right that DBCP2 does not pick up password changes after initialization. That is a DBCP2 limitation, not something this PR introduces — the fallback path logs that the pool does not support explicit eviction and relies on natural connection expiry + validation. If we want to support DBCP2 specifically, we would need to call setPassword() + restart() on BasicDataSource, which is a separate concern. Same as Agroal, this can be a follow-up.

Full rotation test: see the reply above — happy to add it as a follow-up JIRA, but it is a significant test-infra addition (Testcontainers + PostgreSQL + multiple pool vendors) that should not gate this PR.

@gnodet

gnodet commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @davsclaus — both points addressed in d711425:

  • Not-started pool: now uses new HikariDataSource() + setJdbcUrl(...) (lazy init), with assertNull(ds.getHikariPoolMXBean()) to verify the pool really isn't started before eviction.
  • Started pool: replaced assertDoesNotThrow with a physical connection identity check — conn.unwrap(Connection.class) before and after eviction, then assertNotSame to prove the pool replaced the evicted connection.

CI is green ✅

@gnodet

gnodet commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Both test points addressed in d711425:

  1. Not-started pool: switched to no-arg new HikariDataSource() + setters (lazy init). Added explicit assertNull(ds.getHikariPoolMXBean()) to prove the MXBean is truly null before testing eviction.

  2. Stronger assertions on started pool: replaced assertDoesNotThrow with assertNotSame(physicalBefore, physicalAfter) — unwraps the physical Connection before and after eviction, using maxPoolSize=1 to force the same slot. Proves the pool actually replaced the evicted connection.

@gnodet

gnodet commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @davsclaus — both test points fixed in d711425:

  1. Lazy pool init: evict_notStartedPool_handlesNullMXBeanGracefully now uses the no-arg HikariDataSource() constructor + setters, and assertNull(ds.getHikariPoolMXBean()) confirms the pool is truly not started.
  2. Stronger assertions: evict_startedPool_evictsIdleConnections now verifies eviction actually happened — it grabs the physical connection before eviction, calls evictDataSourceConnections(), gets a new connection, and asserts assertNotSame(physicalBefore, physicalAfter) to prove the pool replaced the evicted connection with a fresh one.

@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, the HikariCP test is now meaningful. With maxPoolSize=1, it compares the physical connection (via unwrap(Connection.class)) before and after eviction, and the not-started case checks for a null pool MXBean. LGTM.

Claude Code on behalf of davsclaus

@gnodet

gnodet commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

All review feedback addressed — davsclaus approved (LGTM), gnodet-bot approved, apupier's initial concern (MXBean indirection) was resolved. CI green. Ready for merge.

@apupier could you re-review or approve? Your Sep 24 CHANGES_REQUESTED review (about softEvictConnections() not being on HikariDataSource) was addressed — the fix now uses two-step reflection via getHikariPoolMXBean().

@apupier apupier 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.

request change for documentation part

comments:
I think the test should really be closer to real use case given the complexity of all the parts together. Here there is the eviction which is called directly on the datasource.
There is no credentials really rotated.

Note that it will be worthy to create a ticket on Camel Quarkus side to mention all the classes and methods used by reflection. They will need to be registered (or at least documented given htat we do not provide Hikari by default) to make it working in native mode.

@gnodet

gnodet commented Sep 28, 2026

Copy link
Copy Markdown
Contributor Author

@apupier Thanks for the review.

Documentation (registerMbeans): Replied inline — registerMbeans=true is not required. We call getHikariPoolMXBean() directly via reflection on the DataSource, not through JMX. See the source.

Tests closer to real use case: The latest commit (d711425) already includes a real HikariCP+h2 integration test (DataSourceHelperHikariIntegrationTest) that exercises the actual reflection path against a real HikariDataSource — both the started-pool and not-started-pool paths. This was requested and approved by @davsclaus. The test verifies that eviction actually replaces the physical connection (via unwrap() comparison), not just assertDoesNotThrow.

Camel Quarkus native reflection registration: Good point — I'll open a follow-up ticket on camel-quarkus. The classes used by reflection are HikariDataSource.getHikariPoolMXBean() and HikariPoolMXBean.softEvictConnections().

…ive mode

- Clarify that HikariCP eviction uses direct reflection on
  getHikariPoolMXBean(), not JMX — registerMbeans=true is not required.
- Add note about GraalVM native mode: reflection registration needed
  for HikariDataSource/HikariPoolMXBean classes and methods.
- Applied to both jdbc-component.adoc and sql-component.adoc
  (source + catalog copies).

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

Checking the two new commits since last APPROVE (b796416).

Previous findings — all confirmed addressed

No outstanding findings remain from any reviewer (apupier, gnodet-bot ×4, davsclaus, Croway, oscerd).

New commits

d711425 — Fix HikariCP integration test — ✅

  • Started-pool test now uses maxPoolSize=1 + minimumIdle=1 and compares physical connection identity via conn.unwrap(Connection.class) + assertNotSame. This proves eviction actually replaced the connection, not just that the call didn't throw. Correct.
  • Not-started-pool test now uses the no-arg HikariDataSource() constructor + setters (true lazy init, pool only starts on first getConnection()), with assertNull(ds.getHikariPoolMXBean()) confirming the MXBean is genuinely null. Correct — the config-based constructor (new HikariDataSource(config)) eagerly initializes the pool, which defeated the purpose of the test.

79ad28d — Clarify JMX not required, document reflection for native mode — ✅

  • "JMX registration (registerMbeans=true) is not required" — correct. getHikariPoolMXBean() is a direct method on HikariDataSource that returns the internal pool object; registerMbeans only controls whether the MBean is registered with the JMX MBeanServer for remote monitoring.
  • GraalVM native reflection NOTE — correct and useful. The two-step reflection chain (getHikariPoolMXBean() + softEvictConnections()) would need reflect-config.json entries in native mode.
  • All four doc copies (jdbc source, sql source, jdbc catalog, sql catalog) updated consistently.

Verdict

Docs and test improvements only, no production code changes. All technically accurate, all addressing davsclaus's review feedback. CI is queued (just pushed) — previous CI run was green.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — Agroal pool eviction support (ae4aa49)

New commit adds Agroal flush(GRACEFUL) detection via reflection and an integration test. The code is correct — but the documentation now contradicts the implementation.

New finding — stale documentation (4 files)

The .adoc docs in all four copies still say:

Currently only HikariCP pools are supported for active eviction
Other pool implementations (including Quarkus Agroal) are not actively evicted

This is now false — DataSourceHelper.evictDataSourceConnections() actively supports Agroal via flush(GRACEFUL). The Javadoc on DataSourceHelper was correctly updated, but the user-facing documentation was not.

See inline comment on jdbc-component.adoc — same fix needed in the other 3 copies.

Confirmed OK

  • Agroal reflection approach: The flush(FlushMode) detection via method-name + enum-type check is robust and won't false-positive on unrelated flush methods.
  • Test coverage: Integration test exercises both started and smoke paths against a real AgroalDataSource + h2.
  • ast-grep: catch (Exception e) on the new Agroal block (line 152) — same intentional pattern as the existing HikariCP block. Acceptable for reflection error handling.
  • Test dependency: agroal-api + agroal-pool added as test-scope only in camel-sql — no production dependency footprint.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment on lines +347 to +351
Currently only HikariCP pools are supported for active eviction via `softEvictConnections()`.
The eviction is triggered by calling `getHikariPoolMXBean()` directly on the `HikariDataSource` instance
via reflection — JMX registration (`registerMbeans=true`) is *not* required.
Other pool implementations (including Quarkus Agroal) are not actively evicted — existing connections
will be replaced as they expire or are validated by the pool.

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.

⚠️ Stale docs — this section was written before the Agroal commit and now contradicts DataSourceHelper, which actively supports Agroal via flush(GRACEFUL).

Update to reflect both supported pools:

Suggested change
Currently only HikariCP pools are supported for active eviction via `softEvictConnections()`.
The eviction is triggered by calling `getHikariPoolMXBean()` directly on the `HikariDataSource` instance
via reflection — JMX registration (`registerMbeans=true`) is *not* required.
Other pool implementations (including Quarkus Agroal) are not actively evicted — existing connections
will be replaced as they expire or are validated by the pool.
Currently HikariCP and Agroal (Quarkus default) pools are supported for active eviction.
HikariCP pools are evicted via `softEvictConnections()` called through `getHikariPoolMXBean()`
via reflection — JMX registration (`registerMbeans=true`) is *not* required.
Agroal pools are evicted via `flush(GRACEFUL)` called on `AgroalDataSource` via reflection.
Other pool implementations are not actively evicted — existing connections

The same fix is needed in sql-component.adoc (both source and catalog copies) and catalog/.../jdbc-component.adoc.

Also update the NOTE block below to mention the Agroal reflection classes that need GraalVM native registration (AgroalDataSource.flush, AgroalDataSource.FlushMode).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 2b58bfc. Updated all four .adoc files (jdbc/sql source + catalog) to reflect both HikariCP and Agroal support, and updated the GraalVM native reflection NOTE to include Agroal classes.

The Secret Rotation docs in all four .adoc files (jdbc/sql source + catalog)
still stated that only HikariCP was supported for active eviction and that
Agroal was not. This contradicts the implementation added in ae4aa49 which
actively supports Agroal via flush(GRACEFUL).

Updated docs to accurately describe both supported pools (HikariCP and Agroal)
and updated the GraalVM native reflection NOTE to include Agroal classes.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

The previous review (on ae4aa49) noted one outstanding issue: the .adoc documentation for both components still described only HikariCP support, despite the Agroal eviction code having been added. Commit 2b58bfc addresses this:

  • All four doc files (jdbc/sql source + catalog copies) now correctly list both HikariCP and Agroal as supported pools
  • The GraalVM native reflection registration note includes AgroalDataSource.flush(FlushMode)
  • The wording is consistent across all copies

All prior findings from previous reviews (gnodet-bot ×4, apupier, davsclaus, Croway) remain addressed. No regressions.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@gnodet
gnodet requested a review from apupier September 28, 2026 20:16

@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.

The approval still holds. The Agroal eviction via flush(FlushMode.GRACEFUL) is reasonable scope given Quarkus uses Agroal, and the docs are updated in all copies. One test-quality request inline, and one question:

  • DataSourceHelper resolves flush via ds.getClass().getMethods(). If the DataSource is a non-public wrapper or proxy class, invoke could fail with IllegalAccessException (caught and logged as WARN). Resolving flush from the public AgroalDataSource interface would be more robust. Not blocking.

Note that @apupier's change request is still open (a test that actually rotates credentials, and a Camel Quarkus ticket).

Claude Code on behalf of davsclaus

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

}

// Eviction must succeed — real AgroalDataSource.flush(GRACEFUL) via reflection
assertDoesNotThrow(() -> DataSourceHelper.evictDataSourceConnections(ds, "test-rotation"));

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.

evictDataSourceConnections swallows every exception, so assertDoesNotThrow passes even if the flush detection broke and the helper fell through to the generic log (same for line 70). Same point as for the Hikari test earlier. Suggest maxSize(1) and comparing the physical connection before and after, or metricsEnabled(true) and asserting ds.getMetrics().flushCount() > 0.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in beb6afe. The Agroal test now enables metricsEnabled() and asserts flushCount() > 0 after eviction, and uses maxSize(1) + assertNotSame on the physical connection (via unwrap(Connection.class)) to prove the pool replaced the evicted connection — same approach as the HikariCP test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 673fa2b. flush(FlushMode) is now resolved through the public AgroalDataSource interface via Class.forName("io.agroal.api.AgroalDataSource") + isInstance(ds), instead of ds.getClass().getMethods(). This handles proxy/wrapper classes correctly.

Use metricsEnabled() + flushCount() to verify flush(GRACEFUL) was
actually called via reflection, and compare physical connections
before/after eviction (maxSize=1) to prove the pool replaced the
evicted connection. Same approach as the HikariCP integration test.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

Single new commit (beb6afe) since the last review: strengthens the Agroal integration test to match the HikariCP test's rigour — metricsEnabled() + flushCount() verification, maxSize(1) forced slot recycling, physical connection identity comparison via unwrap() + assertNotSame. Correct and consistent.

All previous findings (gnodet-bot ×4, apupier, davsclaus, Croway) remain fully addressed. No new issues.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@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, the Agroal test now really checks the eviction (maxSize(1), flushCount() and a different physical connection). My approval still holds, with one fix requested inline.

Still open from before (non-blocking): resolving flush through the public AgroalDataSource interface rather than ds.getClass().getMethods(). Note that @apupier's review still asks for a test that actually rotates credentials and a Camel Quarkus ticket.

Claude Code on behalf of davsclaus

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


// GRACEFUL flush marks idle connections for eviction asynchronously;
// allow a short window for Agroal's housekeeping to destroy them
Thread.sleep(500);

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.

Please don't use Thread.sleep in tests (project rule). It's also a flakiness risk: flushPool hands a FlushTask to the housekeeping executor, so the flush is async, and if 500ms isn't enough the next getConnection() can still return the old physical connection. Suggest await().atMost(5, SECONDS).until(() -> metrics.flushCount() > flushCountBefore) instead (Awaitility is already used in camel-sql tests).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in a54a9dc. Replaced Thread.sleep(500) with await().atMost(5, SECONDS).untilAsserted() — properly handles the async nature of Agroal's flush(GRACEFUL) and complies with the project's no-Thread.sleep rule.

Replace Thread.sleep(500) with Awaitility's await().atMost(5, SECONDS)
.untilAsserted() to properly handle Agroal's async flush(GRACEFUL)
eviction. Avoids flakiness and complies with the project's
no-Thread.sleep-in-tests rule.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

New commit a54a9dcf replaces Thread.sleep(500) with Awaitility.await().atMost(5, TimeUnit.SECONDS) in DataSourceHelperAgroalIntegrationTest. Correct fix — Agroal's flush(GRACEFUL) delegates to the housekeeping executor asynchronously, so a fixed sleep was both fragile and non-idiomatic. The Awaitility approach is more robust and consistent with the project's testing conventions.

No production code changes. All previous findings remain addressed.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Resolves flush(FlushMode) from the public AgroalDataSource interface
instead of ds.getClass().getMethods(). This is more robust when the
DataSource is a proxy or non-public wrapper class, since the method
is always visible on the public interface.

Also adds an explicit Class.forName check so we skip the iteration
entirely when Agroal is not on the classpath.
@gnodet

gnodet commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

@apupier Addressing your remaining review points:

  1. Camel Quarkus ticket — created: Register reflection metadata for DataSourceHelper secret rotation (HikariCP + Agroal) camel-quarkus#9252. It documents the reflection metadata needed for both HikariCP and Agroal in native mode.

  2. Agroal flush resolution — addressed in 673fa2b: now resolves flush(FlushMode) through the public AgroalDataSource interface (Class.forName + isInstance) rather than ds.getClass().getMethods(). This is more robust with proxies and wrapper classes, as davsclaus suggested.

  3. Tests closer to real use case: the current tests use real HikariCP and Agroal pools against h2 and verify that eviction actually replaces physical connections (via unwrap(Connection.class) + assertNotSame). A full credential rotation integration test (start pool with password A → rotate to password B → verify new connections use B) would require either a PostgreSQL container in CI or a custom DataSource that reads credentials dynamically — both of which would significantly increase the test surface and CI time. This could be a follow-up, similar to the Agroal support which was also added incrementally. The current tests cover the reflection path and the eviction behavior, which is the core of this PR.

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

One new commit since the previous APPROVE (673fa2b8): resolves Agroal flush(FlushMode) through the public AgroalDataSource interface instead of ds.getClass().getMethods().

Change analysis

The Agroal detection now uses Class.forName("io.agroal.api.AgroalDataSource") → isInstance(ds) → resolve flush from agroalDsClass.getMethods() rather than scanning the concrete class's methods directly. This is strictly better:

  • Works correctly with proxied or wrapped AgroalDataSource instances (e.g. Quarkus CDI proxies)
  • Adds proper ClassNotFoundException handling for the Agroal-not-on-classpath case
  • No change to the HikariCP path or any other production code

All previous findings (gnodet-bot ×4, apupier, davsclaus, Croway) remain addressed. CI green. No issues.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@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, the Awaitility change and resolving flush through the AgroalDataSource interface both look good. Two small, non-blocking points inline.

Claude Code on behalf of davsclaus

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

// Resolved through the public AgroalDataSource interface (not ds.getClass()) so that proxy
// or wrapper classes work correctly. No compile-time dependency on agroal-api.
try {
Class<?> agroalDsClass = Class.forName("io.agroal.api.AgroalDataSource");

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.

Class.forName(String) resolves against camel-support's own classloader. If Agroal lives in a different (child) classloader than camel-support, this throws ClassNotFoundException and silently falls through to the generic fallback. Resolving it via the DataSource's classloader would be sturdier:

Class<?> agroalDsClass = Class.forName("io.agroal.api.AgroalDataSource", false, ds.getClass().getClassLoader());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7ed1cba. Now using Class.forName("io.agroal.api.AgroalDataSource", false, ds.getClass().getClassLoader()) to resolve against the DataSource's own classloader.


// GRACEFUL flush hands a FlushTask to the housekeeping executor, so the
// actual eviction is async. Use Awaitility instead of Thread.sleep to
// avoid flakiness and comply with the project's no-Thread.sleep rule.

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.

Nit: the reference to the project's no-Thread.sleep rule reads a bit odd in source; the first sentence (flush is async) is enough on its own.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 7ed1cba. Trimmed the comment to just the technical reason (flush is async).

@gnodet-bot gnodet-bot 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.

Re-review: CAMEL-24638 — SecretRotationAware for camel-jdbc / camel-sql

Delta since last review (673fa2b → 7ed1cba7): two micro-changes, both correct.

  1. Agroal classloader fix — Class.forName("io.agroal.api.AgroalDataSource", false, ds.getClass().getClassLoader()) instead of the no-arg overload. Correct: in OSGi/modular environments (Karaf, Quarkus dev-mode class isolation), the DataSource's classloader is the right one to resolve Agroal against. The false (no-initialize) parameter is also appropriate since we only need the Class object for isInstance + method reflection, not static initialization.

  2. Comment trim — removed verbose Awaitility justification comment in the Agroal integration test. No logic change.

All previous findings remain addressed. CI pending on this push but the changes are trivially safe.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@apupier apupier 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.

Tests closer to real use case: the current tests use real HikariCP and Agroal pools against h2 and verify that eviction actually replaces physical connections (via unwrap(Connection.class) + assertNotSame). A full credential rotation integration test (start pool with password A → rotate to password B → verify new connections use B) would require either a PostgreSQL container in CI or a custom DataSource that reads credentials dynamically — both of which would significantly increase the test surface and CI time. This could be a follow-up, similar to the Agroal support which was also added incrementally. The current tests cover the reflection path and the eviction behavior, which is the core of this PR.

please create a specific ticket for that because for now we have no proof that it is working end to end and I guess you have not even tested it manually locally

@gnodet

gnodet commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

@apupier Created CAMEL-25149 to track the end-to-end credential rotation integration test (with Testcontainers + PostgreSQL, covering both HikariCP and Agroal).

The Camel Quarkus ticket for native reflection registration was already created: camel-quarkus#9252.

Could you re-review or clear the changes-requested status? The documentation concern (JMX/registerMbeans) was addressed — the docs now clarify that registerMbeans=true is not required since we call getHikariPoolMXBean() directly via reflection, not through JMX.

@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 Guillaume. Both points from my last round are addressed: Agroal is now resolved through the DataSource's own classloader, and the test comment is trimmed. With the earlier rounds (eviction scoped to component/endpoint DataSources, documented credential limitation, real HikariCP and Agroal integration tests) this looks good to me. The end-to-end rotation test is tracked in CAMEL-25149.

Claude Code on behalf of davsclaus

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

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.

6 participants