JBoss AS 7 ActiveMQ integration

Please note this tutorial has been written for an old version of JBoss application server. If you want to integrate WildFly/JBoss with ActiveMQ broker we recommend checking these tutorials:

WildFly – ActiveMQ integration part 1: RAR deployment

WildFly – ActiveMQ integration part 2: module installation

Finally, if you want to integrate WildFly with Artemis MQ broker, check this article

How to connect WildFly to a remote ActiveMQ Artemis server?

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:

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();
        }
    }
}

HelloWorld Resource Adapter tutorial

[Updated] In this tutorial we will show how you can create build and deploy an HelloWorld Resource Adapter and deploy it on WildFly 10.

The Java Connector Architecture (JCA) defines a standard architecture for connecting the Java EE platform to heterogeneous Enterprise Information Systems (EIS). Examples of EISs include Enterprise Resource Planning (ERP), mainframe transaction processing (TP), database and messaging systems.

The IronJacamar project implements the Java Connector Architecture 1.6 specification and is available in a stable version, and a developer version.

In order to create your own Adapter, you need to define your Contract in a Resource Adapter Connection class, define a Factory for creating your Connection to the Resource Adapter and provide the Connector Managed classes which are used to creates a new physical connection to the underlying EIS resource manager and communicate with it.

Create a Resource Adapter from a Maven project

We will first show how to create a new Resource Adapter from a Maven project. Create a new Maven Java Project as follows:

$ mvn archetype:generate -DgroupId=com.sample -DartifactId=jcademo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

