Configuring JMS Bridge with WildFly 10

In this article we will learn how to configure a JMS bridge with WildFly 10 so that we can route messages from one destination to another.

First of all some basics: the purpose of a JMS bridge is to consume messages from a source JMS destination and send them to a target JMS destination. The JMS bridge can be used to bridge messages from a broker to another (remote) broker or also within the same JMS broker. Additionally, the bridge can also be used to bridge messages from other non Artemis JMS servers, as long as they are JMS 1.1 compliant. 

In WildFly 10, the JMS Bridge is provided by the Artemis project. We need to apply some configuration on the source Broker and on the Destination Broker. As you can imagine, the bridge has to be defined on the source Broker, while on the target broker we will just define the JMS destination. We will now create an example of a JMS bridge using two WildFly 10 servers on the same machine, the first one with the default offset (0) and the second one with an offset of 100.

jms bridge wildfly

Source Broker configuration

So here is a sample jms-bridge configuration we can add to our server:

<jms-bridge name="simple-jms-bridge" max-batch-time="100" max-batch-size="10" max-retries="1" failure-retry-interval="10000" quality-of-service="AT_MOST_ONCE">
        <source destination="queue/JMSBridgeSourceQueue" connection-factory="ConnectionFactory"/>
        <target password="password" user="jmsuser" destination="jms/queues/JMSBridgeTargetQueue" connection-factory="jms/RemoteConnectionFactory">
            <target-context>
                <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory"/>
                <property name="java.naming.provider.url" value="http-remoting://localhost:8180"/>
            </target-context>
        </target>
</jms-bridge>

As you can see, we have basically defined:

  • A JMS bridge element
  • A source (queue/JMSBridgeSourceQueue) and target destination (jms/queues/JMSBridgeTargetQueue), both of which are using a JMS Connection Factory to receive and route messafes
  • Authorization is required in order to reach the Target WildFly server, therefore you need creating an user named jmsuser belonging to an authorized group, such as the "guest" group

If you want to see the full configuration of the messaging-activemq subsystem, here it is:

<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
    <server name="default">
        <security-setting name="#">
            <role name="guest" delete-non-durable-queue="true" create-non-durable-queue="true" consume="true" send="true"/>
        </security-setting>
        <address-setting name="#" message-counter-history-day-limit="10" page-size-bytes="2097152" max-size-bytes="10485760" expiry-address="jms.queue.ExpiryQueue" dead-letter-address="jms.queue.DLQ"/>
        <http-connector name="http-connector" endpoint="http-acceptor" socket-binding="http"/>
        <http-connector name="bridge-connector" endpoint="bridge-acceptor" socket-binding="messaging-remote"/>
        <http-connector name="http-connector-throughput" endpoint="http-acceptor-throughput" socket-binding="http">
            <param name="batch-delay" value="50"/>
        </http-connector>
        <in-vm-connector name="in-vm" server-id="0"/>
        <http-acceptor name="http-acceptor" http-listener="default"/>
        <http-acceptor name="http-acceptor-throughput" http-listener="default">
            <param name="batch-delay" value="50"/>
            <param name="direct-deliver" value="false"/>
        </http-acceptor>
        <in-vm-acceptor name="in-vm" server-id="0"/>
        <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
        <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
      
        <jms-queue name="JMSBridgeSourceQueue" entries="queue/JMSBridgeSourceQueue java:jboss/exported/jms/queues/JMSBridgeSourceQueue"/>
        <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
        <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="bridge-connector"/>
        <pooled-connection-factory name="activemq-ra" transaction="xa" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm"/>
    </server>
    <jms-bridge name="simple-jms-bridge" max-batch-time="100" max-batch-size="10" max-retries="1" failure-retry-interval="10000" quality-of-service="AT_MOST_ONCE">
        <source destination="queue/JMSBridgeSourceQueue" connection-factory="ConnectionFactory"/>
        <target password="guest" user="guest" destination="jms/queues/JMSBridgeTargetQueue" connection-factory="jms/RemoteConnectionFactory">
            <target-context>
                <property name="java.naming.factory.initial" value="org.jboss.naming.remote.client.InitialContextFactory"/>
                <property name="java.naming.provider.url" value="http-remoting://localhost:8180"/>
            </target-context>
        </target>
    </jms-bridge>
