JMS Details

This section provides a more detailed description of JMS. In particular, we explore the acknowledgement modes, which are fundamental to understanding the reliability aspects of a JMS provider. Also, this section covers message producers and consumers, as well as the details of exception listeners and message selectors.

As described previously, the Pub/Sub and P2P models have a lot in common, and unless otherwise noted, the information described in this section applies to both models. The only major differences between the two models in terms of the JMS API's is that the P2P model supports a queue browser and the Pub/Sub models support durable subscribers.

Acknowledgement Modes

Message acknowledgement is purely a consumer side concept, which relates to how a consumer tells the JMS provider that is has received a messages. On the producer side, the only notion of acknowledgement consists of a successful invocation of either the topic publisher's publish method or the queue sender's send method.

Acknowledgment of a message means that the JMS provider must never deliver the message to the consumer in question again. This also means that the JMS provider can release any resources it is occupying on behalf of said message. To minimize resource consumption, consumer applications should therefore acknowledge messages as quickly as possible.

JMS support a number of message acknowledgement modes:

Duplicates Allowed

Consumer applications specify this acknowledge mode using the DUPS_OK_ACKNOWLEDGE constant defined in the Session interface. Using this mode, the session acknowledges message lazily, which provides faster message processing, with the penalty that some duplicate messages may be delivered multiple times if JMS fails. Only applications that are tolerant to message duplicates should use this acknowledge mode.

Auto acknowledge

This is the default acknowledge mode, which is specified using the AUTO_ACKNOWLEDGE constant defined in the Session interface. For each message, the session automatically acknowledges that a client has received a message either:

If a JMS provider or the message consumer crashes while it is processing a message, this message is subject to either re-delivery or loss when using the automatic acknowledgement mode.

With synchronous receive, the message will be lost of JMS acknowledges it but crashes before receive returns the message to the consumer. With an asynchronous message listener, a duplicate will happen if JMS crashes after onMessage completed but before the acknowledgement was recorded.

Note that these situations are not limitations of a JMS implementation but the nature of doing automatic acknowledgements in a distributed system. The only way to prevent this is by maintaining persistent state in the client, or by using a distributed transaction.

Client acknowledge

Consumer applications specify this acknowledge mode using the CLIENT_ACKNOWLEDGE constant defined in the Session interface. This acknowledgement mode gives consumer more control over when messages are acknowledged. A consumer can group a number of messages and then invoke the acknowledge method of the Message to instruct the JMS provider that the message (and all other messages received up until this point) have been consumed.

When a consumer uses client acknowledge, it can use the recover method of the session to revert back to its last check point. This causes the session to re-deliver all messages that have not yet been acknowledged by the consumer. Note that if a client crashes and later re-connects to its queue or topic, the session will effectively be recovered and the consumer will receive all un-acknowledged messages.

Transactional Acknowledge

The session finally supports a different kinds of acknowledgement mode, which is referred to as a transacted session. A transacted session is a related group of consumed and produced messages that are treated as a single work unit. A transaction can be either committed or rolled back.

When the session's commit method is called, the consumed messages are acknowledged, and the associated produced messages are sent. When a session's rollback method is called, the produced messages are destroyed, and the consumed messages are recovered.

A transacted session always has a "current" transaction and applications do not explicitly start one. As soon as either the commit or rollback method is called, the current transaction ends and a new transaction is immediately started. These method can only be called on a transacted session.

The graph below illustrates a transacted session as using a "bucket" for holding on to messages and acknowledgements. The MSG's and ACK's are flushed when the commit orrollback method is called.

A typical use of transacted sessions is to consume and produce a message atomically. If an application moves messages from one destination to another, it should use a transacted session to ensure that the message is either successfully transferred, or not transferred at all. In this case, the commit method should be called after each message.

Message Producers

Message producers send or publish messages to a destination. The QueueSender and TopicPublisher interfaces support several variations of either a send or publish method for sending messages.

The producer application creates the message and is required to set the various properties of the message. If these properties are not specified in the send or publish method, JMS will assign what has been set as the default value for the queue sender or topic publisher:

Once the invocation of the send or publish method returns successfully, JMS has received the message. For persistent messages this means that the message has successfully been written into some persistent store and is guaranteed not to be lost until the recipient has acknowledged it.

Message Consumers