We will not expose all the project classes but just the core parts of it (You can the project on github at. https://github.com/fmarchioni/mastertheboss/tree/master/jca-demo).

The first step will be defining your connector exposed methods in the HelloWorldConnection class

package com.sample.adapter;
 
public interface HelloWorldConnection
{

  public String helloWorld();
  public String helloWorld(String name);

  public void close();
}

Next, your main concern will be implementing the Managed Connection class which contains the actual implementation for our method write which writes our Hello World message to a Stream:

package com.sample.adapter;


import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionEvent;
import javax.resource.spi.ConnectionEventListener;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.LocalTransaction;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionMetaData;

import javax.security.auth.Subject;
import javax.transaction.xa.XAResource;


public class HelloWorldManagedConnection implements ManagedConnection
{
   /** The logger */
   private static Logger log = Logger.getLogger("HelloWorldManagedConnection");

   /** MCF */
   private HelloWorldManagedConnectionFactory mcf;

   /** Log writer */
   private PrintWriter logWriter;

   /** Listeners */
   private List<ConnectionEventListener> listeners;

   /** Connection */
   private Object connection;


   public HelloWorldManagedConnection(HelloWorldManagedConnectionFactory mcf)
   {
      this.mcf = mcf;
      this.logWriter = null;
      this.listeners = new ArrayList<ConnectionEventListener>(1);
      this.connection = null;
   }


   public Object getConnection(Subject subject,
                               ConnectionRequestInfo cxRequestInfo) 
      throws ResourceException
   {
      connection = new HelloWorldConnectionImpl(this, mcf);

      return connection;
   }


   public void associateConnection(Object connection) throws ResourceException
   {
      this.connection = connection;
   }


   public void cleanup() throws ResourceException
   {
   }


   public void destroy() throws ResourceException
   {
      this.connection = null;
   }


   public void addConnectionEventListener(ConnectionEventListener listener)
   {
      if (listener == null)
         throw new IllegalArgumentException("Listener is null");

      listeners.add(listener);
   }

   public void removeConnectionEventListener(ConnectionEventListener listener)
   {
      if (listener == null)
         throw new IllegalArgumentException("Listener is null");

      listeners.remove(listener);
   }


   public PrintWriter getLogWriter() throws ResourceException
   {
      return logWriter;
   }


   public void setLogWriter(PrintWriter out) throws ResourceException
   {
      this.logWriter = out;
   }


   public LocalTransaction getLocalTransaction() throws ResourceException
   {
      throw new NotSupportedException("LocalTransaction not supported");
   }


   public XAResource getXAResource() throws ResourceException
   {
      throw new NotSupportedException("GetXAResource not supported");
   }


   public ManagedConnectionMetaData getMetaData() throws ResourceException
   {
      return new HelloWorldManagedConnectionMetaData();
   }


   String helloWorld(String name)
   {
      return "Hello World, " + name + " !";
   }


   void closeHandle(HelloWorldConnection handle)
   {
      ConnectionEvent event = new ConnectionEvent(this, ConnectionEvent.CONNECTION_CLOSED);
      event.setConnectionHandle(handle);

      for (ConnectionEventListener cel : listeners)
      {
         cel.connectionClosed(event);
      }
   }
}

Finally, the ConnectionImpl class which sends data to the server:

package com.sample.adapter;

import java.util.logging.Logger;


public class HelloWorldConnectionImpl implements HelloWorldConnection
{
   /** The logger */
   private static Logger log = Logger.getLogger("HelloWorldConnectionImpl");

   /** ManagedConnection */
   private HelloWorldManagedConnection mc;

   /** ManagedConnectionFactory */
   private HelloWorldManagedConnectionFactory mcf;


   public HelloWorldConnectionImpl(HelloWorldManagedConnection mc,
                                   HelloWorldManagedConnectionFactory mcf)
   {
      this.mc = mc;
      this.mcf = mcf;
   }


   public String helloWorld()
   {
      return helloWorld(((HelloWorldResourceAdapter)mcf.getResourceAdapter()).getName());
   }


   public String helloWorld(String name)
   {
      return mc.helloWorld(name);
   }

   public void close()
   {
      mc.closeHandle(this);
   }
}

Done with the Java classes. We will now add into the META-INF folder the ironjacamar.xml file which contains the connection definition which will be used by the resource adapter clients:

<ironjacamar>
  <connection-definitions>
    <connection-definition 
     class-name="com.sample.adapter.HelloWorldManagedConnectionFactory" 
     jndi-name="java:/eis/HelloWorld"/>
  </connection-definitions>
</ironjacamar>

In order to build the project, we will add the required dependencies to the pom.xml, including the RAR Maven plugin which will generate a RAR file, including the ironjacamar.xml descriptor:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.sample</groupId>
	<artifactId>jca-demo</artifactId>
	<version>1.0</version>
	<packaging>jar</packaging>

	<name>jca-demo</name>
	<url>http://maven.apache.org</url>

	<properties>
		<version.org.jboss.ironjacamar>1.0.9.Final</version.org.jboss.ironjacamar>
		 <version.wildfly.maven.plugin>1.0.2.Final</version.wildfly.maven.plugin>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.jboss.ironjacamar</groupId>
			<artifactId>ironjacamar-spec-api</artifactId>
			<version>${version.org.jboss.ironjacamar}</version>
			<scope>provided</scope>
		</dependency>

	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.jboss.ironjacamar</groupId>
				<artifactId>ironjacamar-depchain</artifactId>
				<version>${version.org.jboss.ironjacamar}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>2.4</version>
				<configuration>
					<excludes>
						<exclude>**/META-INF/*</exclude>
					</excludes>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-rar-plugin</artifactId>
				<version>2.2</version>
				<executions>
					<execution>
						<id>test</id>
						<goals>
							<goal>rar</goal>
						</goals>
						<configuration>

							<raXmlFile>src/main/resources/META-INF/ironjacamar.xml</raXmlFile>
						</configuration>
					</execution>
				</executions>
			</plugin>
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>${version.wildfly.maven.plugin}</version>
            </plugin>
		</plugins>
	</build>

</project>

Build and deploy the project with:

$ mvn clean install rar:rar wildfly:deploy

Finally, here’s a Test Servlet which can be used to test our resource adapter:

package com.sample;

import java.io.IOException;
import java.io.PrintWriter;

import javax.annotation.Resource;
import javax.resource.ResourceException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

 import com.sample.adapter.HelloWorldConnection;
 import com.sample.adapter.HelloWorldConnectionFactory;

 
@WebServlet("/TestRA")
public class TestRA extends HttpServlet {
	private static final long serialVersionUID = 1L;
	@Resource(mappedName = "java:/eis/HelloWorld")
	private HelloWorldConnectionFactory connectionFactory;

	 public TestRA() {
	        super();
	        
	    }
	    /**
	     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	     */
	    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    	  String result = null;
	  	  HelloWorldConnection connection = null;
	        try {
	         	 connection = connectionFactory.getConnection();	  	       
		         result = connection.helloWorld();
		       
	        } catch (ResourceException e) {
	            // TODO Auto-generated catch block
	            e.printStackTrace();
	        }
 

	        PrintWriter out = response.getWriter();
	        out.println(result);

	        out.flush();
	      //  connection.close();
	    }

 
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

