Chapter 14. Messaging

14.1. HornetQ

14.1.1. HornetQ

HornetQ is a multi-protocol, asynchronous messaging system developed by Red Hat. HornetQ provides high availability (HA) with automatic client failover to guarantee message reliability in the event of a server failure. HornetQ also supports flexible clustering solutions with load-balanced messages.

14.1.2. About Java Messaging Service (JMS)

Messaging systems allow you to loosely couple heterogeneous systems together with added reliability. Java Messaging Service (JMS) providers use a system of transactions, to commit or roll back changes atomically. Unlike systems based on a Remote Procedure Call (RPC) pattern, messaging systems primarily use an asynchronous message passing pattern with no tight relationship between requests and responses. Most messaging systems also support a request-response mode but this is not a primary feature of messaging systems.
Messaging systems decouple the senders of messages from the consumers of messages. The senders and consumers of messages are completely independent and know nothing of each other. This allows you to create flexible, loosely coupled systems. Often, large enterprises use a messaging system to implement a message bus which loosely couples heterogeneous systems together. Message buses often form the core of an Enterprise Service Bus (ESB). Using a message bus to decouple disparate systems can allow the system to grow and adapt more easily. It also allows more flexibility to add new systems or retire old ones since they don't have brittle dependencies on each other.

14.1.3. Supported Messaging Styles

HornetQ supports the following messaging styles:
Message Queue pattern
The Message Queue pattern involves sending a message to a queue. Once in the queue, the message is usually made persistent to guarantee delivery. Once the message has moved through the queue, the messaging system delivers it to a message consumer. The message consumer acknowledges the delivery of the message once it is processed.
When used with point-to-point messaging, the Message Queue pattern allows multiple consumers for a queue, but each message can only be received by a single consumer.
Publish-Subscribe pattern
The Publish-Subscribe pattern allows multiple senders to send messages to a single entity on the server. This entity is often known as a "topic". Each topic can be attended by multiple consumers, known as "subscriptions".
Each subscription receives a copy of every message sent to the topic. This differs from the Message Queue pattern, where each message is only consumed by a single consumer.
Subscriptions that are durable retain copies of each message sent to the topic until the subscriber consumes them. These copies are retained even in the event of a server restart. Non-durable subscriptions last only as long as the connection that created them.

14.1.4. About Acceptors and Connectors

HornetQ uses the concept of connectors and acceptors as a key part of the messaging system.

Acceptors and Connectors

Acceptor
An acceptor defines which types of connections are accepted by the HornetQ server.
Connector
A connector defines how to connect to a HornetQ server, and is used by the HornetQ client.
There are two types of connectors and acceptors, relating to the whether the matched connector and acceptor pair occur within same JVM or not.

Invm and Netty

Invm
Invm is short for Intra Virtual Machine. It can be used when both the client and the server are running in the same JVM.
Netty
The name of a JBoss project. It must be used when the client and server are running in different JVMs.
A HornetQ client must use a connector that is compatible with one of the server's acceptors. Only an Invm connector can connect to an Invm acceptor, and only a netty connector can connect to a netty acceptor. The connectors and acceptors are both configured on the server in a standalone.xml and domain.xml. You can use either the Management Console or the Management CLI to define them.

Example 14.1. Example of the Default Acceptor and Connector Configuration

<connectors>
    <netty-connector name="netty" socket-binding="messaging"/>
    <netty-connector name="netty-throughput" socket-binding="messaging-throughput">
        <param key="batch-delay" value="50"/>
    </netty-connector>
    <in-vm-connector name="in-vm" server-id="0"/>
</connectors>
<acceptors>
    <netty-acceptor name="netty" socket-binding="messaging"/>
    <netty-acceptor name="netty-throughput" socket-binding="messaging-throughput">
        <param key="batch-delay" value="50"/>
        <param key="direct-deliver" value="false"/>
    </netty-acceptor>
    <in-vm-acceptor name="in-vm" server-id="0"/>
</acceptors>
The example configuration also shows how the JBoss Enterprise Application Platform 6 implementation of HornetQ uses socket bindings in the acceptor and connector configuration. This differs from the standalone verson of HornetQ, which requires you to declare the specific hosts and ports.

14.1.5. About Bridges

The function of a bridge is to consume messages from a source queue, and forward them to a target address, typically on a different HornetQ server. Bridges cope with unreliable connections, automatically reconnecting when the connections become available again. HornetQ bridges can be configured with filter expressions to only forward certain messages.

14.1.6. Work with Large Messages

HornetQ supports the use of large messages even when either the client or server has limited amounts of memory. Large messages can be streamed as they are, or compressed further for more efficient transferral.

14.1.7. Configure High-availability (HA) Failover

High-availability failover is available with either automatic client failover or application-level failover.

Important

HornetQ HA only supports shared stores on GFS2 on SAN.

14.1.8. Embed HornetQ in Applications

To implement messaging functionality internally within an application, you can directly instantiate HornetQ clients and servers in the application code. This is called embedding HornetQ.
  1. Instantiate the configuration object

    Instantiate the configuration object either from a configuration file, or by setting configuration parameters programmatically.
    • Create the configuration object from a file

      Use the FileConfigurationImpl class to set a configuration object based on a file.
      import org.hornetq.core.config.Configuration;
      import org.hornetq.core.config.impl.FileConfiguration;
      ...
      Configuration config = new FileConfiguration();
      config.setConfigurationUrl(<replaceable>file-url</replaceable>);
      config.start();
    • Create the configuration object programmatically

      1. Use the ConfigurationImpl class to create a configuration object.
        import org.hornetq.core.config.Configuration;
        import org.hornetq.core.config.impl.FileConfiguration;
        ...
        Configuration config = new ConfigurationImpl();
      2. Set any configuration parameters programmatically, such as acceptors. For example:
        HashSet<TransportConfiguration> transports = new HashSet<TransportConfiguration>();
              
        transports.add(new TransportConfiguration(NettyAcceptorFactory.class.getName()));
        transports.add(new TransportConfiguration(InVMAcceptorFactory.class.getName()));
        
        config.setAcceptorConfigurations(transports);
  2. Instantiate and start the server

    Use the org.hornetq.api.core.server.HornetQ static methods to create and start a server based on the configuration object.
    import org.hornetq.api.core.server.HornetQ;
    import org.hornetq.core.server.HornetQServer;
    ...
    HornetQServer server = HornetQ.newHornetQServer(config);
    server.start();
Result:

An embedded HornetQ instance is instantiated for internal messaging. To connect clients to the embedded HornetQ, create factories as normal.

14.1.9. Configure the JMS Server

