Receiving a message

An application receives messages using a MessageConsumer object. The application creates a MessageConsumer object by using the createConsumer() method on a Session object. This method has a destination parameter that defines where the messages are received from. See Destinations for details of how to create a destination, which is either a Queue or a Topic object.

In the point-to-point domain, the following code creates a MessageConsumer object and then uses the object to receive a message:

MessageConsumer messageConsumer = session.createConsumer(ioQueue);
Message inMessage = messageConsumer.receive(1000);

The parameter on the receive() call is a timeout in milliseconds. This parameter defines how long the method must wait if no message is available immediately. You can omit this parameter; in which case, the call blocks until a suitable message arrives. If you do not want any delay, use the receiveNoWait() method.

The receive() methods return a message of the appropriate type. For example, suppose a text message is put on a queue. When the message is received, the object that is returned is an instance of TextMessage.

To extract the content from the body of the message, it is necessary to cast from the generic Message class (which is the declared return type of the receive() methods) to the more specific subclass, such as TextMessage. If the received message type is not known, you can use the instanceof operator to determine which type it is. It is good practice always to test the message class before casting so that unexpected errors can be handled gracefully.

The following code uses the instanceof operator and shows how to extract the content of a text message:

if (inMessage instanceof TextMessage) {
  String replyString = ((TextMessage) inMessage).getText();
  .
  .
  .
} else {
  // Print error message if Message was not a TextMessage.
  System.out.println("Reply message was not a TextMessage");
}

JMS provides two types of message consumer:

Nondurable message consumer
A nondurable message consumer receives messages from its chosen destination only if the messages are available while the consumer is active.

In the point-to-point domain, whether a consumer receives messages that are sent while the consumer is inactive depends on how WebSphere MQ is configured to support that consumer. In the publish/subscribe domain, a consumer does not receive messages that are sent while the consumer is inactive.

Durable topic subscriber
A durable topic subscriber receives all the messages sent to a destination, including those sent while the consumer is inactive.

The following sections describe how to create a durable topic subscriber, and how to configure WebSphere MQ and the broker to support either type of message consumer.

Creating durable topic subscribers

You cannot create a durable topic subscriber if the transport type is direct.

Durable topic subscribers are used when an application needs to receive messages that are published even while the application is inactive. Creating a durable topic subscriber is similar to creating a nondurable message consumer, but you must also provide a name that identifies the durable subscription, as in the following example:

// Create a durable subscriber, supplying a uniquely-identifying name
TopicSubscriber sub = session.createDurableSubscriber( topic, "D_SUB_000001" );

The session used to create a durable topic subscriber must have an associated client identifier. The name that identifies a durable subscription must be unique only within the client identifier, and therefore the client identifier forms part of the full, unique identifier of the durable subscription. To reuse a durable subscription that was created previously, an application must create a durable topic subscriber using a session with the same client identifier as that associated with the durable subscription.

The client identifier associated with a session is the same as that associated with the connection that is used to create the session. The client identifier can be specified by setting the CLIENTID property of the ConnectionFactory object. Alternatively, an application can specify the client identifier by calling the setClientID() method of the Connection object. For more information about client identifiers and their relationship with durable topic subscribers and durable subscriptions, see the Java(TM) Message Service Specification, Version 1.1.

A durable topic subscriber is created for the queue manager specified by the QMANAGER property of the ConnectionFactory object. If there is a subsequent attempt to create a durable topic subscriber with the same name for a different queue manager, a new and completely independent durable topic subscriber is returned.

Nondurable message consumers in the publish/subscribe domain automatically deregister themselves when their close() method is called, or when they fall out of scope. However, if you want to terminate a durable subscription, you must explicitly notify the broker. To do this, use the unsubscribe() method of the session and pass in the name that identifies the durable subscription:

// Unsubscribe the durable subscriber created above
session.unsubscribe( "D_SUB_000001" );

Message selectors

JMS allows an application to specify that only messages that satisfy certain criteria are returned by successive receive() calls. When creating a MessageConsumer object, you can provide a string that contains an SQL (Structured Query Language) expression, which determines which messages are retrieved. This SQL expression is called a selector. The selector can refer to fields in the JMS message header as well as fields in the message properties (these are effectively application defined header fields). Details of the header field names, as well as the syntax for an SQL selector, are in JMS messages.

The following example shows how to select messages based on a user defined property called myProp:

messageConsumer = session.createConsumer(ioQueue, "myProp = 'blue'");
Note:
The JMS specification does not permit the selector associated with a message consumer to be changed. After a message consumer is created, the selector is fixed for the lifetime of that consumer. This means that, if you require different selectors, you must create new message consumers.

