Java EE Resource Adapter Configuration Example

This example demonstrates how to configure several properties on the HornetQ Resource Adapter. We setup two JBoss Servers. The enterprise application is being deployed in one application server while the MDBs and JMS Connections are pointing to a remote server

This example is composed of two message-driven beans (MDB), MDBQueueA and MDBQueueB, and a stateless session bean StatelessSender and a main class MDBRemoteClientExample.

MDBRemoteClientExample will invoke the StatelessSender bean which will in tirun send a message to 2 queues which will then be consumed by each MDB.

MDBQueueA is on the same server as the StatelessSender bean and consumes the message locally.

MDBQueueB is on the second server who's JCA Adapter is configured to consume remotely from the first server

A Resource Adapter is a way to connect any system provider to an application server, and is integral part of the Java Connectors Architecture specification.

HornetQ provides its own adapter and this example will provide you a quick tutorial on how to configure some of the default properties, and how to change the default values on MDB Inbound Properties, or on ConnectionFactory Outbound Properties.

This ResourceAdapter is what provides integration for Message-Driven Beans or DataSource integration on the application server.

MDB Properties

You can configure the adapter through ActivactionConfigProperties on the MDB. Example:

           @MessageDriven(name = "MessageMDBExample",
               activationConfig =
                     {
                        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
                        @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue"),
                        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
                        @ActivationConfigProperty(propertyName = "ConnectorClassName", propertyValue = "org.hornetq.core.remoting.impl.netty.NettyConnectorFactory"),
                        @ActivationConfigProperty(propertyName = "ConnectionParameters", propertyValue = "hornetq.remoting.netty.port=5545")
                     })
            public class MDBRemoteExample implements MessageListener
        

MDB Properties can also be defined on XML Files. The JBoss EJB3 Documentation will have more information.

Specifying a different resource adapter

Optionally you could also define the resource adapter you are using. On JBoss EJB3 there is a JBoss specific tag where you can define the Resource-adapter file name:


...
import org.jboss.ejb3.annotation.ResourceAdapter;

@MessageDriven(name = "MessageMDBExample",
               activationConfig =
                     {
                                ...
                     })
                     @ResourceAdapter("example-hornetq-ra.rar")
public class MDBRemoteExample implements MessageListener
...

In this example however we will configure the default adapter.

Other application servers will provide different ways of binding the resource-adapter.

Connection Factory Properties

You can configure ConnectionFactories that you use outside of the MDB context, such as in your SessionBeans. On JBoss Application Server, that could be defined on a datasource deployment file (-ds.xml), using Configuration-properties on the connection factory.

For example, jms-remote-ds.xml

<connection-factories>


   <tx-connection-factory>
      <jndi-name>RemoteJmsXA</jndi-name>
      <xa-transaction/>
      <rar-name>jms-ra.rar</rar-name>
      <connection-definition>org.hornetq.ra.HornetQRAConnectionFactory</connection-definition>
      <config-property name="SessionDefaultType" type="java.lang.String">javax.jms.Topic</config-property>
      <config-property name="ConnectorClassName" type="java.lang.String">org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</config-property>
      <config-property name="ConnectionParameters" type="java.lang.String">hornetq.remoting.netty.port=5545</config-property>
      <max-pool-size>20</max-pool-size>
   </tx-connection-factory>


</connection-factories>

Resource Adapter Global Properties

It is possible to also change global configuration at the HornetQ resource adapter. The default installation script will install the HornetQ resource adapter at $JBOSS_HOME/server/YOUR-SERVER/deploy/hornetq-ra.rar.

To change these properties, open the ra.xml under jms-ra.rar/META-INF

Example for ra.xml:

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

<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">