A message consumer receives messages from a destination. The QueueReceiver and TopicSubscriber interfaces both extends the MessageConsumer, which support two way of receiving messages:

Synchronously

The client calls one of the receive methods defined in the MessageConsumer interface:

Note that before a consumer application can start to receive messages, it must call the start method on the Connection object. The start method is a signal to the JMS provider to start the flow on messages to all sessions created by the connection in question.

Asynchronously

The client registers a MessageListener with the MessageConsumer using its setMessageListener method. Note that the asynchronous and synchronous models can not be mixed and it is not allowed to call the receive methods on a consumer with a message listener.

A message listener is simply an object, which implements the onMessage method. This method has a single argument, which is a JMS message. A message listener is not allowed to raise any exceptions and a consumer application should always try to catch any exceptions and deal with them.

Ordinarily, the JMS provider will resolve connection problems. If an error occurs, the provider normally raises an exception when an application tries to send or receive a message. However, when using a message listener this is not possible because the consumer waits for the provider to invoke it.

Therefore, JMS support an interface called an ExceptionListener which is used to communicate exceptions to clients. The exception listener is primarily available to support asynchronous communication, but is is in general recommended that client application use it.

The exception listener is set using the setExceptionListener method on the Connection object. As opposed to a regular message listener, the exception listener is set once per connection instead of once per consumer. By default a connection does not have an exception listener.

So far, the discussion has covered both the P2P and Pub/Sub messaging models. However, both P2P and Pub/Sub support special kinds of message receivers. The P2P model support a queue browser and Pub/Sub support a durable subscriber.

Queue Browser

A queue browser is a special consumer that can retrieve but not consume messages. A queue browser supports the QueueBrowser interface, which has methods for looking at queue messages without actually removing them from the queue.

The QueueBrowser interface provides a familiar Enumeration which elements are messages. The order of messages in the enumeration corresponds to the order in which a regular queue receiver would receive them (subject to message expiry and arrival of new, high-priority messages).

Durable Subscriber

A durable subscriber is used to receive persistent topic messages. Since regular, transient topic subscribers do not survive crashes of either the JMS provider or the subscriber itself, the JMS provider will typically not persist topic messages when the topic only has transient subscribers.

The above is a consequence of the fact that a topic does not retain messages when there are no subscribers. In Pub/Sub messaging, subscribers will only get messages that were received by the topic after the subscription was made. Therefore, there can be no concept of persistent messages if connections can not survive a crash.

A durable subscriber can survive crashes, and the subscription is not lost until it is explicitly un-subscribed. If a durable subscriber is temporarily unavailable, the JMS provider will buffer messages on it behalf. When the subscriber comes back and re-connects, it will receive all buffered messages.

Durable subscribers require a connection client identifier. This identifier is part of the subscription name and must be set using the setClientID method on the Connection. As with an exception listener, this is set once per connection and the client identifier will apply to all durable subscribers within said connection.

Message Selectors

A message selector is an object invoked by the JMS provider to restrict messages from being delivered unless they meet certain specified criteria. Message selectors examine the message header fields and properties and then compare them to a context string that has been specified by the consumer.

The context string used by the message selector is built from syntax based on a subset of SQL92 conditional expression syntax. If you are familiar with JDBC, you essentially query as if the message properties where column names. The following table describes some common values. For a complete list, please refer to the JMS specification.

Value Examples
Comparison operators Amount <= 5
Month = 'January'
Logical operators JMSPriority > 3 AND Value = 42
Width = 2 OR Height > 3
Level < 4 AND NOT Error
Arithmetic operators Amount * 22.3 + Tax / 1.45 < 4220.12
-Value * 9 < 12
SQL operators Amount BETWEEN 12 AND 22
Quote IN ('SSSW','CSCO','MSFT')
Property IS NULL
Number LIKE '12%3'
Word LIKE 'hel_o'

Un-selected message in the P2P model are retained on the queue so that if one consumer does not select a message, the JMS provider will attempt to re-assign it to another consumer (or keep it on the queue for some future consumer).

In the Pub/Sub model, un-selected message are discarded and from a subscriber's point of view, it will be as if the messages was never sent to the topic. The message may be selected by other subscribers of the topic.



Copyright © 2003, 2004 Novell, Inc. All rights reserved. Copyright © 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved.