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 ab32d49ea152 CAMEL-26693: camel-activemq, camel-activemq6 - endpoints 
keep working after the component is stopped and started (#29344)
ab32d49ea152 is described below

commit ab32d49ea15215fbca4d2215fd981b29a2007b4e
Author: Federico Mariani <[email protected]>
AuthorDate: Sat Nov 7 15:49:46 2026 +0100

    CAMEL-26693: camel-activemq, camel-activemq6 - endpoints keep working after 
the component is stopped and started (#29344)
---
 .../camel/catalog/docs/activemq-component.adoc     |  26 +++
 .../camel/catalog/docs/activemq6-component.adoc    |  26 +++
 components/camel-activemq/pom.xml                  |   7 +
 .../src/main/docs/activemq-component.adoc          |  26 +++
 .../component/activemq/ActiveMQComponent.java      |  36 +++-
 .../activemq/ActiveMQComponentRestartTest.java     |  75 ++++++++
 components/camel-activemq6/pom.xml                 |  13 ++
 .../src/main/docs/activemq6-component.adoc         |  26 +++
 .../component/activemq6/ActiveMQComponent.java     |  36 +++-
 .../activemq6/ActiveMQComponentRestartTest.java    | 192 +++++++++++++++++++++
 10 files changed, 451 insertions(+), 12 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq-component.adoc
index c1adbaaebe5e..459da0fd9768 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq-component.adoc
@@ -142,3 +142,29 @@ YAML::
             message: "Received a message - ${body}"
 ----
 ====
+
+== Connection factory and transactions
+
+With only `brokerURL` set, each endpoint creates its own connection factory, 
and with `usePooledConnection=true` (the
+default) its own pool, which needs `org.messaginghub:pooled-jms` on the 
classpath. A message sent from a transacted
+route, for example 
`from("activemq:queue:in?transacted=true").to("activemq:queue:out")`, is then 
not part of the
+transaction of the consumed message: when the route fails, the consumed 
message is rolled back and delivered again,
+but the message sent to `out` is not rolled back.
+
+To send in the transaction of the consumer, set one `connectionFactory` on the 
component, for example a pooled one,
+so that the endpoints share it. A `transactionManager` that you set must use 
that same connection factory: a
+transaction manager on another connection factory does not make the message 
part of the transaction.
+
+[source,properties]
+----
+camel.beans.activemqCF = #class:org.apache.activemq.ActiveMQConnectionFactory
+camel.beans.activemqCF.brokerURL = tcp://localhost:61616
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:activemqCF
+camel.component.activemq.connection-factory = #bean:pooledCF
+----
+
+When the endpoints share one pool, they get the same connection, whose client 
id cannot be changed: give an endpoint
+with its own `clientId` (for example for a durable subscription) a 
`connectionFactory` of its own, otherwise its
+consumer cannot connect and keeps retrying. `useSingleConnection=true` cannot 
be combined with a `clientId`: the shared
+connection of the Spring `SingleConnectionFactory` refuses to set a client id.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq6-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq6-component.adoc
index d05cbdce1a20..392b9b66c892 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq6-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/activemq6-component.adoc
@@ -142,3 +142,29 @@ YAML::
             message: "Received a message - ${body}"
 ----
 ====
+
+== Connection factory and transactions
+
+With only `brokerURL` set, each endpoint creates its own connection factory, 
and with `usePooledConnection=true` (the
+default) its own pool, which needs `org.messaginghub:pooled-jms` on the 
classpath. A message sent from a transacted
+route, for example 
`from("activemq6:queue:in?transacted=true").to("activemq6:queue:out")`, is then 
not part of the
+transaction of the consumed message: when the route fails, the consumed 
message is rolled back and delivered again,
+but the message sent to `out` is not rolled back.
+
+To send in the transaction of the consumer, set one `connectionFactory` on the 
component, for example a pooled one,
+so that the endpoints share it. A `transactionManager` that you set must use 
that same connection factory: a
+transaction manager on another connection factory does not make the message 
part of the transaction.
+
+[source,properties]
+----
+camel.beans.activemqCF = #class:org.apache.activemq.ActiveMQConnectionFactory
+camel.beans.activemqCF.brokerURL = tcp://localhost:61616
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:activemqCF
+camel.component.activemq6.connection-factory = #bean:pooledCF
+----
+
+When the endpoints share one pool, they get the same connection, whose client 
id cannot be changed: give an endpoint
+with its own `clientId` (for example for a durable subscription) a 
`connectionFactory` of its own, otherwise its
+consumer cannot connect and keeps retrying. `useSingleConnection=true` cannot 
be combined with a `clientId`: the shared
+connection of the Spring `SingleConnectionFactory` refuses to set a client id.
diff --git a/components/camel-activemq/pom.xml 
b/components/camel-activemq/pom.xml
index d758fb0dbca8..2f85ab3f96d4 100644
--- a/components/camel-activemq/pom.xml
+++ b/components/camel-activemq/pom.xml
@@ -69,6 +69,13 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <!-- the pool the component uses by default, for the unit tests -->
+        <dependency>
+            <groupId>org.messaginghub</groupId>
+            <artifactId>pooled-jms</artifactId>
+            <version>${pooled-jms-version}</version>
+            <scope>test</scope>
+        </dependency>
 
     </dependencies>
 
diff --git a/components/camel-activemq/src/main/docs/activemq-component.adoc 
b/components/camel-activemq/src/main/docs/activemq-component.adoc
index c1adbaaebe5e..459da0fd9768 100644
--- a/components/camel-activemq/src/main/docs/activemq-component.adoc
+++ b/components/camel-activemq/src/main/docs/activemq-component.adoc
@@ -142,3 +142,29 @@ YAML::
             message: "Received a message - ${body}"
 ----
 ====
+
+== Connection factory and transactions
+
+With only `brokerURL` set, each endpoint creates its own connection factory, 
and with `usePooledConnection=true` (the
+default) its own pool, which needs `org.messaginghub:pooled-jms` on the 
classpath. A message sent from a transacted
+route, for example 
`from("activemq:queue:in?transacted=true").to("activemq:queue:out")`, is then 
not part of the
+transaction of the consumed message: when the route fails, the consumed 
message is rolled back and delivered again,
+but the message sent to `out` is not rolled back.
+
+To send in the transaction of the consumer, set one `connectionFactory` on the 
component, for example a pooled one,
+so that the endpoints share it. A `transactionManager` that you set must use 
that same connection factory: a
+transaction manager on another connection factory does not make the message 
part of the transaction.
+
+[source,properties]
+----
+camel.beans.activemqCF = #class:org.apache.activemq.ActiveMQConnectionFactory
+camel.beans.activemqCF.brokerURL = tcp://localhost:61616
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:activemqCF
+camel.component.activemq.connection-factory = #bean:pooledCF
+----
+
+When the endpoints share one pool, they get the same connection, whose client 
id cannot be changed: give an endpoint
+with its own `clientId` (for example for a durable subscription) a 
`connectionFactory` of its own, otherwise its
+consumer cannot connect and keeps retrying. `useSingleConnection=true` cannot 
be combined with a `clientId`: the shared
+connection of the Spring `SingleConnectionFactory` refuses to set a client id.
diff --git 
a/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQComponent.java
 
b/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQComponent.java
index cadd020ab33e..520e03f6859b 100644
--- 
a/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQComponent.java
+++ 
b/components/camel-activemq/src/main/java/org/apache/camel/component/activemq/ActiveMQComponent.java
@@ -238,27 +238,51 @@ public class ActiveMQComponent extends JmsComponent {
 
     @Override
     protected void doStop() throws Exception {
+        // close the connections of the connection factories that the 
endpoints created, but keep the factories usable:
+        // the endpoints keep them, and open new connections when the 
component is started again
         for (Object s : pooledConnectionFactoryServiceList) {
+            invokePooledConnectionFactory(s, "clear");
+        }
+        for (SingleConnectionFactory s : singleConnectionFactoryList) {
             try {
-                // invoke stop method if exists
-                Method m = s.getClass().getMethod("stop");
-                org.apache.camel.support.ObjectHelper.invokeMethod(m, s);
+                s.resetConnection();
             } catch (Exception e) {
-                // ignore
+                LOG.debug("Error resetting the connection of {}. This 
exception is ignored.", s, e);
             }
         }
+
+        super.doStop();
+    }
+
+    @Override
+    protected void doShutdown() throws Exception {
+        for (Object s : pooledConnectionFactoryServiceList) {
+            invokePooledConnectionFactory(s, "stop");
+        }
         pooledConnectionFactoryServiceList.clear();
 
         for (SingleConnectionFactory s : singleConnectionFactoryList) {
             try {
                 s.destroy();
             } catch (Exception e) {
-                // ignore
+                LOG.debug("Error destroying {}. This exception is ignored.", 
s, e);
             }
         }
         singleConnectionFactoryList.clear();
 
-        super.doStop();
+        super.doShutdown();
+    }
+
+    private static void invokePooledConnectionFactory(Object 
pooledConnectionFactory, String method) {
+        try {
+            // invoke the method if it exists
+            Method m = pooledConnectionFactory.getClass().getMethod(method);
+            org.apache.camel.support.ObjectHelper.invokeMethod(m, 
pooledConnectionFactory);
+        } catch (NoSuchMethodException e) {
+            // the connection factory does not have this method
+        } catch (Exception e) {
+            LOG.debug("Error invoking {} on {}. This exception is ignored.", 
method, pooledConnectionFactory, e);
+        }
     }
 
     /**
diff --git 
a/components/camel-activemq/src/test/java/org/apache/camel/component/activemq/ActiveMQComponentRestartTest.java
 
b/components/camel-activemq/src/test/java/org/apache/camel/component/activemq/ActiveMQComponentRestartTest.java
new file mode 100644
index 000000000000..45a22e20a5fe
--- /dev/null
+++ 
b/components/camel-activemq/src/test/java/org/apache/camel/component/activemq/ActiveMQComponentRestartTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.activemq;
+
+import jakarta.jms.JMSException;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.jms.JmsEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.Test;
+import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * The pool that the component creates for an endpoint from the broker URL 
stays usable when the component is stopped
+ * and started again, and is stopped when Camel stops. No broker listens on 
the broker URL: a usable pool tries to
+ * connect and fails, a stopped pool gives no connection.
+ */
+public class ActiveMQComponentRestartTest {
+
+    private static JmsPoolConnectionFactory pool(CamelContext context) {
+        JmsEndpoint endpoint = context.getEndpoint("activemq:queue:restart", 
JmsEndpoint.class);
+        return assertInstanceOf(JmsPoolConnectionFactory.class, 
endpoint.getConfiguration().getOrCreateConnectionFactory());
+    }
+
+    private static CamelContext context() {
+        ActiveMQComponent activemq = new ActiveMQComponent();
+        activemq.setBrokerURL("tcp://localhost:1");
+        CamelContext context = new DefaultCamelContext();
+        context.addComponent("activemq", activemq);
+        return context;
+    }
+
+    @Test
+    public void poolIsUsableAfterTheComponentIsStoppedAndStarted() throws 
Exception {
+        try (CamelContext context = context()) {
+            context.start();
+            JmsPoolConnectionFactory pool = pool(context);
+
+            ActiveMQComponent activemq = context.getComponent("activemq", 
ActiveMQComponent.class);
+            activemq.stop();
+            activemq.start();
+
+            assertThrows(JMSException.class, pool::createConnection);
+        }
+    }
+
+    @Test
+    public void poolIsStoppedWhenTheContextStops() throws Exception {
+        JmsPoolConnectionFactory pool;
+        try (CamelContext context = context()) {
+            context.start();
+            pool = pool(context);
+        }
+
+        assertNull(pool.createConnection());
+    }
+}
diff --git a/components/camel-activemq6/pom.xml 
b/components/camel-activemq6/pom.xml
index 19c966347cc2..c82f013b954b 100644
--- a/components/camel-activemq6/pom.xml
+++ b/components/camel-activemq6/pom.xml
@@ -70,6 +70,19 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <!-- an embedded broker, and the pool the component uses by default, 
for the unit tests -->
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-broker</artifactId>
+            <version>${activemq6-version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.messaginghub</groupId>
+            <artifactId>pooled-jms</artifactId>
+            <version>${pooled-jms-version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/components/camel-activemq6/src/main/docs/activemq6-component.adoc 
b/components/camel-activemq6/src/main/docs/activemq6-component.adoc
index d05cbdce1a20..392b9b66c892 100644
--- a/components/camel-activemq6/src/main/docs/activemq6-component.adoc
+++ b/components/camel-activemq6/src/main/docs/activemq6-component.adoc
@@ -142,3 +142,29 @@ YAML::
             message: "Received a message - ${body}"
 ----
 ====
+
+== Connection factory and transactions
+
+With only `brokerURL` set, each endpoint creates its own connection factory, 
and with `usePooledConnection=true` (the
+default) its own pool, which needs `org.messaginghub:pooled-jms` on the 
classpath. A message sent from a transacted
+route, for example 
`from("activemq6:queue:in?transacted=true").to("activemq6:queue:out")`, is then 
not part of the
+transaction of the consumed message: when the route fails, the consumed 
message is rolled back and delivered again,
+but the message sent to `out` is not rolled back.
+
+To send in the transaction of the consumer, set one `connectionFactory` on the 
component, for example a pooled one,
+so that the endpoints share it. A `transactionManager` that you set must use 
that same connection factory: a
+transaction manager on another connection factory does not make the message 
part of the transaction.
+
+[source,properties]
+----
+camel.beans.activemqCF = #class:org.apache.activemq.ActiveMQConnectionFactory
+camel.beans.activemqCF.brokerURL = tcp://localhost:61616
+camel.beans.pooledCF = 
#class:org.messaginghub.pooled.jms.JmsPoolConnectionFactory
+camel.beans.pooledCF.connectionFactory = #bean:activemqCF
+camel.component.activemq6.connection-factory = #bean:pooledCF
+----
+
+When the endpoints share one pool, they get the same connection, whose client 
id cannot be changed: give an endpoint
+with its own `clientId` (for example for a durable subscription) a 
`connectionFactory` of its own, otherwise its
+consumer cannot connect and keeps retrying. `useSingleConnection=true` cannot 
be combined with a `clientId`: the shared
+connection of the Spring `SingleConnectionFactory` refuses to set a client id.
diff --git 
a/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQComponent.java
 
b/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQComponent.java
index f5627a21b518..47133b9eae72 100644
--- 
a/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQComponent.java
+++ 
b/components/camel-activemq6/src/main/java/org/apache/camel/component/activemq6/ActiveMQComponent.java
@@ -238,27 +238,51 @@ public class ActiveMQComponent extends JmsComponent {
 
     @Override
     protected void doStop() throws Exception {
+        // close the connections of the connection factories that the 
endpoints created, but keep the factories usable:
+        // the endpoints keep them, and open new connections when the 
component is started again
         for (Object s : pooledConnectionFactoryServiceList) {
+            invokePooledConnectionFactory(s, "clear");
+        }
+        for (SingleConnectionFactory s : singleConnectionFactoryList) {
             try {
-                // invoke stop method if exists
-                Method m = s.getClass().getMethod("stop");
-                org.apache.camel.support.ObjectHelper.invokeMethod(m, s);
+                s.resetConnection();
             } catch (Exception e) {
-                // ignore
+                LOG.debug("Error resetting the connection of {}. This 
exception is ignored.", s, e);
             }
         }
+
+        super.doStop();
+    }
+
+    @Override
+    protected void doShutdown() throws Exception {
+        for (Object s : pooledConnectionFactoryServiceList) {
+            invokePooledConnectionFactory(s, "stop");
+        }
         pooledConnectionFactoryServiceList.clear();
 
         for (SingleConnectionFactory s : singleConnectionFactoryList) {
             try {
                 s.destroy();
             } catch (Exception e) {
-                // ignore
+                LOG.debug("Error destroying {}. This exception is ignored.", 
s, e);
             }
         }
         singleConnectionFactoryList.clear();
 
-        super.doStop();
+        super.doShutdown();
+    }
+
+    private static void invokePooledConnectionFactory(Object 
pooledConnectionFactory, String method) {
+        try {
+            // invoke the method if it exists
+            Method m = pooledConnectionFactory.getClass().getMethod(method);
+            org.apache.camel.support.ObjectHelper.invokeMethod(m, 
pooledConnectionFactory);
+        } catch (NoSuchMethodException e) {
+            // the connection factory does not have this method
+        } catch (Exception e) {
+            LOG.debug("Error invoking {} on {}. This exception is ignored.", 
method, pooledConnectionFactory, e);
+        }
     }
 
     /**
diff --git 
a/components/camel-activemq6/src/test/java/org/apache/camel/component/activemq6/ActiveMQComponentRestartTest.java
 
b/components/camel-activemq6/src/test/java/org/apache/camel/component/activemq6/ActiveMQComponentRestartTest.java
new file mode 100644
index 000000000000..be299bc3e4e1
--- /dev/null
+++ 
b/components/camel-activemq6/src/test/java/org/apache/camel/component/activemq6/ActiveMQComponentRestartTest.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.activemq6;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jms.JmsEndpoint;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * The connection factories that the component creates from the broker URL 
keep working when the component, a route or
+ * the CamelContext is stopped and started again, and their connections are 
closed when Camel stops.
+ */
+public class ActiveMQComponentRestartTest {
+
+    private BrokerService broker;
+    private String brokerUrl;
+
+    @BeforeEach
+    void startBroker() throws Exception {
+        broker = new BrokerService();
+        broker.setBrokerName("restart");
+        broker.setPersistent(false);
+        broker.setUseJmx(true);
+        broker.getManagementContext().setCreateConnector(false);
+        broker.setAdvisorySupport(false);
+        TransportConnector connector = 
broker.addConnector("tcp://localhost:0");
+        broker.start();
+        broker.waitUntilStarted();
+        brokerUrl = connector.getConnectUri().toString();
+    }
+
+    @AfterEach
+    void stopBroker() throws Exception {
+        broker.stop();
+    }
+
+    private long brokerConnections() throws Exception {
+        return broker.getAdminView().getCurrentConnectionsCount();
+    }
+
+    private ActiveMQComponent activemq(boolean singleConnection) {
+        ActiveMQComponent activemq = new ActiveMQComponent();
+        activemq.setBrokerURL(brokerUrl);
+        activemq.setUseSingleConnection(singleConnection);
+        return activemq;
+    }
+
+    private static CamelContext context(ActiveMQComponent activemq, String 
queue) throws Exception {
+        CamelContext context = new DefaultCamelContext();
+        context.addComponent("activemq", activemq);
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("activemq:queue:" + 
queue).routeId("consumer").to("mock:result");
+            }
+        });
+        return context;
+    }
+
+    private static void assertSendAndReceive(CamelContext context, String 
queue, String body) throws Exception {
+        MockEndpoint result = context.getEndpoint("mock:result", 
MockEndpoint.class);
+        result.reset();
+        result.expectedBodiesReceived(body);
+        context.createProducerTemplate().sendBody("activemq:queue:" + queue, 
body);
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    private void awaitNoBrokerConnections() {
+        await().atMost(10, TimeUnit.SECONDS).until(() -> brokerConnections() 
== 0);
+    }
+
+    @Test
+    public void componentStopAndStartWithPooledConnection() throws Exception {
+        componentStopAndStart(false, "restart.component.pooled");
+    }
+
+    @Test
+    public void componentStopAndStartWithSingleConnection() throws Exception {
+        componentStopAndStart(true, "restart.component.single");
+    }
+
+    private void componentStopAndStart(boolean singleConnection, String queue) 
throws Exception {
+        ActiveMQComponent activemq = activemq(singleConnection);
+        CamelContext context = context(activemq, queue);
+        context.start();
+        try {
+            assertSendAndReceive(context, queue, "before");
+
+            context.getRouteController().stopRoute("consumer");
+            activemq.stop();
+            awaitNoBrokerConnections();
+            activemq.start();
+            context.getRouteController().startRoute("consumer");
+
+            assertSendAndReceive(context, queue, "after");
+
+            // and the connections opened after the restart are closed when 
the component stops again
+            context.getRouteController().stopRoute("consumer");
+            activemq.stop();
+            awaitNoBrokerConnections();
+        } finally {
+            context.stop();
+        }
+    }
+
+    @Test
+    public void routeStopAndStart() throws Exception {
+        String queue = "restart.route";
+        CamelContext context = context(activemq(false), queue);
+        context.start();
+        try {
+            assertSendAndReceive(context, queue, "before");
+
+            context.getRouteController().stopRoute("consumer");
+            context.getRouteController().startRoute("consumer");
+
+            assertSendAndReceive(context, queue, "after");
+        } finally {
+            context.stop();
+        }
+        awaitNoBrokerConnections();
+    }
+
+    @Test
+    public void contextStopAndStart() throws Exception {
+        String queue = "restart.context";
+        ActiveMQComponent activemq = activemq(false);
+        CamelContext context = context(activemq, queue);
+        context.start();
+        try {
+            assertSendAndReceive(context, queue, "before");
+
+            // the CamelContext shuts its components down when it stops, and 
creates its endpoints again when it starts
+            context.stop();
+            awaitNoBrokerConnections();
+            context.addComponent("activemq", activemq);
+            context.start();
+
+            assertSendAndReceive(context, queue, "after");
+        } finally {
+            context.stop();
+        }
+        awaitNoBrokerConnections();
+    }
+
+    @Test
+    public void shutdownStopsThePools() throws Exception {
+        String queue = "restart.shutdown";
+        CamelContext context = context(activemq(false), queue);
+        context.start();
+        JmsPoolConnectionFactory pool;
+        try {
+            assertSendAndReceive(context, queue, "Hello");
+            pool = assertInstanceOf(JmsPoolConnectionFactory.class,
+                    context.getEndpoint("activemq:queue:" + queue, 
JmsEndpoint.class).getConfiguration()
+                            .getConnectionFactory());
+        } finally {
+            context.stop();
+        }
+        awaitNoBrokerConnections();
+        // a stopped pool gives no connection
+        assertNull(pool.createConnection());
+    }
+}

Reply via email to