Skip to content

Fix #361: Generate Quarkus properties during camel export#380

Open
JiriOndrusek wants to merge 1 commit into
KaotoIO:mainfrom
JiriOndrusek:361-quarkus-property-translation-02
Open

Fix #361: Generate Quarkus properties during camel export#380
JiriOndrusek wants to merge 1 commit into
KaotoIO:mainfrom
JiriOndrusek:361-quarkus-property-translation-02

Conversation

@JiriOndrusek

@JiriOndrusek JiriOndrusek commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

fixes #361

During camel export --runtime=quarkus, forage properties are now translated to their Quarkus-native
equivalents directly in application.properties, eliminating the need for runtime translation by the
forage plugin.

How it works

The translation hooks into PluginExporter.getDependencies(RuntimeType) — the only plugin hook called
after application.properties is written that receives the runtime type. For Quarkus exports, it:

  1. Scans the working directory for forage.* properties
  2. Discovers ForageModuleDescriptor implementations via ServiceLoader
  3. Delegates to each descriptor's translatePropertiesForExport() to produce Quarkus-native properties
  4. Rewrites application.properties: removes the original forage keys and appends the translated Quarkus
    properties grouped by module, with comments documenting the original forage properties that were
    translated

Transformation examples

  • JDBC (default instance):
  # Before (forage)
  forage.jdbc.db.kind=postgresql
  forage.jdbc.url=jdbc:postgresql://localhost:5432/mydb
  forage.jdbc.username=admin
  forage.jdbc.password=secret
  • After (Quarkus-native, generated output)
  # Properties for jdbc
  # Translated from:
  #   forage.jdbc.db.kind=postgresql
  #   forage.jdbc.url=jdbc:postgresql://localhost:5432/mydb
  #   forage.jdbc.username=admin
  #   forage.jdbc.password=secret
  quarkus.datasource."dataSource".db-kind=postgresql
  quarkus.datasource."dataSource".jdbc.url=jdbc:postgresql://localhost:5432/mydb
  quarkus.datasource."dataSource".username=admin
  quarkus.datasource."dataSource".password=secret
  • JDBC (named instances):
  forage.ds1.jdbc.db.kind=postgresql
  forage.ds1.jdbc.url=jdbc:postgresql://localhost:5432/postgres
  forage.ds1.jdbc.username=test
  forage.ds1.jdbc.password=test
  • After
  # Properties for jdbc with prefix 'ds1'
  # Translated from:
  #   forage.ds1.jdbc.db.kind=postgresql
  #   forage.ds1.jdbc.url=jdbc:postgresql://localhost:5432/postgres
  #   forage.ds1.jdbc.username=test
  #   forage.ds1.jdbc.password=test
  quarkus.datasource."ds1".db-kind=postgresql
  quarkus.datasource."ds1".jdbc.url=jdbc:postgresql://localhost:5432/postgres
  quarkus.datasource."ds1".username=test
  quarkus.datasource."ds1".password=test
  • AI Agent (Ollama):
  forage.agent.model.kind=ollama
  forage.agent.base.url=http://localhost:11434
  forage.agent.model.name=llama3
  • After
  # Properties for agent
  # Translated from:
  #   forage.agent.model.kind=ollama
  #   forage.agent.base.url=http://localhost:11434
  #   forage.agent.model.name=llama3
  quarkus.langchain4j.ollama.base-url=http://localhost:11434
  quarkus.langchain4j.ollama.chat-model.model-id=llama3
  • AI Agent (Anthropic):
  forage.agent.model.kind=anthropic
  forage.agent.api.key=sk-test-key
  forage.agent.model.name=claude-sonnet-4-20250514
  forage.agent.temperature=0.7
  • After
  # Properties for agent
  # Translated from:
  #   forage.agent.model.kind=anthropic
  #   forage.agent.api.key=sk-test-key
  #   forage.agent.model.name=claude-sonnet-4-20250514
  #   forage.agent.temperature=0.7
  quarkus.langchain4j.anthropic.api-key=sk-test-key
  quarkus.langchain4j.anthropic.chat-model.model-name=claude-sonnet-4-20250514
  quarkus.langchain4j.anthropic.chat-model.temperature=0.7

