ASF classes and functions
WebSphere MQ JMS implements the ConnectionConsumer class and advanced functionality in the Session class. For details, see:
ConnectionConsumer
The JMS specification enables an appserver to integrate closely with a JMS implementation by using the ConnectionConsumer interface. This feature provides concurrent processing of messages. Typically, an appserver creates a pool of threads, and the JMS implementation makes messages available to these threads. A JMS-aware appserver can use this feature to provide high-level messaging functionality, such as message processing beans.
Normal applications do not use the ConnectionConsumer, but expert JMS clients might use it. For such clients, the ConnectionConsumer provides a high-performance method to deliver messages concurrently to a pool of threads. When a message arrives on a queue or a topic, JMS selects a thread from the pool and delivers a batch of messages to it. To do this, JMS runs an associated MessageListener's onMessage() method.
You can achieve the same effect by constructing multiple Session and MessageConsumer objects, each with a registered MessageListener. However, the ConnectionConsumer provides better performance, less use of resources, and greater flexibility. In particular, fewer Session objects are required.
To help you develop applications that use ConnectionConsumers, WebSphere MQ JMS provides a fully-functioning example implementation of a pool. You can use this implementation without any changes, or adapt it to suit the specific needs of the application.
Planning an application
This section tells you how to plan an application including:
- General principles for point-to-point messaging
- General principles for publish/subscribe messaging
- Handling poison messages
- Removing messages from the queue
General principles for point-to-point messaging
When an application creates a ConnectionConsumer from a QueueConnection object, it specifies a JMS queue object and a selector string. The ConnectionConsumer then begins to provide messages to sessions in the associated ServerSessionPool. Messages arrive on the queue, and if they match the selector, they are delivered to sessions in the associated ServerSessionPool.
In WebSphere MQ terms, the queue object refers to either a QLOCAL or a QALIAS on the local queue manager. If it is a QALIAS, that QALIAS must refer to a QLOCAL. The fully-resolved WebSphere MQ QLOCAL is known as the underlying QLOCAL. A ConnectionConsumer is said to be active if it is not closed and its parent QueueConnection is started.
It is possible for multiple ConnectionConsumers, each with different selectors, to run against the same underlying QLOCAL. To maintain performance, unwanted messages must not accumulate on the queue. Unwanted messages are those for which no active ConnectionConsumer has a matching selector. You can set the QueueConnectionFactory so that these unwanted messages are removed from the queue (for details, see Removing messages from the queue). You can set this behavior in one of two ways:
- Use the JMS administration tool to set the QueueConnectionFactory to MRET(NO).
- In your program, use:
MQQueueConnectionFactory.setMessageRetention(JMSC.MQJMS_MRET_NO)If you do not change this setting, the default is to retain such unwanted messages on the queue.
It is possible that ConnectionConsumers that target the same underlying QLOCAL could be created from multiple QueueConnection objects. However, for performance reasons, we recommend that multiple JVMs do not create ConnectionConsumers against the same underlying QLOCAL.
When you set up the WebSphere MQ queue manager, consider the following points:
- The underlying QLOCAL must be enabled for shared input. To do this, use the following MQSC command:
ALTER QLOCAL(your.qlocal.name) SHARE GET(ENABLED)- Your queue manager must have an enabled dead-letter queue. If a ConnectionConsumer experiences a problem when it puts a message on the dead-letter queue, message delivery from the underlying QLOCAL stops. To define a dead-letter queue, use:
ALTER QMGR DEADQ(your.dead.letter.queue.name)- The user that runs the ConnectionConsumer must have authority to perform MQOPEN with MQOO_SAVE_ALL_CONTEXT and MQOO_PASS_ALL_CONTEXT. For details, see the WebSphere MQ documentation for your specific platform.
- If unwanted messages are left on the queue, they degrade the system performance. Therefore, plan your message selectors so that between them, the ConnectionConsumers will remove all messages from the queue.
For details about MQSC commands, see the WebSphere MQ Script (MQSC) Command Reference.
General principles for publish/subscribe messaging
When an application creates a ConnectionConsumer from a TopicConnection object, it specifies a Topic object and a selector string. The ConnectionConsumer then begins to receive messages that match the selector on that Topic.
Alternatively, an application can create a durable ConnectionConsumer that is associated with a specific name. This ConnectionConsumer receives messages that have been published on the Topic since the durable ConnectionConsumer was last active. It receives all such messages that match the selector on the Topic.
For non-durable subscriptions, a separate queue is used for ConnectionConsumer subscriptions. The CCSUB configurable option on the TopicConnectionFactory specifies the queue to use. Normally, the CCSUB specifies a single queue for use by all ConnectionConsumers that use the same TopicConnectionFactory. However, it is possible to make each ConnectionConsumer generate a temporary queue by specifying a queue name prefix followed by a *.
For durable subscriptions, the CCDSUB property of the Topic specifies the queue to use. Again, this can be a queue that already exists or a queue name prefix followed by a *. If you specify a queue that already exists, all durable ConnectionConsumers that subscribe to the Topic use this queue. If you specify a queue name prefix followed by a *, a queue is generated the first time that a durable ConnectionConsumer is created with a given name. This queue is reused later when a durable ConnectionConsumer is created with the same name.
When you set up the WebSphere MQ queue manager, consider the following points:
- Your queue manager must have an enabled dead-letter queue. If a ConnectionConsumer experiences a problem when it puts a message on the dead-letter queue, message delivery from the underlying QLOCAL stops. To define a dead-letter queue, use:
ALTER QMGR DEADQ(your.dead.letter.queue.name)- The user that runs the ConnectionConsumer must have authority to perform MQOPEN with MQOO_SAVE_ALL_CONTEXT and MQOO_PASS_ALL_CONTEXT. For details, see the WebSphere MQ documentation for your platform.
- You can optimize performance for an individual ConnectionConsumer by creating a separate, dedicated, queue for it. This is at the cost of extra resource usage.
Handling poison messages
Sometimes, a badly-formatted message arrives on a queue. Such a message might make the receiving application fail and back out the receipt of the message. In this situation, such a message might be received, then returned to the queue, repeatedly. These messages are known as poison messages. The ConnectionConsumer must be able to detect poison messages and reroute them to an alternative destination.
When an application uses ConnectionConsumers, the circumstances in which a message is backed out depend on the session that the appserver provides:
- When the session is non-transacted, with AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE, a message is backed out only after a system error, or if the application terminates unexpectedly.
- When the session is non-transacted with CLIENT_ACKNOWLEDGE, unacknowledged messages can be backed out by the appserver calling Session.recover().
Typically, the client implementation of MessageListener or the application server calls Message.acknowledge(). Message.acknowledge() acknowledges all messages delivered on the session so far.
- When the session is transacted, the appserver usually commits the session. If the appserver detects an error, it may choose to back out one or more messages.
- If the appserver supplies an XASession, messages are committed or backed out depending on a distributed transaction. The application server takes responsibility for completing the transaction.
The WebSphere MQ queue manager keeps a record of the number of times that each message has been backed out. When this number reaches a configurable threshold, the ConnectionConsumer requeues the message on a named backout queue. If this requeue fails for any reason, the message is removed from the queue and either requeued to the dead-letter queue, or discarded. See Removing messages from the queue for more details.
On most platforms, the threshold and requeue queue are properties of the WebSphere MQ QLOCAL. For point-to-point messaging, this is the underlying QLOCAL. For publish/subscribe messaging, this is the CCSUB queue defined on the TopicConnectionFactory, or the CCDSUB queue defined on the Topic. To set the threshold and requeue queue properties, issue the following MQSC command:
ALTER QLOCAL(your.queue.name) BOTHRESH(threshold) BOQUEUE(your.requeue.queue.name)For publish/subscribe messaging, if your system creates a dynamic queue for each subscription, these settings are obtained from the WebSphere MQ JMS model queue. To alter these settings, you can use:
ALTER QMODEL(SYSTEM.JMS.MODEL.QUEUE) BOTHRESH(threshold) BOQUEUE(your.requeue.queue.name)If the threshold is zero, poison message handling is disabled, and poison messages remain on the input queue. Otherwise, when the backout count reaches the threshold, the message is sent to the named requeue queue. If the backout count reaches the threshold, but the message cannot go to the requeue queue, the message is sent to the dead-letter queue or discarded. This situation occurs if the requeue queue is not defined, or if the ConnectionConsumer cannot send the message to the requeue queue. On some platforms, you cannot specify the threshold and requeue queue properties. On these platforms, messages are sent to the dead-letter queue, or discarded, when the backout count reaches 20. See Removing messages from the queue for further details.
Removing messages from the queue
When an application uses ConnectionConsumers, JMS might need to remove messages from the queue in a number of situations:
- Badly formatted message
- A message might arrive that JMS cannot parse.
- Poison message
- A message might reach the backout threshold, but the ConnectionConsumer fails to requeue it on the backout queue.
- No interested ConnectionConsumer
- For point-to-point messaging, when the QueueConnectionFactory is set so that it does not retain unwanted messages, a message arrives that is unwanted by any of the ConnectionConsumers.
In these situations, the ConnectionConsumer attempts to remove the message from the queue. The disposition options in the report field of the message's MQMD set the exact behavior. These options are:
- MQRO_DEAD_LETTER_Q
- The message is requeued to the queue manager's dead-letter queue. This is the default.
- MQRO_DISCARD_MSG
- The message is discarded.
The ConnectionConsumer also generates a report message, and this also depends on the report field of the message's MQMD. This message is sent to the message's ReplyToQ on the ReplyToQmgr. If there is an error while the report message is being sent, the message is sent to the dead-letter queue instead. The exception report options in the report field of the message's MQMD set details of the report message. These options are:
- MQRO_EXCEPTION
- A report message is generated that contains the MQMD of the original message. It does not contain any message body data.
- MQRO_EXCEPTION_WITH_DATA
- A report message is generated that contains the MQMD, any MQ headers, and 100 bytes of body data.
- MQRO_EXCEPTION_WITH_FULL_DATA
- A report message is generated that contains all data from the original message.
- default
- No report message is generated.
When report messages are generated, the following options are honored:
- MQRO_NEW_MSG_ID
- MQRO_PASS_MSG_ID
- MQRO_COPY_MSG_ID_TO_CORREL_ID
- MQRO_PASS_CORREL_ID
If a ConnectionConsumer cannot follow the disposition options or exception report options in the message's MQMD, its action depends on the persistence of the message. If the message is non-persistent, the message is discarded and no report message is generated. If the message is persistent, delivery of all messages from the QLOCAL stops.
It is important to define a dead-letter queue, and to check it regularly to ensure that no problems occur. Particularly, ensure that the dead-letter queue does not reach its maximum depth, and that its maximum message size is large enough for all messages.
When a message is requeued to the dead-letter queue, it is preceded by a WebSphere MQ dead-letter header (MQDLH). See the WebSphere MQ Application Programming Reference for details about the format of the MQDLH. You can identify messages that a ConnectionConsumer has placed on the dead-letter queue, or report messages that a ConnectionConsumer has generated, by the following fields:
- PutApplType is MQAT_JAVA (0x1C)
- PutApplName is "MQ JMS ConnectionConsumer"
These fields are in the MQDLH of messages on the dead-letter queue, and the MQMD of report messages. The feedback field of the MQMD, and the Reason field of the MQDLH, contain a code describing the error. For details about these codes, see Error handling. Other fields are as described in the WebSphere MQ Application Programming Reference.
Error handling
This section covers various aspects of error handling, including Recovering from error conditions and Reason and feedback codes.
Recovering from error conditions
If a ConnectionConsumer experiences a serious error, message delivery to all ConnectionConsumers with an interest in the same QLOCAL stops. Typically, this occurs if the ConnectionConsumer cannot requeue a message to the dead-letter queue, or it experiences an error when reading messages from the QLOCAL.
When this occurs, any ExceptionListener that is registered with the affected Connection is notified.
You can use these to identify the cause of the problem. In some cases, the system administrator must intervene to resolve the problem.
There are two ways in which an application can recover from these error conditions:
- Call close() on all affected ConnectionConsumers. The application can create new ConnectionConsumers only after all affected ConnectionConsumers are closed and any system problems are resolved.
- Call stop() on all affected Connections. Once all Connections are stopped and any system problems are resolved, the application should be able to start() all Connections successfully.
Reason and feedback codes
To determine the cause of an error, you can use:
- The feedback code in any report messages
- The reason code in the MQDLH of any messages in the dead-letter queue
ConnectionConsumers generate the following reason codes.
- MQRC_BACKOUT_THRESHOLD_REACHED (0x93A; 2362)
- Cause
- The message has reached the Backout Threshold defined on the QLOCAL, but no Backout Queue is defined.
On platforms where you cannot define the Backout Queue, the message has reached the JMS-defined backout threshold of 20.
- Action
- If this is not wanted, define the Backout Queue for the relevant QLOCAL. Also look for the cause of the multiple backouts.
- MQRC_MSG_NOT_MATCHED (0x93B; 2363)
- Cause
- In point-to-point messaging, there is a message that does not match any of the selectors for the ConnectionConsumers monitoring the queue. To maintain performance, the message is requeued to the dead-letter queue.
- Action
- To avoid this situation, ensure that ConnectionConsumers using the queue provide a set of selectors that deal with all messages, or set the QueueConnectionFactory to retain messages.
Alternatively, investigate the source of the message.
- MQRC_JMS_FORMAT_ERROR (0x93C; 2364)
- Cause
- JMS cannot interpret the message on the queue.
- Action
- Investigate the origin of the message. JMS usually delivers messages of an unexpected format as a BytesMessage or TextMessage. Occasionally, this fails if the message is very badly formatted.
Other codes that appear in these fields are caused by a failed attempt to requeue the message to a Backout Queue. In this situation, the code describes the reason that the requeue failed. To diagnose the cause of these errors, refer to the WebSphere MQ Application Programming Reference.
If the report message cannot be put on the ReplyToQ, it is put on the dead-letter queue. In this situation, the feedback field of the MQMD is filled in as described above. The reason field in the MQDLH explains why the report message could not be placed on the ReplyToQ.
WebSphere is a trademark of the IBM Corporation in the United States, other countries, or both.
IBM is a trademark of the IBM Corporation in the United States, other countries, or both.