Chapter 6. Using JMS

Although HornetQ provides a JMS agnostic messaging API, many users will be more comfortable using JMS.
JMS is a very popular API standard for messaging, and most messaging systems provide a JMS API.
This section will cover the main steps in configuring the server for JMS and creating a simple JMS program. It will also show how to configure and use JNDI, and how to use JMS with HornetQ without using any JNDI.

6.1. A Simple Ordering System - Configuration Example

This configuration example uses a single JMS Queue called OrderQueue, with a single MessageProducer sending an order messages to the queue. A single MessageConsumer consumes the order message from the queue.
The queue is configured to be durable, (it will survive a server restart or crash).
The example also shows how to specify the queue in the server JMS configuration so it is created automatically without having to explicitly create it from the client.

6.1.1. JMS Server Configuration

The file hornetq-jms.xml on the server classpath (in standard configurations, JBOSS_DIST/jboss-as/server/<PROFILE>/deploy/hornetq/hornetq-jms.xml) contains any JMS queue, topic and ConnectionFactory instances that we wish to create and make available to lookup via the JNDI.
A JMS ConnectionFactory object is used by the client to make connections to the server. It knows the location of the server it is connecting to, as well as many other configuration parameters. In most cases the defaults will be acceptable.
The example will deploy a single JMS queue and a single JMS Connection Factory instance on the server for this example but there are no limits to the number of queues, topics and ConnectionFactory instances you can deploy from the file. Here is the configuration:
<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hornetq ../schemas/hornetq-jms.xsd ">
   <connection-factory name="NettyConnectionFactory">
      <connectors>
         <connector-ref connector-name="netty"/>
      </connectors>
      <entries>
         <entry name="/ConnectionFactory"/>           
      </entries>
   </connection-factory>
   <queue name="OrderQueue">
      <entry name="queues/OrderQueue"/>
   </queue>
</configuration>
One ConnectionFactory called ConnectionFactory is deployed and bound in just one place in JNDI as given by the entry element. ConnectionFactory instances can be bound in many places in JNDI if it is required.

Note

The JMS connection factory references a connector called netty. This is a reference to a connector object deployed in the main core configuration file <JBOSS_HOME>/jboss-as/server/<PROFILE>/deploy/hornetq/hornetq-configuration.xml, which defines the transport and parameters used to actually connect to the server.

6.1.2. Connection Factory Types

The JMS API doc provides several connection factories for applications. HornetQ JMS users can choose to configure the types for their connection factories. Each connection factory has a signature attribute and a xa parameter, the combination of which determines the type of the factory.
Attribute signature has three possible string values (generic, queue and topic).
xa is a boolean type parameter. The following table gives their configuration values for different connection factory interfaces.

Table 6.1. Configuration for Connection Factory Types

signature xa Connection Factory Type
generic (default) false (default) javax.jms.ConnectionFactory
generic true javax.jms.XAConnectionFactory
queue false javax.jms.QueueConnectionFactory
queue true javax.jms.XAQueueConnectionFactory
topic false javax.jms.TopicConnectionFactory
topic true javax.jms.XATopicConnectionFactory
As an example, the following configures an XAQueueConnectionFactory:
<configuration xmlns="urn:hornetq" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:hornetq ../schemas/hornetq-jms.xsd ">
    
    <connection-factory name="ConnectionFactory" signature="queue">
        <xa>true</xa>
        <connectors>
           <connector-ref connector-name="netty"/>
        </connectors>
        <entries>
            <entry name="/ConnectionFactory"/>           
        </entries>
    </connection-factory>
</configuration>

6.1.3. The code

The code for the example is available below.
The first step is to create a JNDI initial context from which to look up JMS objects.
InitialContect ic = new InitialContext();
The next step is to look up the connection factory:
ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory");
Followed by looking up the Queue:
Queue orderQueue = (Queue)ic.lookup("/queues/OrderQueue");
Next, create a JMS connection using the connection factory:
Connection connection = cf.createConnection();
Create a non transacted JMS Session, with AUTO_ACKNOWLEDGE acknowledge mode:
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Create a MessageProducer that will send orders to the queue:
MessageProducer producer = session.createProducer(orderQueue);
Create a MessageConsumer which will consume orders from the queue:
MessageConsumer consumer = session.createConsumer(orderQueue);
Make sure to start the connection, or delivery will not occur on it:
connection.start();
Create a simple TextMessage and send it:
TextMessage message = session.createTextMessage("This is an order");
producer.send(message);
Consume the message:
TextMessage receivedMessage = (TextMessage)consumer.receive();
System.out.println("Got order: " + receivedMessage.getText());

Warning

JMS connections, sessions, producers, and consumers are designed to be re-used.
It is an anti-pattern to create new connections, sessions, producers, and consumers for each message you produce or consume. If you do this, your application will perform very poorly. This is discussed further in Chapter 43, Performance Tuning.