In order to be able to run your client application provide a dependency through the WEB-INF/jboss-deployment-structure.xml file as follows:

<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="deployment.jca-demo-1.0.rar" />
    </dependencies>
  </deployment>
</jboss-deployment-structure> 

Now test your application:

$ curl http://localhost:8080/raclient/TestRA

HelloWorld WildFly!

Build the Project with Eclipse

If you are not using Maven to build your projects, you can still use a Wizard which is built-in with Eclipse. All you have to do is creating a new Connector Project from Eclipse (You can also use an ordinary Java Project, however the Connector project has the advantage of automatically publishing the project as RAR archive to WildFly ):

 

Your Connector classes will be, by default, placed into the connectorModule folder:

Finally, the last screenshot allows you to include or not the standard descriptor for the resource adapter (ra.xml). This is not a mandatory step as we will use the custom resource adapter from the IronJacamer project named ironjacamar.xml.

Finish by copying the source from guthub into the connectorModule folder and you are done!

References: http://www.ironjacamar.org/doc/userguide/1.2/en-US/html_single/index.html#sample_helloworld_resourceadpater

WildFly – ActiveMQ integration part 2: module installation

This is the second tutorial about how to integrate Active MQ broker with WildFly. In the first tutorial we have covered how to install Active MQ RAR file on WildFly:

This tutorial shows how to deploy a Resource Adapter for ActiveMQ as a module and configure a ConnectionFactory and a Queue towards ActiveMQ.

Prerequisite to this tutorial is that you are running a JBoss EAP 6.1/6.2 or Wildfly application server. As for earlier server versions there’s an issue [AS7-5768] “Support resource adapter deployments via modules” which prevents this tutorial from working.

So I suppose you have either WildFly or JBoss EAP 6.1+ up and running: the scenario we are going to describe covers deploying a resource adapter into the application server as module without running embedded broker but rather activemq running standalone in separate process.