Key design decisions

  • translatePropertiesForExport() added to ForageModuleDescriptor — defaults to translateProperties() but
    allows overriding to skip runtime-only checks (e.g., AgentModuleDescriptor skips ServiceLoader-based
    model provider lookup that would fail at export time)
  • ConfigStore cleanup — translate() populates the global ConfigStore singleton via config.register();
    the caller reloads it after translation to prevent leaking scanned values into subsequent operations
  • Non-forage properties preserved — non-forage property lines are kept intact in the rewritten output;
    each translated group includes # Translated from: comments documenting the original forage properties
    for traceability

Summary by CodeRabbit

  • New Features

    • Configuration properties now automatically translate from forage format to Quarkus-native format when exporting to Quarkus projects, improving compatibility across database, messaging, and agent modules.
  • Tests

    • Added comprehensive test coverage validating property translation logic, configuration file rewriting, and correct handling of named dataset instances.

Translate forage properties to Quarkus-native equivalents in
application.properties during `camel export --runtime=quarkus`.

Property translation runs as a side effect in getDependencies(RuntimeType),
which is the only PluginExporter hook called after application.properties
is written that receives the runtime type. The build directory is derived
from CommandLineHelper.CAMEL_JBANG_WORK_DIR (mirrors ExportBaseCommand.BUILD_DIR
which is protected and not accessible from plugins).
@JiriOndrusek
JiriOndrusek requested review from Croway and orpiske and removed request for Croway June 4, 2026 11:33
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements export-time translation of forage properties to Quarkus-native format. It adds an interface hook, wires up module descriptor discovery via ServiceLoader, builds a translator that scans and converts properties, integrates into the export plugin, and provides comprehensive tests for the translation and rewriting flows.

Changes

Export-time property translation for Quarkus export

Layer / File(s) Summary
Export-time translation interface contract
core/forage-core-common/src/main/java/io/kaoto/forage/core/common/ForageModuleDescriptor.java
New default method translatePropertiesForExport(prefix, config) delegates to translateProperties unless overridden, enabling export-time translation hooks.
Module descriptor implementations and service registration
library/ai/agents/forage-agent/src/main/java/io/kaoto/forage/agent/AgentModuleDescriptor.java, library/ai/agents/forage-agent/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor, library/cxf/forage-cxf-common/src/main/resources/META-INF/services/..., library/jdbc/forage-jdbc-common/src/main/resources/META-INF/services/..., library/jms/forage-jms-common/src/main/resources/META-INF/services/..., library/messaging/forage-spring-rabbitmq-common/src/main/resources/META-INF/services/...
AgentModuleDescriptor refactors translation into translateModelProperties helper and adds translatePropertiesForExport override. All module descriptors registered via Java SPI for runtime discovery.
Quarkus property translator utility
tooling/camel-jbang-plugin-forage/src/main/java/io/kaoto/forage/plugin/QuarkusPropertyTranslator.java
Scans forage properties from disk, discovers module descriptors via ServiceLoader, groups by named prefix, translates using translatePropertiesForExport, returns aggregated TranslationResult with error handling for missing descriptors and translation failures.
Plugin export integration and property rewriting
tooling/camel-jbang-plugin-forage/pom.xml, tooling/camel-jbang-plugin-forage/src/main/java/io/kaoto/forage/plugin/ForagePlugin.java
Adds dependencies on descriptor modules. Hooks translation into getDependencies() for Quarkus runtime. Rewrites application.properties by removing translated forage keys and appending Quarkus-native properties with metadata headers.
Translator unit tests
tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/QuarkusPropertyTranslatorTest.java
Validates prefix extraction, property scanning and translation for JDBC, Agent, and multi-instance scenarios, empty directories, and non-forage property handling.
Property file rewriting tests
tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/ForagePluginRewriteTest.java
Tests rewriting across scenarios: key removal, comment preservation, named prefix headers, translated-from metadata, and non-translated key retention.

