This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 6211b526cf81 CAMEL-25783: camel-jms - the docs show how to connect to 
a broker, and the AI tools find jms for Artemis and IBM MQ (#28097)
6211b526cf81 is described below

commit 6211b526cf81b8c2202a3c63086bd53def628a0d
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Oct 19 19:57:04 2026 +0200

    CAMEL-25783: camel-jms - the docs show how to connect to a broker, and the 
AI tools find jms for Artemis and IBM MQ (#28097)
    
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../apache/camel/catalog/docs/jms-component.adoc   | 115 ++++++++++++++++++---
 .../camel-jms/src/main/docs/jms-component.adoc     | 115 ++++++++++++++++++---
 .../dsl/jbang/core/commands/ai/CatalogDocs.java    |  12 +++
 .../dsl/jbang/core/commands/ai/CatalogSamples.java |   8 +-
 .../jbang/core/commands/ai/CatalogDocsTest.java    |  12 +++
 .../jbang/core/commands/ai/CatalogSamplesTest.java |   8 ++
 6 files changed, 235 insertions(+), 35 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
index 8a6da1bbf46f..aaba25bf786a 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
@@ -35,11 +35,11 @@ for this component:
 ====
 *Using ActiveMQ*
 
-If you are using http://activemq.apache.org/[Apache ActiveMQ], you
+If you are using http://activemq.apache.org/[Apache ActiveMQ] Classic, you
 should prefer the ActiveMQ component as it has been
 optimized for ActiveMQ. All the options and
 samples on this page are also valid for the ActiveMQ
-component.
+component. For ActiveMQ Artemis, use this component, as shown in _Connecting 
to a broker_ below.
 ====
 
 [NOTE]
@@ -60,6 +60,78 @@ number of options to configure for performance, and clustered
 environments.
 ====
 
+== Connecting to a broker
+
+The JMS component needs a `ConnectionFactory` from the client library of the 
broker. Create it as a bean, and set it
+on the component with the `connectionFactory` option. Put a connection pool 
around it: without a pool, the component
+opens a new connection for every message it sends.
+
+For example, for ActiveMQ Artemis (such as the broker that `camel infra run 
artemis` starts), with the
+https://github.com/messaginghub/pooled-jms[pooled-jms] connection pool:
+
+[tabs]
+====
+Application properties::
++
+[source,properties]
+----
+camel.beans.artemisCF = 
#class:org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory
+camel.beans.artemisCF.brokerURL = tcp://localhost:61616
+camel.beans.artemisCF.user = artemis
+camel.beans.artemisCF.password = artemis
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:artemisCF
+camel.beans.pooledCF.maxConnections = 8
+camel.component.jms.connection-factory = #bean:pooledCF
+----
+
+Java::
++
+[source,java]
+----
+ActiveMQConnectionFactory artemis = new 
ActiveMQConnectionFactory("tcp://localhost:61616", "artemis", "artemis");
+JmsPoolConnectionFactory pool = new JmsPoolConnectionFactory();
+pool.setConnectionFactory(artemis);
+pool.setMaxConnections(8);
+context.getComponent("jms", JmsComponent.class).setConnectionFactory(pool);
+----
+
+Spring XML::
++
+[source,xml]
+----
+<bean id="artemisCF" 
class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
+  <property name="brokerURL" value="tcp://localhost:61616"/>
+  <property name="user" value="artemis"/>
+  <property name="password" value="artemis"/>
+</bean>
+
+<bean id="pooledCF" 
class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory" 
destroy-method="stop">
+  <property name="connectionFactory" ref="artemisCF"/>
+  <property name="maxConnections" value="8"/>
+</bean>
+
+<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
+  <property name="connectionFactory" ref="pooledCF"/>
+</bean>
+----
+====
+
+The application properties work with routes in any DSL (YAML, XML or Java) on 
Camel Main and Camel JBang. Then the
+routes use the broker as usual, for example `jms:queue:orders`.
+
+When the registry has exactly one `ConnectionFactory`, the component uses it 
without the `connectionFactory` option
+(`allowAutoWiredConnectionFactory`, which is on by default). The example has 
two, the one of the client and the pool,
+so it sets the pool on the component.
+
+`camel run` downloads the client libraries of these classes. In a Maven 
project, add
+`org.apache.artemis:artemis-jakarta-client` and `org.messaginghub:pooled-jms`.
+
+Other brokers work the same way, with the `ConnectionFactory` of their client 
library, for example
+`com.ibm.mq.jakarta.jms.MQConnectionFactory` for IBM MQ (with `hostName`, 
`port`, `channel`, `queueManager`, and
+`transportType` set to `1` for a client connection). For ActiveMQ Classic, the 
xref:activemq-component.adoc[ActiveMQ]
+component sets up the connection factory from a `brokerURL`.
+
 == URI format
 
 ----
@@ -887,24 +959,33 @@ another JMS endpoint).
 
 === Configuring different JMS providers
 
-You can configure your JMS provider in Spring XML as
-follows:
+You can configure as many JMS component instances as you wish, each with its 
own connection factory, and give each a
+unique name. For example, a component named `artemis`, with the `pooledCF` 
connection factory from _Connecting to a
+broker_ above:
 
-You can configure as many JMS component instances as you wish
-and give them *a unique name using the* `id` **attribute**. The
-preceding example configures an `activemq` component. You could do the
-same to configure MQSeries, TibCo, BEA, Sonic and so on.
+[tabs]
+====
+Application properties::
++
+[source,properties]
+----
+camel.beans.artemis = #class:org.apache.camel.component.jms.JmsComponent
+camel.beans.artemis.connectionFactory = #bean:pooledCF
+----
 
-Once you have a named JMS component, you can then refer to endpoints
-within that component using URIs. For example, for the component name,
-`activemq`, you can then refer to destinations using the URI format,
-`activemq:[queue:|topic:]destinationName`. You can use the same approach
-for all other JMS providers.
+Spring XML::
++
+[source,xml]
+----
+<bean id="artemis" class="org.apache.camel.component.jms.JmsComponent">
+  <property name="connectionFactory" ref="pooledCF"/>
+</bean>
+----
+====
 
-This works by the SpringCamelContext lazily fetching components from the
-spring context for the scheme name you use for
-Endpoint URIs and having the
-Component resolve the endpoint URIs.
+Once you have a named JMS component, you can refer to destinations of that 
component with its name as the scheme, for
+example `artemis:[queue:|topic:]destinationName`. Camel looks up the component 
by that name in the registry. You can
+do the same for other JMS providers, such as IBM MQ or TIBCO EMS.
 
 ==== Using JNDI to find the ConnectionFactory
 
diff --git a/components/camel-jms/src/main/docs/jms-component.adoc 
b/components/camel-jms/src/main/docs/jms-component.adoc
index 8a6da1bbf46f..aaba25bf786a 100644
--- a/components/camel-jms/src/main/docs/jms-component.adoc
+++ b/components/camel-jms/src/main/docs/jms-component.adoc
@@ -35,11 +35,11 @@ for this component:
 ====
 *Using ActiveMQ*
 
-If you are using http://activemq.apache.org/[Apache ActiveMQ], you
+If you are using http://activemq.apache.org/[Apache ActiveMQ] Classic, you
 should prefer the ActiveMQ component as it has been
 optimized for ActiveMQ. All the options and
 samples on this page are also valid for the ActiveMQ
-component.
+component. For ActiveMQ Artemis, use this component, as shown in _Connecting 
to a broker_ below.
 ====
 
 [NOTE]
@@ -60,6 +60,78 @@ number of options to configure for performance, and clustered
 environments.
 ====
 
+== Connecting to a broker
+
+The JMS component needs a `ConnectionFactory` from the client library of the 
broker. Create it as a bean, and set it
+on the component with the `connectionFactory` option. Put a connection pool 
around it: without a pool, the component
+opens a new connection for every message it sends.
+
+For example, for ActiveMQ Artemis (such as the broker that `camel infra run 
artemis` starts), with the
+https://github.com/messaginghub/pooled-jms[pooled-jms] connection pool:
+
+[tabs]
+====
+Application properties::
++
+[source,properties]
+----
+camel.beans.artemisCF = 
#class:org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory
+camel.beans.artemisCF.brokerURL = tcp://localhost:61616
+camel.beans.artemisCF.user = artemis
+camel.beans.artemisCF.password = artemis
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:artemisCF
+camel.beans.pooledCF.maxConnections = 8
+camel.component.jms.connection-factory = #bean:pooledCF
+----
+
+Java::
++
+[source,java]
+----
+ActiveMQConnectionFactory artemis = new 
ActiveMQConnectionFactory("tcp://localhost:61616", "artemis", "artemis");
+JmsPoolConnectionFactory pool = new JmsPoolConnectionFactory();
+pool.setConnectionFactory(artemis);
+pool.setMaxConnections(8);
+context.getComponent("jms", JmsComponent.class).setConnectionFactory(pool);
+----
+
+Spring XML::
++
+[source,xml]
+----
+<bean id="artemisCF" 
class="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory">
+  <property name="brokerURL" value="tcp://localhost:61616"/>
+  <property name="user" value="artemis"/>
+  <property name="password" value="artemis"/>
+</bean>
+
+<bean id="pooledCF" 
class="org.messaginghub.pooled.jms.JmsPoolConnectionFactory" 
destroy-method="stop">
+  <property name="connectionFactory" ref="artemisCF"/>
+  <property name="maxConnections" value="8"/>
+</bean>
+
+<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
+  <property name="connectionFactory" ref="pooledCF"/>
+</bean>
+----
+====
+
+The application properties work with routes in any DSL (YAML, XML or Java) on 
Camel Main and Camel JBang. Then the
+routes use the broker as usual, for example `jms:queue:orders`.
+
+When the registry has exactly one `ConnectionFactory`, the component uses it 
without the `connectionFactory` option
+(`allowAutoWiredConnectionFactory`, which is on by default). The example has 
two, the one of the client and the pool,
+so it sets the pool on the component.
+
+`camel run` downloads the client libraries of these classes. In a Maven 
project, add
+`org.apache.artemis:artemis-jakarta-client` and `org.messaginghub:pooled-jms`.
+
+Other brokers work the same way, with the `ConnectionFactory` of their client 
library, for example
+`com.ibm.mq.jakarta.jms.MQConnectionFactory` for IBM MQ (with `hostName`, 
`port`, `channel`, `queueManager`, and
+`transportType` set to `1` for a client connection). For ActiveMQ Classic, the 
xref:activemq-component.adoc[ActiveMQ]
+component sets up the connection factory from a `brokerURL`.
+
 == URI format
 
 ----
@@ -887,24 +959,33 @@ another JMS endpoint).
 
 === Configuring different JMS providers
 