First you’d need ActiveMQ server running. Grab it from apache’s activemq site (http://activemq.apache.org/download.html). Once downloaded, unpack activemq server bundle and start it
($AMQ_DIR/bin/activemq console on linux, %AMQ_DIR%\bin\activemq on windows)

Next, you’d need the ActiveMQResource Adapter. Grab it from here:
https://repository.apache.org/content/repositories/releases/org-apache/activemq/activemq-rar/5.9.0/

Since JBoss EAP 6.1 supports only unpacked resource adapter deployment so, unpack it into some temporary directory.
Open META-INF/ra.xml file and locate the following comment:

<!-- NOTE disable the following property if you do not wish to deploy an embedded broker -->

It demarcates config property which you should comment out/remove to disable embedded broker. So either comment it out or remove it completely. Save the file.

Module installation on the application server

Create the folder:$JBOSS_HOME/modules/system/layers/base/org/apache/activemq/main/
Copy all unpacked files of resource adapter to that folder, including the META-INF/ra.xml file.
Add module.xml file to the same folder with the following content:

<module xmlns="urn:jboss:module:1.1" name="org.apache.activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <resources>
    <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"/>
  </resources>
  <exports>
    <exclude path="org/springframework/**"/>
    <exclude path="org/apache/xbean/**"/>
    <exclude path="org/apache/commons/**"/>
    <exclude path="org/aopalliance/**"/>
    <exclude path="org/fusesource/**"/>
  </exports>
  <dependencies>
    <module name="javax.api"/>
    <module name="org.slf4j"/>
    <module name="javax.resource.api"/>
    <module name="javax.jms.api"/>
    <module name="javax.management.j2ee.api"/>
  </dependencies>
</module>

Note on <exclude path> section: I’ve added those to exclude mentioned packages because I don’t really want that classes to clash with my deployments where I use specific version of spring/aopalliance artifacts. If you really need to depend/import some classes from resource adapter directly in your code then IMHO you are doing something wrong.

Here’s how the structure of your module should look like:

activemq
    |main
    |   activemq-broker-5.9.0.jar
    |   activemq-client-5.9.0.jar
    |   activemq-jms-pool-5.9.0.jar
    |   activemq-kahadb-store-5.9.0.jar
    |   activemq-openwire-legacy-5.9.0.jar
    |   activemq-pool-5.9.0.jar
    |   activemq-protobuf-1.1.jar
    |   activemq-ra-5.9.0.jar
    |   activemq-spring-5.9.0.jar
    |   aopalliance-1.0.jar
    |   commons-logging-1.1.3.jar
    |   commons-net-3.3.jar
    |   commons-pool-1.6.jar
    |   geronimo-j2ee-management_1.1_spec-1.0.1.jar
    |   hawtbuf-1.9.jar
    |   log4j-1.2.17.jar
    |   module.xml
    |   slf4j-api-1.7.5.jar
    |   slf4j-log4j12-1.7.5.jar
    |   spring-aop-3.2.4.RELEASE.jar
    |   spring-beans-3.2.4.RELEASE.jar
    |   spring-context-3.2.4.RELEASE.jar
    |   spring-core-3.2.4.RELEASE.jar
    |   spring-expression-3.2.4.RELEASE.jar
    |   xbean-spring-3.14.jar
    |
    |   META-INF
            ra.xml

Module Configuration

Next thing is to configure resource adapter. Open your configuration file and add the following node within the resource-adapter subsystem:

<resource-adapters>
    <resource-adapter id="activemq-rar.rar">
        <module slot="main" id="org.apache.activemq"/>
        <transaction-support>NoTransaction</transaction-support>
        <config-property name="ServerUrl">
            tcp://localhost:61616
        </config-property>
        <connection-definitions>
            <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/ConnectionFactory" enabled="true" use-java-context="true" pool-name="ConnectionFactory"/>
        </connection-definitions>
        <admin-objects>
            <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="queue/test-queue" use-java-context="true" pool-name="test_queue">
                <config-property name="PhysicalName">
                    testQueue
                </config-property>
            </admin-object>
        </admin-objects>
    </resource-adapter>
</resource-adapters>

Now, (re)start your JBoss application server.
If everything is set correctly, in output/console/server log you should have line something like:

18:13:16,331 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-16) JBAS010405: Registered admin object at java:/queue/test-queue

From here on, you should be able to use connection factory and queue as usual in Java EE application.

How to use a Resource Adapter in your MDB?

In WildFly you can bind your MDBs to a specific Resource Adapter in three ways. Here’s how to do it!

1. At deployment descriptor level (jboss-ejb3.xml)

<jboss xmlns="http://www.jboss.com/xml/ns/javaee" 
    xmlns:jee="http://java.sun.com/xml/ns/javaee"
    xmlns:mdb="urn:resource-adapter-binding"
    xmlns:security="urn:security">

    <jee:assembly-descriptor>
        <mdb:resource-adapter-binding>
            <jee:ejb-name>SOCKET_MDB</jee:ejb-name>
            <mdb:resource-adapter-name>activemq-rar-5.7.0.rar</mdb:resource-adapter-name>
        </mdb:resource-adapter-binding>
    </jee:assembly-descriptor>
</jboss>

The above, is a sample jboss-ejb3.xml file which can be deployed along with your EJB (or WEB) project, which in turns maps the following MDB:

@MessageDriven(name = "SOCKET_MDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue.demoQueue"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")
},mappedName = "java:/jms/demoQueue")

public class HelloWorldQueueMDB implements MessageListener {

   
}