In the publish/subscribe domain, you can control whether the JMS client or the broker performs message filtering by setting the MSGSELECTION property on the ConnectionFactory object. If the broker is capable of performing message selection, it is generally preferable to let the broker do it because it reduces the amount of work done by the client. However, if the broker is very heavily loaded, it might be preferable to let the client perform message selection instead.

Suppressing local publications

You can create a message consumer that ignores publications published on the consumer's own connection. To do this, set the third parameter on the createConsumer() call to true, as shown in the following example:

// Create a nondurable message consumer with the noLocal option set
MessageConsumer con = session.createConsumer( topic, null, true );

The example that follows shows how to create a durable topic subscriber that applies a selector and ignores local publications:

// Create a durable, noLocal subscriber with a selector applied
String selector = "company = 'IBM'";
TopicSubscriber sub = session.createDurableSubscriber( topic, "D_SUB_000001",
                                                      selector, true );

Configuring the consumer queue

You cannot configure a consumer queue if the transport type is direct.

In the publish/subscribe messaging domain, you can configure message consumers in two ways:

You can choose which approach to use, and configure which queues to use.

In general, there is a modest performance advantage if you use the shared queue approach. For systems with a high throughput, there are also large system management and administrative advantages because of the significant reduction in the number of queues required.

In some situations, however, there are good reasons for using the multiple queue approach:

Default configuration

The default WebSphere MQ JMS configuration for the publish/subscribe domain uses the following shared consumer queues:

These are created for you when you run the MQJMS_PSQ.MQSC script.

If required, you can specify alternative WebSphere MQ queues. You can also change the configuration to use the multiple queue approach.

Configuring nondurable message consumers

You can specify the name of the consumer queue for nondurable message consumers in either of the following ways:

The queue name you provide must start with the following characters:

To use the shared queue approach, specify the complete name of the shared queue. The queue must exist before you can create a subscription.

To use the multiple queue approach, specify a queue name that ends with an asterisk (*). Subsequently, when an application creates a nondurable message consumer specifying this queue name, WebSphere MQ JMS creates a temporary dynamic queue for exclusive use by that consumer. With the multiple queue approach, therefore, all the required queues are created dynamically.

If you use the multiple queue approach, you cannot specify the complete name of a queue, only a prefix. This allows you to create different domains of consumer queues. For example, you can use:

The characters that precede the asterisk (*) are used as the prefix, so that all dynamic queues for nondurable message consumers specifying this prefix have queue names that start with SYSTEM.JMS.ND.MYDOMAIN.

Configuring durable topic subscribers

As stated previously, there might still be good reasons to use the multiple queue approach for durable topic subscribers. Durable topic subscribers are likely to have a longer life span, and so it is possible for a large number of messages for a durable subscriber to accumulate on a queue.

The name of the consumer queue for a durable topic subscriber is a property of a Topic object. This allows you to specify a number of different consumer queue names without having to create multiple objects starting from a ConnectionFactory object.

You can specify the name of the consumer queue for durable topic subscribers in either of the following ways:

The queue name you provide must start with the following characters:

To use the shared queue approach, specify the complete name of the shared queue. The queue must exist before you can create a subscription.

To use the multiple queue approach, specify a queue name that ends with an asterisk (*). Subsequently, when an application creates a durable topic subscriber specifying this queue name, WebSphere MQ JMS creates a permanent dynamic queue for exclusive use by that subscriber. With the multiple queue approach, therefore, all the required queues are created dynamically.

Here is an example of using the multiple queue approach:

// Set the MQTopic durable subscriber queue name using
// the multi-queue approach
sportsTopic.setBrokerDurSubQueue("SYSTEM.JMS.D.FOOTBALL.*");

After the Topic object is initialized, it can be passed into the createDurableSubscriber() method of a Session object to create a durable topic subscriber:

// Create a durable subscriber using our earlier Topic
TopicSubscriber sub = session.createDurableSubscriber(sportsTopic,
                                                      "D_SUB_SPORT_001");

If you use the multiple queue approach, you cannot specify the complete name of a queue, only a prefix. This allows you to create different domains of consumer queues. For example, you can use:

The characters that precede the asterisk (*) are used as the prefix, so that all dynamic queues for durable topic subscribers specifying this prefix have queue names that start with SYSTEM.JMS.D.MYDOMAIN.

