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.
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:
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.
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:
Just before the call to a message consumer's receive
or
receiveNoWait
return a message.
Right after the onMessage
method returns successfully
after invoking the consumer's
MessageListener.
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.
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.
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 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:
The destination of the message. In P2P this is a queue and in Pub/Sub it's a topic.
The message delivery mode. JMS support persistent and non-persistent message delivery modes, with persistent being the default.
The message priority. JMS guarantees FIFO order for messages of the same priority but will attempt to expedite messages of higher priority.
The expiry of the message. This is also referred to a time-to-live (TTL) for the message. Expired messages are not delivered to consumers.
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.
A message consumer receives messages from a destination. The QueueReceiver and TopicSubscriber interfaces both extends the MessageConsumer, which support two way of receiving messages:
The client calls one of the receive methods defined in the MessageConsumer interface:
receive
- This method can be called with out without a
timeout. The consumer block either indefinitely or for the specified
amount of time to retrieve a message. If a message was not available
on the destination before the timeout expired, null is returned.
receiveNoWait
- This method checks for a message and returns
immediately with either null or a message if one is available on the
destination to which to consumer is registered.
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.
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.
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).
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.
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.