Over a million developers have joined DZone.

Connecting JBoss WildFly 7 to ActiveMQ 5.9

DZone's Guide to

Connecting JBoss WildFly 7 to ActiveMQ 5.9

· Integration Zone ·
Free Resource

How to Transform Your Business in the Digital Age: Learn how organizations are re-architecting their integration strategy with data-driven app integration for true digital transformation.

We (C2B2 Consulting) recently had the same question from a number of customers - how could they create a bridge between the HornetQ JMS implementation running in JBoss WildFly 7, and a stand-alone ActiveMQ server. ActiveMQ has always been a solid choice as a stand-alone message broker, and with Red Hat having purchased Fusesource and now peddling their JBoss AMQ version of ActiveMQ, this question is more relevant than ever.

It is of course possible to not use bridging, and just directly expose the JMS queues from ActiveMQ into JBoss, but this has the dis-advantage that if the ActiveMQ server goes down for any reason, JMS producers running in JBoss will start to fail, and consumers will lose their connections and need to reconnet. A much better architecture is to have producers inside JBoss enqueue to a local (HornetQ) queue, and then bridge these messages to the external ActiveMQ broker. With this architecture then producers can continue to enqueue messages while ActiveMQ is down, and when it comes back the messages will be transferred from HornetQ to ActiveMQ.

The steps to configure a bridge are actually quite simple. We need to do the following things:

1. Download the ActiveMQ resource adapter archive

2. Install and configure the resource adapter in WildFly 7

3. Create a local JMS queue in the embedded HornetQ instance in WildFly 7

4. Create a JMS bridge between the local queue and the remote ActiveMQ queue.

To get started, I downloaded the ActiveMQ resource adapter from http://repo1.maven.org/maven2/org/apache/activemq/activemq-rar/

The next step is that we need to create a JBoss module for the activemq resource adapter with the following commands:

mkdir modules/system/layers/base/org/activemq/main
cd modules/system/layers/base/org/activemq/main
unzip ~/activemq-rar-5.9.0.rar