You cannot change the consumer queue of a durable topic subscriber. If, for example, you want to move from the multiple queue approach to the single queue approach, you must first delete the old subscriber using the unsubscribe() method and then create a new subscriber. Deleting the old subscriber also deletes any unconsumed messages for that subscriber.

Subscription stores

A subscription store is not used if the transport type is direct.

When an application creates a message consumer in the publish/subscribe domain, information about the subscription is created at the same time. WebSphere MQ JMS maintains a persistent store of subscription information called a subscription store. A subscription store is used to reopen durable topic subscribers and to clean up after a nondurable message consumer fails. A subscription store can be managed by the local queue manager or by the publish/subscribe broker.

The SUBSTORE property of a ConnectionFactory object determines the location of a subscription store. SUBSTORE has three possible values:

SUBSTORE(QUEUE)
Subscription information is stored in the queues, SYSTEM.JMS.ADMIN.QUEUE and SYSTEM.JMS.PS.STATUS.QUEUE, on the local queue manager.

WebSphere MQ JMS maintains an extra connection to each queue manager used by subscribers. Each connection is used by a long running transaction that detects when a subscriber loses its connection to the queue manager and cleans up after the subscriber. In a busy system, a long running transaction might cause the queue manager log to fill up resulting in errors from both the queue manager and the applications connected to it.

If you experience these problems, your system administrator can add extra log files or data sets to the queue manager. Alternatively, you can reduce the value of the STATREFRESHINT property of the ConnectionFactory object. This causes the long running transaction to be refreshed more frequently, allowing the queue manager log to reset itself before it becomes full.

After a nondurable message consumer fails, the following occurs:

This option is provided for compatibility with versions of MQSeries JMS.

SUBSTORE(BROKER)
Subscription information is stored by the publish/subscribe broker used by the application, not in WebSphere MQ queues. This means that, if a JMS client fails, the broker can clean up the resources associated with the JMS client without having to wait for the JMS client to reconnect.

If a nondurable message consumer fails, the subscription is de-registered from the broker as soon as possible. In response to the de-registration, the broker puts a report message on the queue, SYSTEM.JMS.REPORT.QUEUE. This message is used to clean up after the failed consumer.

If you use this option, a separate cleanup thread is run in the background. By default, the cleanup utility runs once every 10 minutes, but you can change this interval by setting the CLEANUPINT property of the ConnectionFactory object. To customize the actions performed by the cleanup utility, use the CLEANUP property of the ConnectionFactory object. For more information about how the cleanup utility works, see Consumer cleanup utility for the publish/subscribe domain.

SUBSTORE(MIGRATE)
This is the default value.

This option dynamically selects a queue based or a broker based subscription store depending on the release levels of WebSphere MQ and the publish/subscribe broker that are installed. If both WebSphere MQ and the broker are capable of supporting the SUBSTORE(BROKER) option, this option behaves like the SUBSTORE(BROKER) option; otherwise, it behaves like the SUBSTORE(QUEUE) option.

If this option behaves like the SUBSTORE(BROKER) option, the option additionally migrates durable subscription information from the queue based subscription store to the broker based store. This migration occurs the first time a durable subscription is opened when both WebSphere MQ and the broker are capable of supporting a broker based subscription store. Only information related to the subscription being opened is migrated. Information related to other subscriptions is left in the queue based subscription store. This option therefore provides an easy migration path from older versions of WebSphere MQ JMS, WebSphere MQ, and the publish/subscribe broker.

Migration and coexistence considerations

Except when the SUBSTORE(MIGRATE) option is used, a queue based subscription store and a broker based subscription store are entirely independent.

A durable subscription is created in the subscription store specified by the ConnectionFactory object. If there is a subsequent attempt to create a durable subscription with the same name and ClientID, but with the other subscription store, a new durable subscription is created.

When a connection uses the SUBSTORE(MIGRATE) option, subscription information is automatically migrated from the queue based subscription store to the broker based subscription store when the application calls the createDurableSubscriber() method. If a durable subscription with a matching name and ClientID already exists in the broker based subscription store, the migration cannot complete and an exception is thrown by the createDurableSubscriber() call.

After a subscription is migrated, it is important not to access the subscription from an application using an older version of WebSphere MQ JMS, or from an application running with the SUBSTORE(QUEUE) option. Doing either of these creates a subscription in the queue based subscription store and prevents an application running with the SUBSTORE(MIGRATE) option from using the subscription.

To recover from this situation if it occurs, run your application with the SUBSTORE(BROKER) option, or unsubscribe from the subscription that is held in the queue based subscription store.