2. Annotate it in your MDB

Another option is by using the @org.jboss.ejb3.annotation.ResourceAdapter annotation within your MDB:

@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();
        }
    }
}

Please notice that the above @ResourceAdapter annotation requires a JBoss specific dependency to be used:

<dependency>
         <groupId>org.jboss.ejb3</groupId>
         <artifactId>jboss-ejb3-ext-api</artifactId>
         <scope>provided</scope>
</dependency>

3. Configure it at MDB Pool level

If you want to configure the Resource adapter for all the MDBs in your pool, then you can just configure it in the EJB3 subsystem:

<subsystem xmlns="urn:jboss:domain:ejb3:1.4">

. . . . .

    <mdb>
        <resource-adapter-ref resource-adapter-name="activemq-rar-5.7.0.rar"/>
        <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
    </mdb>

</subsystem>

Remember that you need to declare your resource adapter in a file name ironjacamar.xml which can be deployed alogn with your .rar file, or configure the resource adapter into the resource-adapters subsystem:

<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0">
    <resource-adapters>
        <resource-adapter>
            <archive>
                activemq-rar-5.7.0.rar
            </archive>
        </resource-adapter>
    </resource-adapters>
</subsystem>

Configuring a Resource Adapter for JBoss AS7: OpenMQ

This tutorial shows how to configure a Resource Adapter on JBoss AS 7. The purpose of it, is connecting your MDB on another JMS provider (OpenMQ).

What is a Resource Adapter ? to keep it simple, imagine a resource adapter something analogous to a JDBC driver. Both provide a standard API through which an application can access a resource that is outside the JEE server. For a resource adapter, the outside resource is an EIS (Enterprise Information system) and allows a standard  way for EIS vendor’s software to be integrated with JEE applications; on the other hand for a JDBC driver, it is a DBMS(Database Management System).

A resource adapter is stored in a RAR (Resource Adapter Archive) file and may be deployed on any JEE server, much like the EAR file of a JEE application.

 In this tutorial we will show how to configure a resource adapter for connecting with glassfish’s OpenMQ messaging system. So the first step is getting the OpenMQ RA. This one can be downloaded from http://mq.java.net/downloads.html  or you can get it bundled into Glassfish distribution (under the folder “GLASSFISH_HOME\mq\lib” ).

So , once you have got the file imqjmsra.rar unzip it with a common unzip tool.

As you can see, in the root folder you can find all the JARs which are used by OpenMQ and the Glassfish’s naming context interfaces. In the META-INF folder there’s the ra.xml file which contains all the information required to configure the Resource Adapter.

Now we need to configure the resource on JBoss AS 7: how can we do that ? JBoss AS 7 uses IronJacamar as JCA implementation.
The subsystem is contained into the AS 7 configuration file:

  <subsystem xmlns="urn:jboss:domain:jca:1.1">
  . . . . .
  </subsystem>