</subsystem>
. . . .
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
. . . .
<outbound-socket-binding name="messaging-remote">
    <remote-destination host="localhost" port="8180"/>
</outbound-socket-binding>
</socket-binding-group>

Target Broker configuration

The target bridge configuration is pretty simple, you have just to include the JMS queue definition:

 <jms-queue name="JMSBridgeTargetQueue" entries="queue/JMSBridgeTargetQueue java:jboss/exported/jms/queues/JMSBridgeTargetQueue"/>

Remember that you need to create on the target broker an Application user (named in our example jmsuser) belonging to the group guest.

Now start the target broker first (in our case it's on localhost with an offset of 100)

./standalone.sh -Djboss.socket.binding.port-offset=100 -c standalone-full.xml

And start as well the source broker, on the default port:

./standalone.sh -c standalone-full.xml

If you don't find any connection error in your source broker you can be confident that the JMS bridge started correctly and that the connection towards tha target destination has been established:

21:10:14,594 INFO  [org.apache.activemq.artemis.core.server] (ServerService Thread Pool -- 67) AMQ221003: trying to deploy queue jms.queue.JMSBridgeTargetQueue

Connecting to another JMS broker using the Bridge

The JMS bridge is capable of routing messages from/to any JMS 1.1 compliant broker. Let's see as an example how to bridge messages toward an ActiveMQ server. In this example, we have shown how to provide a Connection Factory towards ActiveMQ by means of a Resource adapter: Configuring JMS Bridge with WildFly 10

jms bridge wildfly

Just to recap, here are the resources available through the resource-adapter subsystem:

<subsystem xmlns="urn:jboss:domain:resource-adapters:4.0">
    <resource-adapters>
        <resource-adapter id="activemq">
            <archive>
                activemq-rar-5.12.0.rar
            </archive>
            <transaction-support>XATransaction</transaction-support>
            <config-property name="ServerUrl">
                tcp://localhost:61616
            </config-property>
            <config-property name="UserName">
                defaultUser
            </config-property>
            <config-property name="UseInboundSession">
                false
            </config-property>
            <config-property name="Password">
                defaultPassword
            </config-property>
            <connection-definitions>
                <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/MQConnectionFactory" enabled="true" pool-name="ConnectionFactory">
                    <xa-pool>
                        <min-pool-size>1</min-pool-size>
                        <max-pool-size>20</max-pool-size>
                        <prefill>false</prefill>
                        <is-same-rm-override>false</is-same-rm-override>
                    </xa-pool>
                </connection-definition>
            </connection-definitions>
            <admin-objects>
                <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:jboss/activemq/topic/TestTopic" use-java-context="true" pool-name="TestTopic">
                    <config-property name="PhysicalName">
                        activemq/topic/TestTopic
                    </config-property>
                </admin-object>
                <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:/activemq/queue/TestQueue" use-java-context="true" pool-name="TestQueue">
                    <config-property name="PhysicalName">
                        activemq/queue/TestQueue
                    </config-property>
                </admin-object>
            </admin-objects>
        </resource-adapter>
    </resource-adapters>
</subsystem>

Now we have available in our JNDI references to external resources (MQConnectionFactory and activemq/queue/TestQueue)

<jms-bridge name="simple-jms-bridge" max-batch-time="100" max-batch-size="10" max-retries="1" failure-retry-interval="10000" quality-of-service="AT_MOST_ONCE">
<source destination="queue/JMSBridgeSourceQueue" connection-factory="ConnectionFactory"/>
<target destination="activemq/queue/TestQueue" connection-factory="MQConnectionFactory"/>
</jms-bridge>

Now try to deploy a JMS producer for the Queue queue/JMSBridgeSourceQueue and one for the Queue activemq/queue/TestQueue. You will see messages are routed correctly through the two brokers.

jms bridge jboss wildfly

Follow us on Twitter