-You can configure your JMS provider in Spring XML as
-follows:
+You can configure as many JMS component instances as you wish, each with its 
own connection factory, and give each a
+unique name. For example, a component named `artemis`, with the `pooledCF` 
connection factory from _Connecting to a
+broker_ above:
 
-You can configure as many JMS component instances as you wish
-and give them *a unique name using the* `id` **attribute**. The
-preceding example configures an `activemq` component. You could do the
-same to configure MQSeries, TibCo, BEA, Sonic and so on.
+[tabs]
+====
+Application properties::
++
+[source,properties]
+----
+camel.beans.artemis = #class:org.apache.camel.component.jms.JmsComponent
+camel.beans.artemis.connectionFactory = #bean:pooledCF
+----
 
-Once you have a named JMS component, you can then refer to endpoints
-within that component using URIs. For example, for the component name,
-`activemq`, you can then refer to destinations using the URI format,
-`activemq:[queue:|topic:]destinationName`. You can use the same approach
-for all other JMS providers.
+Spring XML::
++
+[source,xml]
+----
+<bean id="artemis" class="org.apache.camel.component.jms.JmsComponent">
+  <property name="connectionFactory" ref="pooledCF"/>
+</bean>
+----
+====
 
-This works by the SpringCamelContext lazily fetching components from the
-spring context for the scheme name you use for
-Endpoint URIs and having the
-Component resolve the endpoint URIs.
+Once you have a named JMS component, you can refer to destinations of that 
component with its name as the scheme, for
+example `artemis:[queue:|topic:]destinationName`. Camel looks up the component 
by that name in the registry. You can
+do the same for other JMS providers, such as IBM MQ or TIBCO EMS.
 
 ==== Using JNDI to find the ConnectionFactory
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
index 76074aa8e7a0..208883f172cc 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
@@ -993,6 +993,18 @@ public final class CatalogDocs {
                     matches.add(o);
                 }
             }