Sequence Diagram

sequenceDiagram
  participant User as camel export --runtime=quarkus
  participant ForagePlugin
  participant QuarkusPropertyTranslator
  participant ServiceLoader
  participant ModuleDescriptor
  participant AppProperties as application.properties

  User->>ForagePlugin: getDependencies(Quarkus)
  ForagePlugin->>QuarkusPropertyTranslator: translate(buildDir)
  QuarkusPropertyTranslator->>QuarkusPropertyTranslator: scanForageProperties()
  QuarkusPropertyTranslator->>ServiceLoader: load ForageModuleDescriptors
  ServiceLoader-->>QuarkusPropertyTranslator: [Agent, JDBC, JMS, CXF, RabbitMQ]
  loop for each module type
    QuarkusPropertyTranslator->>QuarkusPropertyTranslator: groupByPrefix()
    loop for each named prefix
      QuarkusPropertyTranslator->>ModuleDescriptor: translatePropertiesForExport(prefix, config)
      ModuleDescriptor-->>QuarkusPropertyTranslator: quarkus.* properties
    end
  end
  QuarkusPropertyTranslator-->>ForagePlugin: TranslationResult
  ForagePlugin->>ForagePlugin: rewriteApplicationProperties(result)
  ForagePlugin->>AppProperties: remove forage.*, append quarkus.* entries
  AppProperties-->>User: exported with native Quarkus properties
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • KaotoIO/forage#224: Both PRs modify the core ForageModuleDescriptor abstraction; this PR adds the translatePropertiesForExport(...) hook while the referenced PR introduced the original translateProperties(...) method used by runtime adapters.

Suggested reviewers

  • orpiske
  • Croway
  • oscerd

Poem

🐰 At export time, properties transform with care,
From forage namespace to Quarkus's native air,
ServiceLoaders dance and translators chime,
Rewriting the config at just the right time! 🌱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.02% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix #361: Generate Quarkus properties during camel export' accurately and concisely summarizes the main change: implementing Quarkus property generation during export.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #361: forage.* properties are translated to Quarkus-native properties and written to application.properties during export.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #361 objectives: adding translatePropertiesForExport to ForageModuleDescriptor, implementing QuarkusPropertyTranslator, updating module descriptors, and integrating translation into ForagePlugin.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/QuarkusPropertyTranslatorTest.java (1)

129-135: ⚡ Quick win

Make named-instance prefix assertion strict.

This assertion allows unexpected extra groups to slip through. Prefer exact membership to catch regressions in prefix grouping.

✅ Suggested test tightening
             assertThat(result.groups())
                     .extracting(QuarkusPropertyTranslator.TranslationGroup::prefix)
-                    .contains("ds1", "ds2");
+                    .containsExactlyInAnyOrder("ds1", "ds2");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/QuarkusPropertyTranslatorTest.java`
around lines 129 - 135, The test currently asserts prefixes with
.extracting(QuarkusPropertyTranslator.TranslationGroup::prefix).contains("ds1",
"ds2") which allows extra unexpected groups; change that assertion to require
exact membership by using .containsOnly("ds1", "ds2") (or .containsExactly(...)
if order matters) on the extracted prefixes from result.groups() in
QuarkusPropertyTranslatorTest so the test fails when any extra prefix groups are
present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/QuarkusPropertyTranslatorTest.java`:
- Around line 129-135: The test currently asserts prefixes with
.extracting(QuarkusPropertyTranslator.TranslationGroup::prefix).contains("ds1",
"ds2") which allows extra unexpected groups; change that assertion to require
exact membership by using .containsOnly("ds1", "ds2") (or .containsExactly(...)
if order matters) on the extracted prefixes from result.groups() in
QuarkusPropertyTranslatorTest so the test fails when any extra prefix groups are
present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 35a03ae8-a441-46d5-8853-2add5f4ecb10

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca9395 and 33f56a7.