This will create a directory in the modules heirarchy with the necessary structure, and extract the activemq resource adapter files into it. JBoss only supports expanded resource adapters as modules, so we extract the contents of the archive. We also need to create a module.xml with the following contents, in the activemq/main directory. This will tell JBoss which jar files should be loaded and which classes should not be shared with other modules (We don't want to clash with other implementations of any of the libraries).

<module xmlns="urn:jboss:module:1.1" name="org.apache.activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <resource-root path="."/>
    <resource-root path="activemq-broker-5.9.0.jar"/>
    <resource-root path="activemq-client-5.9.0.jar"/>
    <resource-root path="activemq-jms-pool-5.9.0.jar"/>
    <resource-root path="activemq-kahadb-store-5.9.0.jar"/>
    <resource-root path="activemq-openwire-legacy-5.9.0.jar"/>
    <resource-root path="activemq-pool-5.9.0.jar"/>
    <resource-root path="activemq-protobuf-1.1.jar"/>
    <resource-root path="activemq-ra-5.9.0.jar"/>
    <resource-root path="activemq-spring-5.9.0.jar"/>
    <resource-root path="aopalliance-1.0.jar"/>
    <resource-root path="commons-pool-1.6.jar"/>
    <resource-root path="commons-logging-1.1.3.jar"/>
    <resource-root path="hawtbuf-1.9.jar"/>
    <resource-root path="spring-aop-3.2.4.RELEASE.jar"/>
    <resource-root path="spring-beans-3.2.4.RELEASE.jar"/>
    <resource-root path="spring-context-3.2.4.RELEASE.jar"/>
    <resource-root path="spring-core-3.2.4.RELEASE.jar"/>
    <resource-root path="spring-expression-3.2.4.RELEASE.jar"/>
    <resource-root path="xbean-spring-3.14.jar"/>
    <exclude path="org/springframework/**"/>
    <exclude path="org/apache/xbean/**"/>
    <exclude path="org/apache/commons/**"/>
    <exclude path="org/aopalliance/**"/>
    <exclude path="org/fusesource/**"/>
    <module name="javax.api"/>
    <module name="org.slf4j"/>
    <module name="javax.resource.api"/>
    <module name="javax.jms.api"/>
    <module name="javax.management.j2ee.api"/>

To configure the module we need to edit the JBoss configuration file, for this I started with standalone-full.xml as it already has HornetQ configured (which saves quite a lot of effort to add it). We need to add the activeMQ resource adapter, which we do by changing the line

 <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"/>


        <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">
                <resource-adapter id="activemq-rar.rar">
                    <module slot="main" id=" org.apache.activemq "/>
                    <config-property name="ServerUrl">
                        <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name=" java:/AMQConnectionFactory " enabled="true" use-java-context="true" pool-name="AMQConnectionFactory"/>
                                         <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name=" queue/JMSBridgeTargetQ " use-java-context="true" pool-name="target_queue">
                                            <config-property name="PhysicalName">

This creates a resource adapter that uses the org.apache.activemq module we created earlier and connects to the remote ActiveMQ server running on tcp://localhost:61616. It registers a connection factory called java:AMQConnectionFactory that will allow us to connect to the remote server, and creates a local JNDI entry of queue/JMSBridgeTargetQ that will bind to the ActiveMQ queue called JMSBridgeTargetQ.

The next step is to configure the bridge and the local queue. We edit the hornetq subsystem to add a JMS bridge after the definition of the hornetQ server.

            <jms-bridge name="simple-jms-bridge">
                    <connection-factory name=" ConnectionFactory "/>
                    <destination name=" queue/JMSBridgeSourceQ "/>
                    <connection-factory name=" AMQConnectionFactory "/>
                    <destination name=" queue/JMSBridgeTargetQ "/>

This creates a bridge that will use the connection factory called ConnectionFactory to consume from the local queue with the JNDI name queue/JMSBridgeSourceQ. It will then use the connection factory called AMQConnectionFactory (which is created by our resource adapter) to send the messages to the queue with the JNDI name queue/JMSBridgeTargetQ. This is mapped by our resource adapter to the remote ActiveMQ queue. We also need to create a local queue called JMSBridgeSourceQ in the jms-destinations section of the configuration.

                    <jms-queue name="JMSBridgeSourceQueue">
                        <entry name=" java:/queue/JMSBridgeSourceQ "/>
                        <entry name="java:jboss/exported/jms/queue/JMSBridgeSourceQ "/>

This queue has two JNDI names, to allow it to be accessed both internally (by the bridge) and externally (by our client).

To create the correspoding destination on the ActiveMQ side, we start ActiveMQ using the bin/activemq start command, and use the ActiveMQ hawtio console (http://localhost:8161/hawtio) to create a new JMS queue by browsing to ActiveMQ -> Broker -> Localhost -> Queue and selecting Create. Name the Queue JMSBridgeTargetQ in this example

This is all the configuration necessary. We should be able to start the WildFly server and see that the bridge works and is connected to ActiveMQ

 13:43:11,959 INFO  [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on
13:43:12,447 INFO  [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on
13:43:12,452 INFO  [org.jboss.as.connector.deployers.RaXmlDeployer] (MSC service thread 1-2) IJ020001: Required license terms for file:/home/matt/jboss-as-7.2.0.Final/modules/system/layers/base/org/apache/activemq/main/./
13:43:12,511 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010406: Registered connection factory java:/AMQConnectionFactory
13:43:12,522 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010405: Registered admin object at java:/queue/JMSBridgeTargetQ
13:43:12,538 INFO  [org.hornetq.core.server] (MSC service thread 1-1) HQ221024: Started Netty Acceptor version 3.6.2.Final-c0d783c for CORE protocol
13:43:12,550 INFO  [org.jboss.as.connector.deployers.RaXmlDeployer] (MSC service thread 1-2) IJ020002: Deployed: file:/home/matt/jboss-as-7.2.0.Final/modules/system/layers/base/org/apache/activemq/main/./
13:43:12,555 INFO  [org.hornetq.core.server] (MSC service thread 1-1) HQ221024: Started Netty Acceptor version 3.6.2.Final-c0d783c for CORE protocol
13:43:12,558 INFO  [org.hornetq.core.server] (MSC service thread 1-1) HQ221009: Server is now live
13:43:12,561 INFO  [org.hornetq.core.server] (MSC service thread 1-1) HQ221003: HornetQ Server version 2.3.0.CR1 (buzzzzz!, 122) [1ef84f49-88d8-11e3-a2ac-f9239574df9d]
13:43:12,584 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-1) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
13:43:12,600 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-1) JBAS010401: Bound JCA ConnectionFactory [java:/AMQConnectionFactory]
13:43:12,611 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-1) JBAS010401: Bound JCA AdminObject [java:/queue/JMSBridgeTargetQ]
13:43:12,683 INFO  [org.jboss.as.messaging] (ServerService Thread Pool -- 58) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory
13:43:12,686 INFO  [org.hornetq.core.server] (ServerService Thread Pool -- 60) HQ221005: trying to deploy queue jms.queue.JMSBridgeSourceQueue
13:43:12,733 INFO  [org.jboss.as.messaging] (ServerService Thread Pool -- 60) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/JMSBridgeSourceQ
13:43:12,738 INFO  [org.jboss.as.messaging] (ServerService Thread Pool -- 60) JBAS011601: Bound messaging object to jndi name java:/queue/JMSBridgeSourceQ
13:43:12,747 INFO  [org.jboss.as.messaging] (ServerService Thread Pool -- 59) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory
13:43:12,916 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010406: Registered connection factory java:/JmsXA
13:43:12,968 INFO  [org.hornetq.ra] (MSC service thread 1-2) HornetQ resource adaptor started
13:43:12,969 INFO  [org.jboss.as.connector.services.resourceadapters.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-2) IJ020002: Deployed: file://RaActivatorhornetq-ra
13:43:12,974 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-1) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
13:43:13,286 INFO  [org.jboss.messaging] (ServerService Thread Pool -- 58) JBAS011610: Started JMS Bridge simple-jms-bridge
13:43:13,439 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on
13:43:13,440 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on
13:43:13,440 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.2.0.Final "Janus" started in 9912ms - Started 169 of 228 services (58 services are passive or on-demand)
We can now place messages on the JMSBridgeSourceQ in JBoss, and they will end up on the JMSBridgeTargetQ in ActiveMQ.

It is possible to reverse the direction of the bridge to have messages flow the other way, although bridging for consumers is not as vital as bridging with producers. With a consumer it is usually preferable to consume messages directly from the mapped JNDI name created by the resource adapter (in this case queue/JMSBridgeTargetQ), rather than bridging the messages to a local queue and consuming from there.

Build and deploy API integrations 7x faster. Try the Cloud Elements 100% RESTful platform for 30 days free. Access your trial here.


Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}