JBoss AS 7 ActiveMQ integration

Apache ActiveMQ is an open source (Apache 2.0 licensed) message broker which fully implements the Java Message Service 1.1 (JMS). It provides Enterprise Features like clustering, multiple message stores, and ability to use any database as a JMS persistence provider besides VM, cache, and journal persistency. In this tutorial we will show how to integrate the ActiveMQ message broker with JBoss AS 7

In order to run this tutorial we suggest you using the following server/library releases:

  • Jboss-as-7.2.0.Alpha1-SNAPSHOT
  • activemq-rar-5.7.0.rar

ActiveMQ Resource Adapter is not distributed anymore with the JMS broker bundle but you have to download it from Maven repository at  http://repo1.maven.org/maven2/org/apache/activemq/activemq-rar/5.7.0/

Resource adapters (.rar) are deployed by copying the resource adapter into the deploy/ directory. Before doing that, we need to configure the Resource Adapter in your server configuration. This can be either done by adding the configuration in the jca subsystem, or (suggested choice) by creating an ironjacamar.xml which is a descriptor of the external resource.

The IronJacamar distribution features a resource adapter information tool (rar-info.sh), that can be used to create the resource adapter  deployment descriptor, by generating a report file containing all the necessary information.

So start by issuing the following command:


./rar-info.sh activemq-rar-5.7.0.rar

This will generate a file called activemq-rar-5.7.0.txt which can be used to construct the ironjacamar.xml configuration file:

<ironjacamar>
    <!-- This defines the ConnectionFactory bindings for JNDI -->
    <!-- You HAVE to use ManagedConnectionFactories here and you HAVE to disable the definitions in the ra.xml except the basic ConnectionFactory -->
    <connection-definitions>
        <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:jboss/activemq/TopicConnectionFactory" pool-name="TopicConnectionFactory">
            <pool>
                <min-pool-size>1</min-pool-size>
                <max-pool-size>200</max-pool-size>
                <prefill>false</prefill>
            </pool>
            <security>
                <application/>
            </security>
            <timeout>
                <blocking-timeout-millis>30000</blocking-timeout-millis>
                <idle-timeout-minutes>3</idle-timeout-minutes>
            </timeout>
            <validation>
                <background-validation>false</background-validation>
                <use-fast-fail>false</use-fast-fail>
            </validation>
        </connection-definition>
        <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:jboss/activemq/QueueConnectionFactory" pool-name="QueueConnectionFactory">
            <pool>
                <min-pool-size>1</min-pool-size>
                <max-pool-size>200</max-pool-size>
                <prefill>false</prefill>
            </pool>
            <security>
                <application/>
            </security>
            <timeout>
                <blocking-timeout-millis>30000</blocking-timeout-millis>
                <idle-timeout-minutes>3</idle-timeout-minutes>
            </timeout>
            <validation>
                <background-validation>false</background-validation>
                <use-fast-fail>false</use-fast-fail>
            </validation>
        </connection-definition>
    </connection-definitions>
    <!--  Define your Topics/Queues here and specify a PhysicalName and a JNDI name -->
    <admin-objects>
        <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:jboss/activemq/topic/LocalRPCRequest">
            <config-property name="PhysicalName">activemq/topic/LocalRPCRequest</config-property>
        </admin-object>
        <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:jboss/activemq/topic/LocalRPCReply">
            <config-property name="PhysicalName">activemq/topic/LocalRPCReply</config-property>
        </admin-object>
    </admin-objects>                    

</ironjacamar>

This file needs to be copied into the META-INF folder of the activemq-rar-5.7.0.rar.

Another thing I needed to customize is the ra.xml configuration file which contained an outbound resource adapter Connection definition not accepted by JBoss AS. Here's the correct ra.xml that you have to place in the META-INF folder of your resource adapter:


<connector xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"
    version="1.5">
    <description>ActiveMQ  inbound and outbound JMS ResourceAdapter</description>
    <display-name>ActiveMQ JMS Resource Adapter</display-name>
    <vendor-name>activemq.org</vendor-name>
    <eis-type>JMS 1.1</eis-type>
    <resourceadapter-version>1.0</resourceadapter-version>
    <resourceadapter>
        <resourceadapter-class>org.apache.activemq.ra.ActiveMQResourceAdapter</resourceadapter-class>
        <config-property>
            <description>
              The URL to the ActiveMQ server that you want this connection to connect to.  If using
              an embedded broker, this value should be 'vm://jboss-activemq-broker'.
            </description>
            <config-property-name>ServerUrl</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
            <config-property-value>vm://jboss-activemq-broker</config-property-value>
        </config-property>
        <config-property>
            <description>The default user name that will be used to establish connections to the ActiveMQ server.</description>
            <config-property-name>UserName</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
            <config-property-value>defaultUser</config-property-value>
        </config-property>
        <config-property>
            <description>The default password that will be used to log the default user into the ActiveMQ server.</description>
            <config-property-name>Password</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
            <config-property-value>defaultPassword</config-property-value>
        </config-property>
        <config-property>
            <description>The client id that will be set on the connection that is established to the ActiveMQ server.</description>
            <config-property-name>Clientid</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
        </config-property>
        <config-property>
            <description>Boolean to configure if outbound connections should reuse the inbound connection's session for sending messages.</description>
            <config-property-name>UseInboundSession</config-property-name>
            <config-property-type>java.lang.Boolean</config-property-type>
            <config-property-value>false</config-property-value>
        </config-property>

        <!-- NOTE disable the following property if you do not wish to deploy an embedded broker -->
        <config-property>
            <description>
              Sets the XML configuration file used to configure the embedded ActiveMQ broker via 
              Spring if using embedded mode.

              BrokerXmlConfig is the filename which is assumed to be on the classpath unless 
              a URL is specified. So a value of foo/bar.xml would be assumed to be on the 
              classpath whereas file:dir/file.xml would use the file system. 
              Any valid URL string is supported.              
            </description>
            <config-property-name>BrokerXmlConfig</config-property-name>
            <config-property-type>java.lang.String</config-property-type>
            <!--
             To use the broker-config.xml from the root for the RAR
            -->
            <config-property-value>xbean:broker-config.xml</config-property-value>
        </config-property>

        <outbound-resourceadapter>
            <connection-definition>
                <managedconnectionfactory-class>org.apache.activemq.ra.ActiveMQManagedConnectionFactory</managedconnectionfactory-class>
                <connectionfactory-interface>javax.jms.ConnectionFactory</connectionfactory-interface>
                <connectionfactory-impl-class>org.apache.activemq.ra.ActiveMQConnectionFactory</connectionfactory-impl-class>
                <connection-interface>javax.jms.Connection</connection-interface>
                <connection-impl-class>org.apache.activemq.ra.ManagedConnectionProxy</connection-impl-class>
            </connection-definition>
            <transaction-support>NoTransaction</transaction-support>
            <reauthentication-support>false</reauthentication-support>
        </outbound-resourceadapter>
        <inbound-resourceadapter>
            <messageadapter>
                <messagelistener>
                    <messagelistener-type>javax.jms.MessageListener</messagelistener-type>
                    <activationspec>
                        <activationspec-class>org.apache.activemq.ra.ActiveMQActivationSpec</activationspec-class>
                        <required-config-property>
                            <config-property-name>destination</config-property-name>
                        </required-config-property>
                        <required-config-property>
                            <config-property-name>destinationType</config-property-name>
                        </required-config-property>
                    </activationspec>
                </messagelistener>
            </messageadapter>
        </inbound-resourceadapter>
        <adminobject>
            <adminobject-interface>javax.jms.Queue</adminobject-interface>
            <adminobject-class>org.apache.activemq.command.ActiveMQQueue</adminobject-class>
            <config-property>
                <config-property-name>PhysicalName</config-property-name>
                <config-property-type>java.lang.String</config-property-type>
            </config-property>
        </adminobject>
        <adminobject>
            <adminobject-interface>javax.jms.Topic</adminobject-interface>
            <adminobject-class>org.apache.activemq.command.ActiveMQTopic</adminobject-class>
            <config-property>
                <config-property-name>PhysicalName</config-property-name>
                <config-property-type>java.lang.String</config-property-type>
            </config-property>
        </adminobject>
    </resourceadapter>
</connector>

Now start JBoss AS 7 using the full configuration:


standalone.bat -c standalone-full.xml

If everything is in the right place, you will see from the server logs that JCA Admin objects have been bound in JBoss' JNDI tree:

jboss as 7 active mq tutorial jboss as 7 active mq tutorial jboss as 7 active mq tutorial

And here's a sample MDB which is able to consume JMS Messages from the ActiveMQ resource adapter:


package com.sample.mdb;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.jboss.ejb3.annotation.ResourceAdapter;

@MessageDriven(
activationConfig = { 
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="java:jboss/activemq/queue/LocalRPCRequest")
}, 
name = "ActiveMQMDB")
@ResourceAdapter(value="activemq-rar-5.7.0.rar")
public class ActiveMQMDB implements MessageListener {

    public ActiveMQMDB() {}

    @Override
    public void onMessage(Message message) {
    try {    
    if(message instanceof TextMessage) {
    System.out.println("Got Message "+((TextMessage)message).getText());
}
        }
        catch (JMSException e) {
        e.printStackTrace();
        }
    }
}


Advertisement