📒 Files selected for processing (12)
  • core/forage-core-common/src/main/java/io/kaoto/forage/core/common/ForageModuleDescriptor.java
  • library/ai/agents/forage-agent/src/main/java/io/kaoto/forage/agent/AgentModuleDescriptor.java
  • library/ai/agents/forage-agent/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor
  • library/cxf/forage-cxf-common/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor
  • library/jdbc/forage-jdbc-common/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor
  • library/jms/forage-jms-common/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor
  • library/messaging/forage-spring-rabbitmq-common/src/main/resources/META-INF/services/io.kaoto.forage.core.common.ForageModuleDescriptor
  • tooling/camel-jbang-plugin-forage/pom.xml
  • tooling/camel-jbang-plugin-forage/src/main/java/io/kaoto/forage/plugin/ForagePlugin.java
  • tooling/camel-jbang-plugin-forage/src/main/java/io/kaoto/forage/plugin/QuarkusPropertyTranslator.java
  • tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/ForagePluginRewriteTest.java
  • tooling/camel-jbang-plugin-forage/src/test/java/io/kaoto/forage/plugin/QuarkusPropertyTranslatorTest.java

@Croway

Croway commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

nice, does it work with forage-*.properties as well? I mean, are the properties commented out there, and added to the applciation.properties?

@JiriOndrusek

JiriOndrusek commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

nice, does it work with forage-*.properties as well? I mean, are the properties commented out there, and added to the applciation.properties?

I missed that there are forage-* properties, are those also translated to quarkus propertis?
I'm transforming only forage.*into quarkus ones (in this PR)....
though it should be easy to extend the functionality for more prefixes, if needed.

@Croway

Croway commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

I mean, there are forage-.properties files, you can have a forage property in the application.properties file, or in a forage-jdbc.properties for example (not 100% sure about the naming)

@JiriOndrusek

Copy link
Copy Markdown
Contributor Author

I mean, there are forage-.properties files, you can have a forage property in the application.properties file, or in a forage-jdbc.properties for example (not 100% sure about the naming)

you mean that, this works as well

@JiriOndrusek

Copy link
Copy Markdown
Contributor Author

all properties known to forage are translated for the quarkus rubtime) during export and are put into application.properties

@JiriOndrusek

JiriOndrusek commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@Croway I retested the export, where only forage-database.properties with content

# PostgreSQL JDBC Configuration
# Database connection settings
forage.ds1.jdbc.db.kind=postgresql
forage.ds1.jdbc.url=jdbc:postgresql://localhost:5432/postgres
forage.ds1.jdbc.username=test
forage.ds1.jdbc.password=test

were present (no application.properties)

The exported project contains only application.properties with content

# Properties for jdbc with prefix 'ds1'
# Translated from:
#   forage.ds1.jdbc.db.kind=postgresql
#   forage.ds1.jdbc.password=test
#   forage.ds1.jdbc.url=jdbc:postgresql://localhost:5432/postgres
#   forage.ds1.jdbc.username=test
quarkus.datasource."ds1".jdbc.leak-detection-interval=10M
quarkus.datasource."ds1".jdbc.url=jdbc:postgresql://localhost:5432/postgres
quarkus.datasource."ds1".jdbc.acquisition-timeout=5S
quarkus.datasource."ds1".jdbc.validation-query-timeout=3S
quarkus.datasource."ds1".db-kind=postgresql
quarkus.datasource."ds1".jdbc.initial-size=5
quarkus.datasource."ds1".jdbc.min-size=2
quarkus.datasource."ds1".jdbc.max-size=2
quarkus.datasource."ds1".password=test
quarkus.datasource."ds1".username=test

Confirmed, that the use-case is working.
(I think that export reads all properties - from application, forage-*.properties files and converts them to application.properties -> which is the only place I modify in this PR)

@Croway

Croway commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

that is great @JiriOndrusek , as we discussed let's keep the merge in hold, and merge it only after the next release (4.18.3)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export to CQ: Generate Quarkus properties instead of runtime translation

2 participants