+            // what a component does, or a broker it reaches without a 
component of its own, such as artemis with the
+            // jms component (CAMEL-25783)
+            String[] intent = 
CatalogSamples.COMPONENT_INTENTS.get(term.trim().toLowerCase(Locale.ROOT));
+            if (intent != null && matches.stream().noneMatch(o -> 
intent[0].equals(((JsonObject) o).getString("name")))) {
+                ComponentModel m = catalog.componentModel(intent[0]);
+                if (m != null) {
+                    JsonObject o = summary("component", m.getScheme(), 
m.getTitle(), m.getDescription(), m.getLabel());
+                    o.put("syntax", m.getSyntax());
+                    o.put("note", "'" + term.trim() + "' is done with " + 
intent[1]);
+                    matches.add(0, o);
+                }
+            }
         }
         if (kind == null || "dataformat".equals(kind)) {
             for (String name : catalog.suggestDataFormatNames(term, max)) {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
index 0bb0209f06e3..fdc543f29d8b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
@@ -109,6 +109,10 @@ public final class CatalogSamples {
     private static final String[] HTTP_CALL = {
             "http", "a to: with the http component (toD: when the URI is built 
from the message, such as a path"
                     + " parameter); the response becomes the message body" };
+    // a JMS broker without a component of its own (CAMEL-25783)
+    private static final String[] JMS_BROKER = {
+            "jms", "the jms component, with the ConnectionFactory of the 
broker's client library as a bean on the"
+                   + " component (the jms page shows it under Connecting to a 
broker)" };
     private static final String[] OPENAPI_CALL = {
             "rest-openapi", "a to: with the rest-openapi component, its 
specificationUri and operationId; path and"
                             + " query parameters come from headers of the same 
name, the body is the request body" };
@@ -138,7 +142,9 @@ public final class CatalogSamples {
             Map.entry("call service", HTTP_CALL), Map.entry("call", 
HTTP_CALL), Map.entry("http call", HTTP_CALL),
             Map.entry("call api", HTTP_CALL), Map.entry("http client", 
HTTP_CALL), Map.entry("call http", HTTP_CALL),
             Map.entry("openapi client", OPENAPI_CALL), Map.entry("call by 
contract", OPENAPI_CALL),
-            Map.entry("call operation", OPENAPI_CALL));
+            Map.entry("call operation", OPENAPI_CALL),
+            Map.entry("artemis", JMS_BROKER), Map.entry("activemq artemis", 
JMS_BROKER), Map.entry("ibm mq", JMS_BROKER),
+            Map.entry("ibmmq", JMS_BROKER), Map.entry("websphere mq", 
JMS_BROKER));
 
     private static volatile Map<String, List<Map<String, String>>> samples;
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
index b93f3d60f0a3..ae686c0d8080 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
@@ -256,6 +256,18 @@ class CatalogDocsTest {
         assertEquals("==", ((JsonObject) 
eq.getCollection("operators").iterator().next()).getString("name"));
     }
 
+    @Test
+    void aBrokerWithoutAComponentOfItsOwnFindsJms() {
+        // CAMEL-25783: nothing in the catalog is named artemis, so a model 
asking for it found nothing
+        DefaultCamelCatalog catalog = new DefaultCamelCatalog();
+        for (String term : List.of("artemis", "ibm mq")) {
+            JsonArray matches = (JsonArray) CatalogDocs.find(catalog, term, 
null, 10).get("matches");
+            JsonObject first = (JsonObject) matches.get(0);
+            assertEquals("jms", first.getString("name"), term);
+            assertTrue(first.getString("note").contains("Connecting to a 
broker"), first.toJson());
+        }
+    }
+
     @Test
     void anInterfaceNameFindsTheBuiltInBeans() {
         org.apache.camel.catalog.CamelCatalog catalog = new 
org.apache.camel.catalog.DefaultCamelCatalog();
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamplesTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamplesTest.java
index 16ca551d75ee..9ae56ca3e31d 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamplesTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamplesTest.java
@@ -177,6 +177,14 @@ public class CatalogSamplesTest {
         assertThat(CatalogSamples.sample(catalog, "lookup", 
1).getString("name")).isEqualTo("enrich");
     }
 
+    @Test
+    void artemisIsTheJmsComponentWithItsConnectionFactory() {
+        // CAMEL-25783: a broker without a component of its own
+        JsonObject o = CatalogSamples.sample(new DefaultCamelCatalog(), 
"artemis", 1);
+        assertThat(o.getString("name")).isEqualTo("jms");
+        assertThat(o.getString("note")).contains("ConnectionFactory", 
"Connecting to a broker");
+    }
+
     @Test
     void callingAServiceIsTheHttpComponentNotEnrich() {
         CamelCatalog catalog = new DefaultCamelCatalog();

Reply via email to