...


   <resourceadapter>
      <resourceadapter-class>org.hornetq.ra.HornetQResourceAdapter</resourceadapter-class>
      <config-property>
         <description>The transport type</description>
         <config-property-name>ConnectorClassName</config-property-name>
         <config-property-type>java.lang.String</config-property-type>
         <config-property-value>org.hornetq.core.remoting.impl.invm.InVMConnectorFactory</config-property-value>
      </config-property>
      <config-property>
         <description>The transport configuration. These values must be in the form of key=val;key=val;</description>
         <config-property-name>ConnectionParameters</config-property-name>
         <config-property-type>java.lang.String</config-property-type>
         <config-property-value>server-id=0</config-property-value>
      </config-property>
       <config-property>
        <description>Use XA methods to obtain connections?</description>
        <config-property-name>UseXA</config-property-name>
        <config-property-type>java.lang.Boolean</config-property-type>
        <config-property-value>true</config-property-value>
      </config-property>
      <config-property>
        <description>The user name used to login to the JMS server</description>
        <config-property-name>UserName</config-property-name>
        <config-property-type>java.lang.String</config-property-type>
        <config-property-value></config-property-value>
      </config-property>


...

Refer to the Resource Adapter Chapter on the HornetQ Documentation for more information about configuring the ra.xml properties.

You may choose to deploy multiple HornetQ resource adapters on the same application server, for example if you are connecting to different HornetQ servers and if you wish to have a higher control of properties on each server you are connecting to. You will be able to determine which rar you are using individually at each MDB and ConnectionFactory as specified before here. Just copy the directory jms-ra.rar in your application as any other name with the extension .rar and use that file name at your deployments.

Please refer to HornetQ Quickstart guide to install it in JBoss AS 5

Example step-by-step

To deploy and start the first server, simply type ./build.sh deploy (or build.bat deploy on windows) from the example directory

After the first server has started start the second server, simply type ./build.sh deploy2 (or build.bat deploy2 on windows) from the example directory

To run the example, simply type ./build.sh run (or build.bat run on windows) from the example directory

To undeploy the example, simply type ./build.sh undeploy undeploy2 (or build.bat undeploy undeploy2 on windows) from the example directory

** make sure that JBOSS_HOME is set to the JBoss installation directory

  1. First we need to get an initial context so we can look-up the EJB on the second server from JNDI. This initial context will get it's properties from the jndi.properties file in the directory config
  2.             initialContext = new InitialContext();
             
  3. Getting a reference to the Stateless Bean
  4.             StatelessSenderService sender = (StatelessSenderService)initialContext.lookup("mdb-example/StatelessSender/remote");
             
  5. Calling the Stateless Bean
  6.             sender.sendHello("Hello there MDB!");
             
  7. On the second server we invoke the EJB StatelessSender: This will send 2 messages to server 1 using the configured outbound adapter
  8.             HornetQQueue destQueueA = new HornetQQueue("A");
                HornetQQueue destQueueB = new HornetQQueue("B");
             
  9. Create a connection to a remote server using a connection-factory (look at the deployed file jms-remote-ds.xml). JCA will actually manage this thorugh a Connection Pool
  10.             Connection conn = connectionFactory.createConnection("guest", "guest");
             
  11. Send a message to a QueueA on server1, which will be received by MDBQueueA on server1
  12.             Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer prodA = sess.createProducer(destQueueA);
                prod.send(sess.createTextMessage(message));
             
  13. Send a message to a QueueB on the remote server1, which will be received by MDBQueueA on server2
  14.             MessageProducer prodB = sess.createProducer(destQueueB);
                prodB.send(sess.createTextMessage(message));
             
  15. Close the connection. (Since this is a JCA connection, this close will save the connection to a connection pool)
  16.             conn.close();
             
  17. The message is received on the MDBQueueA on server1 which consumed from a local queue
  18. @MessageDriven(name = "MDB_QueueA",
                   activationConfig =
                         {
                            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
                            @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/A"),
                            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"))
                         })
    public class MDBQueueA implements MessageListener
    {
       public void onMessage(Message message).....
             
  19. Another message is received on MDBQueueB on server2 which consumed from a remote queue on server1.
    @MessageDriven(name = "MDB_QueueB",
                   activationConfig =
                         {
                            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
                            @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/B"),
                            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")
                        })
                  @ResourceAdapter("example-hornetq-ra.rar")
    
    public class MDBQueueB implements MessageListener
    {
       public void onMessage(Message message).....