To configure the JMS Server for HornetQ, edit the server configuration file. The server configuration is contained in the EAP_HOME/domain/configuration/domain.xml file for domain servers, or in the EAP_HOME/standalone/configuration/standalone.xml file for standalone servers.
The <subsystem xmlns="urn:jboss:domain:messaging:1.2"> element contains all JMS configuration. Add any JMS ConnectionFactory, Queue, or Topic instances required for the JNDI.
  1. Enable the JMS subsystem in the JBoss Enterprise Application Platform.

    In the <extensions> element, verify that the following line is present and is not commented out:
    <extension module="org.jboss.as.messaging"/>
  2. Add the basic JMS subsystem.

    If the Messaging subsystem is not present in your configuration file, add it.
    1. Look for the <profile> which corresponds to the profile you use, and locate its <subsystems> tag.
    2. Add a new line just beneath the <subsystems> tag. Paste the following into it:
      <subsystem xmlns="urn:jboss:domain:messaging:1.2">
      
      </subsystem>
      All further configuration will be added to the empty line above.
  3. Add basic configuration for JMS.

    <journal-file-size>102400</journal-file-size>
    <journal-min-files>2</journal-min-files>
    <journal-type>NIO</journal-type>
    <!-- disable messaging persistence -->
    <persistence-enabled>false</persistence-enabled>
    Customize the values above to meet your needs.
  4. Add connection factory instances to HornetQ

    The client uses a JMS ConnectionFactory object to make connections to the server. To add a JMS connection factory object to HornetQ, include a single <jms-connection-factories> tag and <connection-factory> element for each connection factory as follows:
    <subsystem xmlns="urn:jboss:domain:messaging:1.2">
      ...
      <jms-connection-factories>
        <connection-factory name="myConnectionFactory">
          <connectors>
            <connector-ref connector-name="netty"/>
          </connectors>
          <entries>
            <entry name="/ConnectionFactory"/>           
          </entries>
        </connection-factory>
      </jms-connection-factories>
      ...
    </subsystem>
  5. Configure the netty connector

    This JMS connection factory uses a netty connector. This is a reference to a connector object deployed in the server configuration file. The connector object defines the transport and parameters used to actually connect to the server.
    To configure the netty connector, include the following settings:
    <subsystem xmlns="urn:jboss:domain:messaging:1.2">
      ...
      <connectors>
        <netty-connector name="netty" socket-binding="messaging"/>
        <netty-connector name="netty-throughput" socket-binding="messaging-throughput">
          <param key="batch-delay" value="50"/>
        </netty-connector>
        <in-vm-connector name="in-vm" server-id="0"/>
      </connectors>
      ...
    </subsystem>
    The connector references the messaging and messaging-throughput socket bindings. The messaging socket binding uses port 5445, and the messaging-throughput socket binding uses port 5455. Ensure the following socket bindings are present in the <socket-binding-groups> element:
    <socket-binding-groups>
      ...
      <socket-binding-group ... >
        <socket-binding name="messaging" port="5445"/>
        <socket-binding name="messaging-throughput" port="5455"/>
        ...
      </socket-binding-group>
      ...
    </socket-binding-groups>
  6. Add queue instances to HornetQ

    The client uses a JMS Queue object to stage sent messages for delivery to the server. To add a JMS queue object to HornetQ, include a <jms-queue> element as follows:
    <subsystem xmlns="urn:jboss:domain:messaging:1.2">
      ...
      <jms-destinations>
        <jms-queue name="myQueue">
          <entry name="/queue/myQueue"/>
        </jms-queue>
      </jms-destinations>
      ...
  7. Optional: Add topic instances to HornetQ

    The client uses a JMS Topic object to manage messages for multiple subscribers. To add a JMS topic object, include a <topic> element as follows:
    <subsystem xmlns="urn:jboss:domain:messaging:1.2">
        ...
        <jms-topic name="myTopic">
            <entry name="/topic/myTopic"/>
        </jms-topic>
        ...
  8. Perform additional configuration

    If you need additional settings, review the DTD in EAP_HOME/docs/schema/jboss-messaging_1_2.xsd.

14.1.10. About Java Naming and Directory Interface (JNDI)

The Java Naming and Directory Interface (JNDI) is a standard Java API for naming and directory services. It allows Java-based technologies to discover and organize named components in a distributed computing environment.

14.1.11. Configure JNDI for HornetQ

Procedure 14.1. Task

When the JBoss Enterprise Application Platform runs as a managed domain, a JNDI server is provided and does not need configuration.
Follow this procedure to configure the JNDIServer bean for HornetQ when the JBoss Enterprise Application Server is running as a standalone server.
  1. Set the JNDI properties on the client side

    The JNDI properties tell the JNDI client where to locate the JNDI server. The properties can be specified in a file named jndi.properties on the client classpath, or declared directly when creating the initial JNDI context.
    Set the JNDI properties to the following settings:
    java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
    java.naming.provider.url=jnp://hostname:1099
    java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
    • hostname is the hostname or IP address of the JNDI server.
  2. Configure the JNDI server ports

    1. Navigate to the Socket Binding Groups panel in the Management Console

      Select the General ConfigurationSocket Binding Groups option from the menu on the left of the console.
      The Socket Binding Groups panel for the selected server appears.
    2. Edit the JNDI Socket Binding

      Select jndi from the Socket Binding Declarations table, then select the Edit button in the Socket Binding section below.
      Configure the following settings: and Multicast Port settings. Select the Save button when done.
      • Port:1099
      • Multicast Port:1098
Result

The JNDI server is now configured for HornetQ.

14.1.12. Configure JMS Address Settings

The JMS subsystem has several configurable options which control aspects of how and when a message is delivered, how many attempts should be made, and when the message expires. These configuration options all exist within the <address-settings> configuration element.
A common feature of address configurations is the syntax for matching multiple addresses, also known as wild cards.
Wildcard Syntax