Now, the simplest way to create your resource adapter configuration is via the rar-info tool contained into the ironjacamar-1.x\doc\as folder. ( The official IronJacamar project page is  http://www.jboss.org/ironjacamar/ where you can download the software) .

The information about the resource adapter is generated using the following command:

./rar-info.sh imqjmsra.rar					

This will generate a report file named imqjmsra-report.txt.  This is the most important part of the report:

<resource-adapters>
  <resource-adapter>
    <archive>imqjmsra.rar</archive>
    <config-property name="UserName">guest</config-property>
    <config-property name="ConnectionURL">mq://localhost:7676/</config-property>
    <config-property name="Password">guest</config-property>
    <transaction-support>XATransaction</transaction-support>
    <connection-definitions>
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/QueueConnection" pool-name="QueueConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/QueueConnection" pool-name="QueueConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/TopicConnection" pool-name="TopicConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
    </connection-definitions>
    <admin-objects>
      <admin-object class-name="com.sun.messaging.Queue" enabled="true" jndi-name="java:jboss/eis/ao/Queue" pool-name="Queue" use-java-context="true">

      </admin-object>
      <admin-object class-name="com.sun.messaging.Topic" enabled="true" jndi-name="java:jboss/eis/ao/Topic" pool-name="Topic" use-java-context="true">

      </admin-object>
    </admin-objects>
  </resource-adapter>
</resource-adapters>

We need applying just a little change to this XML: get rid of the resource-adapters and resource-adapter and archive root elements and replace them with the <ironjacamar> element as follows:

<?xml version="1.0" encoding="UTF-8"?>

<ironjacamar>

    <config-property name="UserName">guest</config-property>
    <config-property name="ConnectionURL">mq://localhost:7676/</config-property>
    <config-property name="Password">guest</config-property>
    <transaction-support>XATransaction</transaction-support>
    <connection-definitions>
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/QueueConnection" pool-name="QueueConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>

     <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/QueueConnection" pool-name="QueueConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>

      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/TopicConnection" pool-name="TopicConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
    </connection-definitions>
    <admin-objects>
      <admin-object class-name="com.sun.messaging.Queue" enabled="true" jndi-name="java:jboss/eis/ao/Queue" pool-name="Queue" use-java-context="true">

      </admin-object>
      <admin-object class-name="com.sun.messaging.Topic" enabled="true" jndi-name="java:jboss/eis/ao/Topic" pool-name="Topic" use-java-context="true">

      </admin-object>
    </admin-objects>

</ironjacamar>

Deploying the Resource Adapter file (ironjacamar.xml)

The simplest way to deploy the Resource Adapter is using an exploded directory which will contain all the configuration files: create a dir named imqjmsra.rar and save the file created with rar-info under the META-INF folder of it, with the name ironjacamar.xml

 Next step are Resource Adapter libraries : since you might want to deploy remote JMS clients (using OpenMQ JNDI) it’s better to install them as module so also other applications can use them.

Create the path modules\com\sun\openmq\main under your installation. There add the JAR files contained into imqjmsra.rar and configure the module in module.xml:

<module xmlns="urn:jboss:module:1.1" name="com.sun.openmq">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

    <dependencies>
        <module name="javax.jms.api" />
        <module name="javax.resource.api"/>
        <module name="javax.api"/>

    </dependencies>

    <resources>
       <resource-root path="fscontext.jar"/>
       <resource-root path="imqbroker.jar"/>
       <resource-root path="imqjmsbridge.jar"/>
       <resource-root path="imqjmsra.jar"/>
       <resource-root path="imqjmx.jar"/>
       <resource-root path="imqstomp.jar"/>

    </resources>
</module>

Fine, now let’s return to our exploded folder and let’s add the module dependency in MANIFEST.MF

Manifest-Version: 1.0
Dependencies: com.sun.openmq export

So this will be our imqjmsra.rar which will just contains three files into the META-INF folder:

imqjmsra.rar
+---META-INF
    ¦   ironjacamar.xml
    ¦   MANIFEST.MF
    ¦   ra.xml

So, when things go OK we should have finished with the resource adapter configuration. All we need is deploying the resource adapter into JBoss AS 7.
Unfortunately installing the RA took a lot more of headaches, since the OpenMQ RA does not seem 100% conform to ActivationSpec. But we fixed and with huge pleasure we managed to get it working!


First issue: when deploying the resource adapter as it is, the deployer raises the following error:
org.jboss.jca.validator.ValidatorException: Severity: ERROR
Section: 19.4.2
Description: A ResourceAdapter must implement a “public int hashCode()” method.
Code: com.sun.messaging.jms.ra.ResourceAdapter

Severity: ERROR
Section: 19.4.2
Description: A ResourceAdapter must implement a “public boolean equals(Object)” method.
Code: com.sun.messaging.jms.ra.ResourceAdapter

So obviously our RA doesn’t seem 100% compliant. There are two things you can do, one is implementing the two methods by yourself in the com.sun.messaging.jms.ra.ResourceAdapter class, or turn off validation on the JBoss JCA subsystem. We will choose the latter so turn off archive validation in your AS 7 configuration:

<subsystem xmlns="urn:jboss:domain:jca:1.1">
  <archive-validation enabled="false" fail-on-error="true" fail-on-warn="false"/>
  . . . .
</subsystem>

Second issue: the second issue we faced was a bit harder, as a matter of fact there was a NPE when the resource adapter was initialized:

13:34:15,054 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-6) MSC00001: Failed to start service jboss.ra.deployer.imqjmsra: org.jboss.msc.service.StartException in service jboss.ra.deployer.imqjmsra: JBAS010446: Failed to start RA deployment [imqjmsra]
        at org.jboss.as.connector.services.resourceadapters.deployment.ResourceAdapterDeploymentService.start(ResourceAdapterDeploymentService.java:105)
        . . . . .
