Forage Catalog¶
The Forage catalog is a machine-readable metadata file that describes every factory, bean, and configuration property available in Forage. It is the foundation for tooling integration: UI designers like Kaoto consume the catalog to generate wizard-like configuration pages, enabling low-code/no-code scenarios that would otherwise require manual Java bean instantiation.
Why the Catalog Matters¶
Configuring a Camel integration with Forage beans requires knowing which providers exist, what properties each one accepts, which are required, and how they relate to each other. The catalog captures all of this metadata in a structured format so that tools can:
- Generate configuration wizards -- present factories as selectable cards, render form fields from config entries, and populate dropdowns from available beans.
- Validate properties -- catch typos, unknown keys, and invalid bean references before runtime (see Property Validation).
- Resolve dependencies -- determine which Maven artifacts to include based on the user's selections.
Catalog Files¶
The build produces these files under forage-catalog/target/generated-catalog/:
| File | Purpose |
|---|---|
forage-catalog.json | Factories with their beans, config entries, variants, and conditional beans |
forage-configuration-catalog.json | Flat list of all configuration entries grouped by module |
forage-catalog.schema.json | JSON Schema (2020-12) for the catalog |
forage-configuration-catalog.schema.json | JSON Schema for the configuration catalog |
YAML versions (forage-catalog.yaml, forage-configuration-catalog.yaml) are also generated.
Generating the Catalog¶
The forage-maven-catalog-plugin runs during the process-classes phase. It scans all Forage module dependencies for @ForageFactory and @ForageBean annotations, extracts configuration entries from ConfigEntries subclasses, and writes the catalog files.
Note
Adding a new module with the proper annotations automatically extends the catalog -- no manual catalog editing is required.
Catalog Structure¶
Top-Level Object¶
{
"version": "2.0",
"generatedBy": "forage-maven-catalog-plugin",
"timestamp": 1773133890023,
"factories": [ ... ]
}
The factories array is the core of the catalog. Each entry describes one Forage factory and everything needed to configure and use it.
Factory¶
A factory represents a high-level capability (e.g., AI Agent, DataSource, JMS Connection). Each factory maps to one or more Camel components.
{
"name": "Agent",
"factoryType": "org.apache.camel.component.langchain4j.agent.api.Agent",
"description": "Creates AI agents with configurable chat models ...",
"components": ["camel-langchain4j-agent"],
"autowired": true,
"propertiesFile": "forage-agent-factory.properties",
"variants": { ... },
"configEntries": [ ... ],
"beansByFeature": [ ... ],
"conditionalBeans": [ ... ]
}
| Field | Description |
|---|---|
name | Display name for the factory |
factoryType | Fully qualified Java type this factory produces |
description | Human-readable summary |
components | Camel component IDs this factory supports |
autowired | If true, the factory can self-configure without an explicit bean name |
propertiesFile | Default properties file name |
variants | Platform-specific implementations |
configEntries | Configuration properties for the factory |
beansByFeature | Selectable bean providers grouped by feature |
conditionalBeans | Beans automatically registered when a config flag is enabled |
Variants¶
Each factory provides up to three platform variants so that tooling can resolve the correct Maven dependency for the user's runtime:
"variants": {
"base": {
"className": "io.kaoto.forage.agent.AgentBeanFactory",
"gav": "io.kaoto.forage:forage-agent:1.2-SNAPSHOT"
},
"springboot": {
"className": "io.kaoto.forage.springboot.agent.ForageAgentAutoConfiguration",
"gav": "io.kaoto.forage:forage-agent-starter:1.2-SNAPSHOT"
},
"quarkus": {
"className": "io.kaoto.forage.quarkus.agent.deployment.ForageAgentProcessor",
"gav": "io.kaoto.forage:forage-quarkus-agent-deployment:1.2-SNAPSHOT"
}
}
A variant may also include additionalDependencies -- extra GAVs required by that platform.
Config Entries¶
Config entries define the properties a user can set. Each entry carries enough metadata for a UI to render the appropriate form control:
{
"name": "forage.agent.model.kind",
"type": "bean-name",
"description": "The model provider kind (e.g., ollama, openai)",
"required": true,
"label": "Model Kind",
"configTag": "COMMON",
"selectsFrom": "Chat Model"
}
| Field | Description |
|---|---|
name | Property key (e.g., forage.agent.api.key) |
type | Data type -- see table below |
description | Help text for the field |
required | Whether the property must be set |
defaultValue | Pre-populated value (optional) |
label | Human-readable label for the form field |
configTag | Grouping hint: COMMON, ADVANCED, or SECURITY |
selectsFrom | For bean-name type -- the feature name whose beans populate the dropdown |
Supported types:
type | UI Control | Notes |
|---|---|---|
string | Text input | General-purpose text field |
integer | Number input | Whole numbers |
double | Number input | Decimal numbers |
boolean | Toggle / checkbox | True/false flags |
password | Password input | Masked text field for secrets |
bean-name | Dropdown | Options populated from beansByFeature matching selectsFrom |
Config tags allow a UI to organize fields into expandable sections. Typically COMMON fields are shown expanded by default, while ADVANCED and SECURITY sections are collapsed.
Beans by Feature¶
Beans represent the concrete implementations a user can choose from. They are grouped by feature so that a UI can present them as selectable options -- for example, a "Memory" dropdown offering message-window, redis, and infinispan.
"beansByFeature": [
{
"feature": "Memory",
"beans": [
{
"name": "infinispan",
"description": "Distributed storage using Infinispan",
"className": "io.kaoto.forage.memory.chat.infinispan.InfinispanMemoryBeanProvider",
"gav": "io.kaoto.forage:forage-memory-infinispan:1.2-SNAPSHOT",
"propertiesFile": "forage-memory-infinispan.properties",
"configEntries": [ ... ]
},
{
"name": "redis",
"description": "Persistent storage using Redis",
"configEntries": [ ... ]
},
{
"name": "message-window",
"description": "Simple in-memory message window",
"configEntries": [ ... ]
}
]
}
]
The link between a factory's configEntries and its beansByFeature is the selectsFrom field. When a config entry has "type": "bean-name" and "selectsFrom": "Memory", the UI populates its dropdown from the beans in the "Memory" feature group. When the user selects a bean (e.g., redis), that bean's own configEntries are rendered as additional form fields.
Each bean also carries a gav field so that tooling can add the correct Maven dependency to the project.
Conditional Beans¶
Conditional beans are automatically registered in the Camel registry when a boolean config entry is enabled. Unlike beansByFeature (which are user-selectable alternatives), conditional beans are activated as a group.
"conditionalBeans": [
{
"id": "jta-transaction-policies",
"description": "JTA Transaction Policy beans for Camel transacted routes",
"configEntry": "forage.jdbc.transaction.enabled",
"beans": [
{
"name": "PROPAGATION_REQUIRED",
"javaType": "org.apache.camel.spi.TransactedPolicy",
"description": "Starts a new transaction if none exists"
},
{ "name": "MANDATORY", "..." : "..." },
{ "name": "REQUIRES_NEW", "..." : "..." }
],
"runtimeDependencies": {
"quarkus": ["mvn:io.quarkus:quarkus-narayana-jta"]
}
}
]
A conditional bean can have either a fixed name or a nameFromConfig field that references another config entry whose value becomes the bean name at runtime:
{
"nameFromConfig": "forage.jdbc.aggregation.repository.name",
"javaType": "org.apache.camel.processor.aggregate.jdbc.JdbcAggregationRepository",
"description": "Transactional JDBC aggregation repository"
}
How the Catalog Powers UI Wizards¶
The catalog is designed to provide everything a UI tool needs to generate configuration wizards without Forage-specific code. Here is the flow as implemented in Kaoto:
flowchart LR
A[Catalog JSON] --> B[Factory Gallery]
B --> C[Configuration Form]
C --> D[Bean Selection]
D --> E[Properties Output]
D --> F[Example Route]
D --> G[Maven Dependencies] Step 1: Factory Selection¶
The UI reads the factories array and renders each factory as a selectable card showing its name, description, and supported components. The user picks the capability they want to configure.
Step 2: Configuration Form¶
Once a factory is selected, the UI converts its configEntries into form fields:
- Each entry's
typedetermines the control (text input, number, password, dropdown, toggle). - Entries are grouped into expandable sections by
configTag. requiredentries are validated before submission.defaultValuepre-populates fields.labelanddescriptionprovide field labels and help text.
For bean-name entries, the UI looks up the selectsFrom feature in beansByFeature and populates a dropdown. When the user selects a bean, its own configEntries appear as additional fields.
Step 3: Multi-Instance Support¶
The wizard supports creating multiple instances of the same factory (e.g., two DataSources for different databases). Each instance gets a name prefix, and all property keys are prefixed accordingly:
# Instance "orders"
forage.orders.jdbc.url=jdbc:postgresql://localhost/orders
forage.orders.jdbc.username=admin
# Instance "inventory"
forage.inventory.jdbc.url=jdbc:postgresql://localhost/inventory
forage.inventory.jdbc.username=admin
Step 4: Output Generation¶
The wizard produces:
- A properties file with all configured values.
- An example Camel route (YAML) that uses the configured factory.
- The correct Maven dependencies resolved from variants and bean
gavcoordinates.
What Drives the Catalog¶
The catalog is entirely derived from annotations and configuration classes in the source code:
| Source | Catalog Output |
|---|---|
@ForageFactory on a class | Factory entry with name, description, components, factoryType |
@ForageFactory(variant = ...) | Populates the variants map (base, springboot, quarkus) |
@ForageFactory(conditionalBeans = ...) | Populates the conditionalBeans array |
@ForageFactory(configClass = ...) | Links the factory to its config entries |
@ForageBean on a class | Bean entry under the matching factory's beansByFeature |
@ForageBean(feature = "Memory") | Groups the bean under the "Memory" feature |
ConfigModule.of(...) | Config entry with name, type, label, description, defaultValue, configTag |
ConfigModule.ofBeanName(...) | Config entry with type: "bean-name" and selectsFrom linking to a feature |
Configuration Catalog¶
The build also produces forage-configuration-catalog.json, a flat list of all config entries grouped by module:
{
"version": "1.0",
"generatedBy": "forage-maven-catalog-plugin",
"timestamp": 1773133890023,
"modules": [
{
"artifactId": "forage-model-open-ai-common",
"groupId": "io.kaoto.forage",
"propertiesFile": "forage-model-openai.properties",
"configEntries": [ ... ]
}
]
}
This flat view is used by the property validator and by tooling that needs a complete list of all known properties without the factory/bean hierarchy.
Programmatic Access¶
The catalog model classes are available as a Maven dependency:
<dependency>
<groupId>io.kaoto.forage</groupId>
<artifactId>forage-catalog-model</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
Key classes in io.kaoto.forage.catalog.model:
| Class | Description |
|---|---|
ForageCatalog | Root object with factories list |
ForageFactory | Factory with variants, config entries, beans, conditional beans |
ForageBean | Bean provider with its own config entries and GAV |
ConfigEntry | Single configuration property with type, label, tag |
FeatureBeans | Groups beans under a named feature |
FactoryVariants / FactoryVariant | Platform-specific implementation info |
ConditionalBeanGroup / ConditionalBeanInfo | Beans conditionally registered via a config flag |
ForageConfigurationCatalog / ConfigurationModule | Flat configuration catalog model |
These classes can be deserialized from the catalog JSON using Jackson.