Address wildcards can be used to match multiple similar addresses with a single statement, similar to how many systems use the asterisk ( *) character to match multiple files or strings with a single search. The following characters have special significance in a wildcard statement.

Table 14.1. JMS Wildcard Syntax

Character Description
. (a single period) Denotes the space between words in a wildcard expression.
# (a pound or hash symbol) Matches any sequence of zero or more words.
* (an asterisk) Matches a single word.

Table 14.2. JMS Wildcard Examples

Example Description
news.europe.#
Matches news.europe, news.europe.sport, news.europe.politic, but not news.usa or europe.
news.
Matches news.europe but not news.europe.sport.
news.*.sport
Matches news.europe.sport and news.usa.sport, but not news.europe.politics.

Example 14.2. Default Address Setting Configuration

The values in this example are used to illustrate the rest of this topic.
<address-settings>
    <!--default for catch all-->
    <address-setting match="#">
        <dead-letter-address>jms.queue.DLQ</dead-letter-address>
        <expiry-address>jms.queue.ExpiryQueue</expiry-address>
        <redelivery-delay>0</redelivery-delay>
        <max-size-bytes>10485760</max-size-bytes>
        <address-full-policy>BLOCK</address-full-policy>
        <message-counter-history-day-limit>10</message-counter-history-day-limit>
    </address-setting>
</address-settings>

Table 14.3. Description of JMS Address Settings

Element Description Default Value Type
address-full-policy
Determines what happens when an address where max-size-bytes is specified becomes full.
PAGE
STRING
dead-letter-address
If a dead letter address is specified, messages are moved to the dead letter address if max-delivery-attempts delivery attempts have failed. Otherwise, these undelivered messages are discarded. Wildcards are allowed.
jms.queue.DLQ
STRING
expiry-address
If the expiry address is present, expired messages are sent to the address or addresses matched by it, instead of being discarded. Wildcards are allowed.
jms.queue.ExpiryQueue
STRING
last-value-queue
Defines whether a queue only uses last values or not.
false
BOOLEAN
max-delivery-attempts
The maximum number of times to attempt to re-deliver a message before it is sent to dead-letter-address or discarded.
10
INT
max-delivery-bytes
The maximum bytes size.
10485760L
LONG
message-counter-history-day-limit
Day limit for the message counter history.
10
INT
page-max-cache-size
The number of page files to keep in memory to optimize IO during paging navigation.
5
INT
page-size-bytes
The paging size.
5
INT
redelivery-delay
Time to delay between re-delivery attempts of messages, expressed in milliseconds. If set to 0, re-delivery attempts occur indefinitely.
0L
LONG
redistribution-delay
Defines how long to wait when the last consumer is closed on a queue before redistributing any messages.
-1L
LONG
send-to-dla-on-no-route
A parameter for an address that sets the condition of a message not ruoted to any queues to instead be sent the to the dead letter address (DLA) indicated for that address.
false
BOOLEAN
  • Configure Address Setting and Pattern Attributes

    Choose either the Management CLI or the Management Console to configure your pattern attributes as required.
    • Configure the Address Settings Using the Management CLI

      Use the Management CLI to configure address settings.
      1. Add a New Pattern

        Use the add operation to create a new address setting if required. You can run this command from the root of the Management CLI session, which in the following examples creates a new pattern titled patternname, with a max-delivery-attempts attribute declared as 5. The examples for both Standalone Server and a Managed Domain editing on the full profile are shown.
        [domain@localhost:9999 /] /profile=full/subsystem=messaging/hornetq-server=default/address-setting=patternname/:add(max-delivery-attempts=5)
        [standalone@localhost:9999 /] /subsystem=messaging/hornetq-server=default/address-setting=patternname/:add(max-delivery-attempts=5)
      2. Edit Pattern Attributes

        Use the write operation to write a new value to an attribute. You can use tab completion to help complete the command string as you type, as well as to expose the available attributes. The following example updates the max-delivery-attempts value to 10
        [domain@localhost:9999 /] /profile=full/subsystem=messaging/hornetq-server=default/address-setting=patternname/:write-attribute(name=max-delivery-attempts,value=10)
        [standalone@localhost:9999 /] /subsystem=messaging/hornetq-server=default/address-setting=patternname/:write-attribute(name=max-delivery-attempts,value=10)
      3. Confirm Pattern Attributes

        Confirm the values are changed by running the read-resource operation with the include-runtime=true parameter to expose all current values active in the server model.
        [domain@localhost:9999 /] /profile=full/subsystem=messaging/hornetq-server=default/address-setting=patternname/:read-resource
        [standalone@localhost:9999 /] /subsystem=messaging/hornetq-server=default/address-setting=patternname/:read-resource
    • Configure the Address Settings Using the Management Console

      Use the Management Console to configure address settings.
      1. Log into the Management Console.

        Log into the Management Console of your Managed Domain or Standalone Server.
      2. If you use a Managed Domain, choose the correct profile.

        Select the Profiles tab at the top right, and then select the correct profile from the Profile menu at the top left of the next screen. Only the full and full-ha profiles have the messaging subsystem enabled.
      3. Select the Messaging item from the navigation menu.

        Expand the Messaging menu item from the navigation menu, and click Destinations.
      4. View the JMS Provider.

        A list of JMS Providers is shown. In the default configuration, only one provider, called default, is shown. Click the View link to view the detailed settings for this provider.
      5. View the Address Settings.

        Click the Addressing tab. Either add a new pattern by clicking the Add button, or edit an existing one by clicking its name and clicking the Edit button.
      6. Configure the options.

        If you are adding a new pattern, the Pattern field refers to the match parameter of the address-setting element. You can also edit the Dead Letter Address, Expiry Address, Redelivery Delay, and Max Delivery Attempts. Other options need to be configured using the Management CLI.

