Additional JMS Features

The following sections cover some additional features available in JMS. Not all the features of JMS are covered, and you should refer to the JMS API specification for more information.

Message Selectors

The JMS API provides support for filtering received messages. This is accomplished by using a message selector. The createConsumer() and the createDurableSubscriber() methods have variants that allow a message selector to be specified.

The message selector is a string containing an SQL-like conditional expression. Only message header values and properties can be specified in the message selector. It is not possible to filter messages based on the contents of the message body.

String highPriority = "JMSPriority = '9' AND topic = 'Java'";
subscriber = session.createConsumer(bulletinBoard, highPriority, false);

This selector will ensure that only priority nine messages are received. Note here that topic is a property of the message that has been created and set by the sender.

Notice that for this form of the createConsumer the parameters are as follows:

TopicSession.createConsumer(destination, messageSelector, noLocal);

You need to set the boolean noLocal parameter to specify whether you want to receive messages created by your own connection. Set noLocal to false to prevent the delivery of messages created by the producer's own connection.

Session Acknowledgement Modes

In most of the examples given so far, auto acknowledgement has been used to send the acknowledgement automatically as soon as the message is received. This has the advantage of removing the burden of acknowledging messages from you, but it has the disadvantage that if your application fails before the message is processed, the message may be lost. After a message is acknowledged, the JMS provider will never redeliver it.

Deferring acknowledgement until after you have processed the message will protect against loss of data. To do this, the session must be created with client acknowledgement.

connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

Now when the message is received, no acknowledgement will be sent automatically. It is up to you to ensure that the message is acknowledged at some later point.

message = (TextMessage) consumer.receive();
// process the message
message.acknowledge();

If you do not acknowledge the message, it may be resent.

A third acknowledgement mode, DUPS_OK_ACKNOWLEDGE, can be used when the delivery of duplicates can be tolerated. This form of AUTO_ACKNOWLEDGE has the advantage of reducing the session overhead spent preventing the delivery of duplicate messages.

Message Persistence

The default JMS delivery mode for a message is PERSISTENT. This ensures that the message will be delivered, even if the JMS provider fails or is shut down.

A second delivery mode, NON_PERSISTENT, can be used where guaranteed delivery is not required. A NON_PERSISTENT message has the lowest overhead because the JMS provider does not need to copy the message to a stable storage medium. JMS still guarantees to deliver a NON_PERSISTENT message at most once (but maybe not at all). Nonpersistent messages should be used when:

  • Performance is important and reliability is not

  • Messages can be lost with no effect on system functionality

Persistent and non-persistent messages can be delivered to the same destination.

Transactions

Often, acknowledgement of single messages is not enough to ensure the integrity of an application. Think of the classic banking system example where two messages are sent to debit an amount from one account and credit the same amount to another. If only one of the messages is received, there will be a problem. A transaction is required where a number of operations involving many messages forms an atomic piece of work.

In JMS, you can specify that a session is transacted when it is created:

createSession(boolean transacted, int acknowledgeMode);

In a transacted session, several sends and receives can be grouped together in a single transaction. The JMS API provides Session.commit() to acknowledge all the messages in a transaction and Session.rollback() to discard all messages. After a rollback, any messages received during the transaction will be redelivered unless they have expired.

To create a transacted session, set the transacted parameter to true, as shown in the following:

session = connection.createSession(true, 0);

For transacted sessions, the acknowledgeMode parameter is ignored. The previous code sets this parameter to 0 to make this fact explicit.

There is no explicit transaction start. The contents of a transaction are simply those messages that have been produced and consumed during the current session, either since the session was created or since the last commit(). After a commit() or rollback(), a new transaction is started.

NOTE

Because the commit() and rollback() methods are associated with a session, it is not possible to mix messages from queues and topics in the same transaction.


The following example shows a simple transaction involving two messages.

Session session = connection.createSession(true, 0);
Destination bank1Queue = (Queue)context.lookup("queue/bank1");
Destination bank2Queue = (Queue)context.lookup("queue/bank2");
MessageProducer bank1Sender = session.createProducer(bank1Queue);
MessageProducer bank2Sender = session.createProducer(bank2Queue);
// .. application processing to create debit and credit messages
try {
    bank1Sender.send(bank1Queue, debitMsg);
    bank2Sender.send(bank2Queue, creditMsg);
    session.commit();
} catch(JMSException ex) {
    System.err.println("Exception in bank transaction:" + ex);
    session.rollback();
}

Where a receiver handles atomic actions sent in multiple messages, it should similarly only commit when all the messages have been received and processed.

A JMS provider may provide support for distributed transaction using the X/Open XA resource interface. This is performed by utilizing the Java Transaction API (JTA). JTA was covered on Day 8, “Transactions and Persistence.” XA support is optional; refer to your JMS provider documentation to see if XA support is provided.

Multithreading

Not all the objects in JMS support concurrent use. The JMS API only specifies the following objects can be shared across multiple threads

  • Connection Factories

  • Connections

  • Destinations

Many threads in the same client may share these objects, whereas the following:

  • Sessions

  • Message Producers

  • Message Consumers

can only be accessed by one thread at a time. The restriction on single-threaded sessions reduces the complexity required by the JMS provider to support transactions.

Session concurrency can be implemented within a multithreaded client by creating multiple sessions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.113.55