Caused by: org.jboss.jca.deployers.common.DeployException: IJ020052: Unable to associate com.sun.messaging.jms.ra.ActivationSpec
        at org.jboss.jca.deployers.common.AbstractResourceAdapterDeployer.associateResourceAdapter(AbstractResourceAdapterDeployer.java:386)
        … 10 more
Caused by: java.lang.NullPointerException
        at com.sun.messaging.jms.ra.ResourceAdapter._getRAUID(ResourceAdapter.java:2081)
        at com.sun.messaging.jms.ra.ActivationSpec.setResourceAdapter(ActivationSpec.java:331)

The problem is buried into the _getRAUID method which fails to return the Resource Adapter Id. The only viable choice is getting our hands dirty with the source code. This is the part of the code we are dealing with:

protected String _getRAUID() {

        if (raUID==null && !_isRADirect()){
            try {

                XAConnectionImpl xaci = (com.sun.messaging.jmq.jmsclient.XAConnectionImpl) xacf.createXAConnection();
                raUID = Long.toString(xaci.generateUID());
                xaci.close();
            } catch (JMSException jmse){
                _loggerB.severe("Unable to generate UID:"+jmse.getMessage());
            }
        }

        return null;
    }

What happens here is that a lazy initialization of the XAConnection is performed. As per ActivationSpec we should initialize our resources into the start method of our Resource Adapter, so change this method to:

protected String _getRAUID() {


        if (  !_isRADirect()){
            return raUID;
        }

        return null;
    }

and add the XA Connection creation at the end of the start method:

    public synchronized void start(BootstrapContext ctx) throws ResourceAdapterInternalException {
       . . ..
      try {
                XAConnectionImpl xaci = (com.sun.messaging.jmq.jmsclient.XAConnectionImpl) xacf.createXAConnection();
                raUID = Long.toString(xaci.generateUID());


                xaci.close();
            } catch (JMSException jmse){
                _loggerB.severe("Unable to generate UID:"+jmse.getMessage());
            }


    }

It was necessary to compile the new class (just add all the OpenMQ libraries in your classpath) and update the archive in the modules section:

jar uvf com imqjmsra.jar	

(The class ResourceAdapter.java is contained in the package com.sun.messaging.jms.ra)
Great, we’re almost there. The last cry of the application server is about a duplicate resource java:jboss/eis/QueueConnection

07:09:21,668 ERROR [org.jboss.msc.service] (MSC service thread 1-5) MSC00002: Invocation of listener “org.jboss.as.connector.deployers.ra.processors.ParsedRaDeploymentProcessor$1@1e7a6ae” failed: java.lang.IllegalStateException: JBAS014666:
 Duplicate resource java:jboss/eis/QueueConnection

Recall the file ironjacamar.xml ? careful readers should have noticed that it actually contains a duplication for the resource resource java:jboss/eis/QueueConnection . However that’s not the fault of the rarinfo tool, it’s the ra.xml file (which ships with the RA) that contains the duplication (the rarinfo creates the sample RA connection from the ra.xml file)

So this is the final ironjacamar.xml file which needs to be deployed in META-INF:

<?xml version="1.0" encoding="UTF-8"?>