14.1.13. Reference for HornetQ Configuration Attributes

The JBoss Enterprise Application Platform 6 implementation of HornetQ exposes the following attributes for configuration. You can use the Management CLI in particular to exposure the configurable or viewable attributes with the read-resource operation.

Example 14.3. Example

[standalone@localhost:9999 /] /subsystem=messaging/hornetq-server=default:read-resource

Table 14.4. TableTitle

Attribute Example Value Type
allow-failback true BOOLEAN
async-connection-execution-enabled true BOOLEAN
backup false BOOLEAN
cluster-password somethingsecure STRING
cluster-user HORNETQ.CLUSTER.ADMIN.USER STRING
clustered false BOOLEAN
connection-ttl-override -1 LONG
create-bindings-dir true BOOLEAN
create-journal-dir true BOOLEAN
failback-delay 5000 LONG
failover-on-shutdown false BOOLEAN
id-cache-size 2000 INT
jmx-domain org.hornetq STRING
jmx-management-enabled false BOOLEAN
journal-buffer-size 100 LONG
journal-buffer-timeout 100 LONG
journal-compact-min-files 10 INT
journal-compact-percentage 30 INT
journal-file-size 102400 LONG
journal-max-io 1 INT
journal-min-files 2 INT
journal-sync-non-transactional true BOOLEAN
journal-sync-transactional true BOOLEAN
journal-type ASYNCIO STRING
live-connector-ref reference STRING
log-journal-write-rate false BOOLEAN
management-address jms.queue.hornetq.management STRING
management-notification-address hornetq.notifications STRING
memory-measure-interval -1 LONG
memory-warning-threshold 25 INT
message-counter-enabled false BOOLEAN
message-counter-max-day-history 10 INT
message-counter-sample-period 10000 LONG
message-expiry-scan-period 30000 LONG
message-expiry-thread-priority 3 INT
page-max-concurrent-io 5 INT
perf-blast-pages -1 INT
persist-delivery-count-before-delivery false BOOLEAN
persist-id-cache true BOOLEAN
persistence-enabled true BOOLEAN
remoting-interceptors undefined LIST
run-sync-speed-test false BOOLEAN
scheduled-thread-pool-max-size 5 INT
security-domain other STRING
security-enabled true BOOLEAN
security-invalidation-interval 10000 LONG
server-dump-interval -1 LONG
shared-store true BOOLEAN
started true BOOLEAN
thread-pool-max-size 30 INT
transaction-timeout 300000 LONG
transaction-timeout-scan-period 1000 LONG
version 2.2.16.Final (HQ_2_2_16_FINAL, 122) STRING
wild-card-routing-enabled true BOOLEAN

