Chapter 2. Getting started with transactions on Karaf (OSGi) This section describes a Camel application that uses transactions to access an Artemis JMS broker. The information is organized as follows: Section 2.1, "Prerequisites" Section 2.2, "Building the camel-jms project" Section 2.3, "Explanation of the camel-jms project" 2.1. Prerequisites Implementation of this Camel application has the following prerequisites: An external AMQ 7 JMS message broker must be running. The following sample code runs a standalone (non-Docker) version of amq-broker-7.1.0-bin.zip . Execution creates and runs an amq7 instance: Client libraries are required. Artemis libraries are available in Maven Central or a Red Hat repository. For example, you can use: mvn:org.apache.activemq/artemis-core-client/2.4.0.amq-710008-redhat-1 mvn:org.apache.activemq/artemis-jms-client/2.4.0.amq-710008-redhat-1 Alternatively, Artemis/AMQ 7 client libraries can be installed as Karaf features, for example: karaf@root()> feature:install artemis-jms-client artemis-core-client Some supporting features that provide Karaf shell commands or dedicated Artemis support are required: Required Camel features are: 2.2. Building the camel-jms project You can download the quickstarts from the Fuse Software Downloads page. Extract the contents of the zip file to a local folder, for example a new folder named quickstarts . You can then build and install the /camel/camel-jms example as an OSGi bundle. This bundle contains a Blueprint XML definition of a Camel route that sends messages to an AMQ 7 JMS queue. In the following example, USDFUSE_HOME is the location of the unzipped Fuse distribution. To build this project: Invoke Maven to build the project: Create a JMS connection factory configuration so that the javax.jms.ConnectionFactory service is published in the OSGi runtime. To do this, copy quickstarts/camel/camel-jms/src/main/resources/etc/org.ops4j.connectionfactory-amq7.cfg into the USDFUSE_HOME/etc directory. This configuration will be processed to create a working connection factory. For example: Verify the published connection factory: Install the bundle: Confirm that it is working: As soon as the Camel routes have started, you can see a directory, work/jms/input , in your Fuse installation. Copy the files you find in this quickstart's src/main/data directory to the newly created work/jms/input directory. Wait a few moments and you will find the same files organized by country under the work/jms/output directory: order1.xml , order2.xml and order4.xml in work/jms/output/others order3.xml and order5.xml in work/jms/output/us order6.xml in work/jms/output/fr See the logs to check out the business logging: See that the queue was dynamically created: Check Camel route statistics: 2.3. Explanation of the camel-jms project Camel routes are using the following endpoint URIs: <route id="file-to-jms-route"> ... <to uri="jms:queue:incomingOrders?transacted=true" /> </route> <route id="jms-cbr-route"> <from uri="jms:queue:incomingOrders?transacted=true" /> ... </route> The jms component is configured by using this snippet: <bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <reference interface="javax.jms.ConnectionFactory" /> </property> <property name="transactionManager" ref="transactionManager"/> </bean> While the transactionManager reference is: <reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" /> As you can see, both the JMS connection factory and the Spring interface of PlatformTransactionManager are only references. There is no need to define them in Blueprint XML. These services are exposed by Fuse itself. You have already seen that javax.jms.ConnectionFactory was created by using etc/org.ops4j.connectionfactory-amq7.cfg . The transaction manager is: Check for other interfaces under which the actual transaction manager is registered: The transaction manager is available from these interfaces: javax.transaction.TransactionManager javax.transaction.TransactionSynchronizationRegistry javax.transaction.UserTransaction org.jboss.narayana.osgi.jta.ObjStoreBrowserService org.ops4j.pax.transx.tm.TransactionManager org.springframework.transaction.PlatformTransactionManager You can use any of them in any context that you need. For example camel-jms requires that the org.apache.camel.component.jms.JmsConfiguration.transactionManager field be initialized. This is why the example uses: <reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" /> instead of, for example: <reference id="transactionManager" interface="javax.transaction.TransactionManager" />