<ironjacamar>

    <config-property name="UserName">guest</config-property>
    <config-property name="ConnectionURL">mq://localhost:7676/</config-property>
    <config-property name="Password">guest</config-property>
    <transaction-support>XATransaction</transaction-support>
    <connection-definitions>
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/QueueConnection" pool-name="QueueConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
      
      <connection-definition class-name="com.sun.messaging.jms.ra.ManagedConnectionFactory" enabled="true" jndi-name="java:jboss/eis/TopicConnection" pool-name="TopicConnection" use-ccm="true" use-java-context="true">
        <config-property name="UserName">guest</config-property>
        <config-property name="AddressList">localhost</config-property>
        <config-property name="Password">guest</config-property>
        <xa-pool>
          <min-pool-size>0</min-pool-size>
          <max-pool-size>10</max-pool-size>
          <prefill>false</prefill>
          <use-strict-min>false</use-strict-min>
          <flush-strategy>FailingConnectionOnly</flush-strategy>
          <pad-xid>false</pad-xid>
          <wrap-xa-resource>true</wrap-xa-resource>
        </xa-pool>
        <security>
          <application/>
        </security>
      </connection-definition>
    </connection-definitions>
    <admin-objects>
      <admin-object class-name="com.sun.messaging.Queue" enabled="true" jndi-name="java:jboss/eis/ao/Queue" pool-name="Queue" use-java-context="true">

      </admin-object>
      <admin-object class-name="com.sun.messaging.Topic" enabled="true" jndi-name="java:jboss/eis/ao/Topic" pool-name="Topic" use-java-context="true">

      </admin-object>
    </admin-objects>
 
</ironjacamar>

Great, now we’re finally ready. You need to start your Glassfish server where OpenMQ lives.

glassfish/bin/startserv.sh

Fine, now start JBoss AS 7 (hint: in order to avoid conflicts with glassfish, if you are running both on the same Pc, apply a port-offset to your configuration)


    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="200">

 On your JBoss AS 7 console you should now see:
 
 13:04:31,862 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-3)
JBAS010401: Bound JCA ConnectionFactory [java:jboss/eis/TopicConnection]
13:04:31,863 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-2)
JBAS010401: Bound JCA AdminObject [java:jboss/eis/ao/Topic]
13:04:31,864 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-5)
JBAS010401: Bound JCA AdminObject [java:jboss/eis/ao/Queue]
13:04:31,863 INFO [org.jboss.as.deployment.connector] (MSC service thread 1-4)
JBAS010401: Bound JCA ConnectionFactory [java:jboss/eis/QueueConnection]

Great! now let’s test everything:


We will create a ConnectionFactory and a JMS Destination (Queue) on the Glassifsh side. Move to the GF administration console (http://localhost:4848):

Here’s the ConnectionFactory:

and here’s a Queue Destination which will be consumed by JBoss AS 7

So that is it: Now we need an MDB on your JBoss AS 7 instance which will consume messages from the external provider.

Here’s our simple MDB impementation: notice the most important part: the @ResourceAdapter definition:

package com.sample;

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 = "destination", propertyValue = "demoQueue"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") 
        
})
@ResourceAdapter("imqjmsra.rar")
public class MDBSample implements MessageListener {
     
   public void onMessage(Message message) {

     TextMessage tm = (TextMessage) message;
       try {

         System.out.println("Received message "+tm.getText());

       } catch (JMSException e) {
  
        e.printStackTrace();
       }
 

   }

}

Deploy your MDB on JBoss AS 7. Now for testing it, I have created a simple JMS client, which will run on Glassfish server.

package com.sample;

import java.io.IOException;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet("/Test")
public class Test extends HttpServlet {
    private static final long serialVersionUID = 1L;


    @Resource(name="connFactory", mappedName="GFConnectionFactory")
    private QueueConnectionFactory qFactory;

    @Resource(name="demoQueue", mappedName="demoQueue")
    private Queue queue;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        try {
            QueueConnection qConn = (QueueConnection)qFactory.
                    createConnection();

            Session session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer publisher;
            publisher = session.createProducer(queue);

            qConn.start();

            TextMessage message = session.createTextMessage("Received Message Hello AS 7 !");
            publisher.send(message);
        } catch (JMSException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
    }

}

It was with great satisfaction that I could read the message on the JBoss AS 7 console!!!!

Download the zip folder containing the RA configuration