14.1.14. Configure Messaging with HornetQ

The recommended method of configuring messaging in JBoss Enterprise Application Platform 6 is in either the Management Console or Management CLI. You can make persistent changes with either of these management tools without needing to manually edit the standalone.xml or domain.xml configuration files. It is useful however to familiarise yourself with the messaging components of the default configuration files, where documentation examples using management tools give configuration file snippets for reference.

14.1.15. Configure Delayed Redelivery

Introduction

Delayed redelivery is defined in the <redelivery-delay> element, which is a child element of the <address-setting> configuration element in the Java Messaging Service (JMS) subsystem configuration.

<!-- delay redelivery of messages for 5s -->
<address-setting match="jms.queue.exampleQueue">
  <redelivery-delay>5000</redelivery-delay>
</address-setting>
If a redelivery delay is specified, the JMS system waits for the duration of this delay before redelivering the messages. If <redelivery-delay> is set to 0, there is no redelivery delay. Address wildcards can be used on the <address-setting-match> element to configure the redelivery delay for addresses which match the wildcard.

14.1.16. Configure Dead Letter Addresses

Introduction

A dead letter address is defined in the <address-setting> element of the Java Messaging Service (JMS) subsystem configuration.

<!-- undelivered messages in exampleQueue will be sent to the dead letter address 
deadLetterQueue after 3 unsuccessful delivery attempts
-->
<address-setting match="jms.queue.exampleQueue">
  <dead-letter-address>jms.queue.deadLetterQueue</dead-letter-address>
  <max-delivery-attempts>3</max-delivery-attempts>
</address-setting>
If a <dead-letter-address> is not specified, messages are removed after trying to deliver <max-delivery-attempts> times. By default, messages delivery is attempted 10 times. Setting <max-delivery-attempts> to -1 allows infinite redelivery attempts. For example, a dead letter can be set globally for a set of matching addresses and you can set <max-delivery-attempts> to -1 for a specific address setting to allow infinite redelivery attempts only for this address. Address wildcards can also be used to configure dead letter settings for a set of addresses.

14.1.17. Configure Message Expiry Addresses

Introduction

Message expiry addresses are defined in the address-setting configuration of the Java Messaging Service (JMS). For example:

<!-- expired messages in exampleQueue will be sent to the expiry address expiryQueue -->
<address-setting match="jms.queue.exampleQueue">
  <expiry-address>jms.queue.expiryQueue</expiry-address>
</address-setting>
If messages are expired and no expiry address is specified, messages are simply removed from the queue and dropped. Address wildcards can also be used to configure specific ranges of an expiry address for a set of addresses.
Address Wildcards

Address wildcards can be used to match multiple similar addresses with a single statement, similar to how many systems use the asterisk (*) character to match multiple files or strings with a single search. The following characters have special significance in a wildcard statement.

Table 14.5. JMS Wildcard Syntax

Character Description
. (a single period) Denotes the space between words in a wildcard expression.
# (a pound or hash symbol) Matches any sequence of zero or more words.
* (an asterisk) Matches a single word.

Table 14.6. JMS Wildcard Examples

Example Description
news.europe.#
Matches news.europe, news.europe.sport, news.europe.politic, but not news.usa or europe.
news.
Matches news.europe but not news.europe.sport.
news.*.sport
Matches news.europe.sport and news.usa.sport, but not news.europe.politics.

14.1.18. Set Message Expiry

Introduction

Using HornetQ Core API, the expiration time can be set directly on the message. For example:

// message will expire in 5000ms from now
message.setExpiration(System.currentTimeMillis() + 5000);
JMS MessageProducer

JMS MessageProducer includes a TimeToLive parameter which controls message expiry for the messages it sends::

// messages sent by this producer will be retained for 5s (5000ms) before expiration           
producer.setTimeToLive(5000);
Expired messages which are consumed from an expiry address have the following properties:
  • _HQ_ORIG_ADDRESS
A string property containing the original address of the expired message.
  • _HQ_ACTUAL_EXPIRY
A long property containing the actual expiration time of the expired message.