Commands:
pwd /data/servers/amq-broker-7.1.0 bin/artemis create --user admin --password admin --require-login amq7 Creating ActiveMQ Artemis instance at: /data/servers/amq-broker-7.1.0/amq7 Auto tuning journal done! Your system can make 27.78 writes per millisecond, your journal-buffer-timeout will be 36000 You can now start the broker by executing: "/data/servers/amq-broker-7.1.0/amq7/bin/artemis" run Or you can run the broker in the background using: "/data/servers/amq-broker-7.1.0/amq7/bin/artemis-service" start amq7/bin/artemis run __ __ ____ ____ _ /\ | \/ |/ __ \ | _ \ | | / \ | \ / | | | | | |_) |_ __ ___ | | _____ _ __ / /\ \ | |\/| | | | | | _ <| '__/ _ \| |/ / _ \ '__| / ____ \| | | | |__| | | |_) | | | (_) | < __/ | /_/ \_\_| |_|\___\_\ |____/|_| \___/|_|\_\___|_| Red Hat JBoss AMQ 7.1.0.GA 018-05-02 16:37:19,294 INFO [org.apache.activemq.artemis.integration.bootstrap] AMQ101000: Starting ActiveMQ Artemis Server
karaf@root()> feature:install jms pax-jms-artemis pax-jms-config
karaf@root()> feature:install camel-jms camel-blueprint
cd quickstarts mvn clean install -f camel/camel-jms/
cp camel/camel-jms/src/main/resources/etc/org.ops4j.connectionfactory-amq7.cfg ../etc/
karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- felix.fileinstall.filename = file:USDFUSE_HOME/etc/org.ops4j.connectionfactory-amq7.cfg name = artemis osgi.jndi.service.name = artemis password = admin pax.jms.managed = true service.bundleid = 251 service.factoryPid = org.ops4j.connectionfactory service.id = 436 service.pid = org.ops4j.connectionfactory.d6207fcc-3fe6-4dc1-a0d8-0e76ba3b89bf service.scope = singleton type = artemis url = tcp://localhost:61616 user = admin Provided by : OPS4J Pax JMS Config (251) karaf@root()> jms:info -u admin -p admin artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1 karaf@root()> jms:queues -u admin -p admin artemis JMS Queues ──────────────────────────────────── df2501d1-aa52-4439-b9e4-c0840c568df1 DLQ ExpiryQueue
karaf@root()> install -s mvn:org.jboss.fuse.quickstarts/camel-jms/7.0.0.redhat-SNAPSHOT Bundle ID: 256
karaf@root()> camel:context-list Context Status Total # Failed # Inflight # Uptime ------- ------ ------- -------- ---------- ------ jms-example-context Started 0 0 0 2 minutes karaf@root()> camel:route-list Context Route Status Total # Failed # Inflight # Uptime ------- ----- ------ ------- -------- ---------- ------ jms-example-context file-to-jms-route Started 0 0 0 2 minutes jms-example-context jms-cbr-route Started 0 0 0 2 minutes
2018-05-02 17:20:47,952 | INFO | ile://work/jms/input | file-to-jms-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Receiving order order1.xml 2018-05-02 17:20:48,052 | INFO | umer[incomingOrders] | jms-cbr-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Sending order order1.xml to another country 2018-05-02 17:20:48,053 | INFO | umer[incomingOrders] | jms-cbr-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Done processing order1.xml
karaf@root()> jms:queues -u admin -p admin artemis JMS Queues ──────────────────────────────────── DLQ 17767323-937f-4bad-a403-07cd63311f4e ExpiryQueue incomingOrders
karaf@root()> camel:route-info jms-example-context file-to-jms-route Camel Route file-to-jms-route Camel Context: jms-example-context State: Started State: Started Statistics Exchanges Total: 1 Exchanges Completed: 1 Exchanges Failed: 0 Exchanges Inflight: 0 Min Processing Time: 67 ms Max Processing Time: 67 ms Mean Processing Time: 67 ms Total Processing Time: 67 ms Last Processing Time: 67 ms Delta Processing Time: 67 ms Start Statistics Date: 2018-05-02 17:14:17 Reset Statistics Date: 2018-05-02 17:14:17 First Exchange Date: 2018-05-02 17:20:48 Last Exchange Date: 2018-05-02 17:20:48
<route id="file-to-jms-route"> <to uri="jms:queue:incomingOrders?transacted=true" /> </route> <route id="jms-cbr-route"> <from uri="jms:queue:incomingOrders?transacted=true" /> </route>
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <reference interface="javax.jms.ConnectionFactory" /> </property> <property name="transactionManager" ref="transactionManager"/> </bean>
<reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
karaf@root()> service:list org.springframework.transaction.PlatformTransactionManager [org.springframework.transaction.PlatformTransactionManager] ------------------------------------------------------------ service.bundleid = 21 service.id = 527 service.scope = singleton Provided by : Red Hat Fuse :: Fuse Modules :: Transaction (21) Used by: Red Hat Fuse :: Quickstarts :: camel-jms (256)
karaf@root()> headers 21 Red Hat Fuse :: Fuse Modules :: Transaction (21) ------------------------------------------------ Bundle-Name = Red Hat Fuse :: Fuse Modules :: Transaction Bundle-SymbolicName = fuse-pax-transx-tm-narayana Bundle-Vendor = Red Hat karaf@root()> bundle:services -p 21 Red Hat Fuse :: Fuse Modules :: Transaction (21) provides: ---------------------------------------------------------- objectClass = [org.osgi.service.cm.ManagedService] service.bundleid = 21 service.id = 519 service.pid = org.ops4j.pax.transx.tm.narayana service.scope = singleton ---- objectClass = [javax.transaction.TransactionManager] provider = narayana service.bundleid = 21 service.id = 520 service.scope = singleton ---- objectClass = [javax.transaction.TransactionSynchronizationRegistry] provider = narayana service.bundleid = 21 service.id = 523 service.scope = singleton ---- objectClass = [javax.transaction.UserTransaction] provider = narayana service.bundleid = 21 service.id = 524 service.scope = singleton ---- objectClass = [org.jboss.narayana.osgi.jta.ObjStoreBrowserService] provider = narayana service.bundleid = 21 service.id = 525 service.scope = singleton ---- objectClass = [org.ops4j.pax.transx.tm.TransactionManager] provider = narayana service.bundleid = 21 service.id = 526 service.scope = singleton ---- objectClass = [org.springframework.transaction.PlatformTransactionManager] service.bundleid = 21 service.id = 527 service.scope = singleton
<reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
<reference id="transactionManager" interface="javax.transaction.TransactionManager" />