Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Architecting and designing applications with the Java Message Service (JMS) requires not only knowing how to use the JMS API, but also having a solid foundation of its concepts. This article focuses on two such powerful concepts: transaction and redelivery. In JMS, a transaction organizes a message or message group into an atomic processing unit; failure to deliver a message may result in redelivery of that message or message group.
In this article, I help you develop a thorough understanding of your transaction options and show how you can evaluate their impact on message redelivery. I assume you have some familiarity with the JMS API as well as message-driven beans (MDBs).
An application has myriad transaction options available, including whether or not it wants to participate in transactions. If your application does not use transactions, it can use one of these acknowledgement modes: auto, duplicates okay, and client. You specify the acknowledgement modes when creating a JMS session. If your application uses transactions, it can choose from these transaction options: transacted session, MDB with container-managed transaction demarcation (CMTD), and MDB with bean-managed transaction demarcation (BMTD). The following lists briefly describe these acknowledgement modes and transaction options.
Acknowledgement options:
Other types of acknowledgement modes are possible. However, these acknowledgement modes are JMS provider specific, and therefore, compromise the JMS application portability.
Transaction options:
Figure 1 depicts a decision tree of the previously mentioned transaction options.

Figure 1. Transaction options decision tree
Before studying the transaction options in detail, we'll explore the message delivery process.
Toward the end of delivery, the message conceptually passes through the following stages: message with JMS provider and message in application processing.
In this stage, the message stays with the JMS provider just before the provider delivers it to the application. Consider a catastrophic situation where the JMS provider fails. What happens to the messages that the provider has not yet delivered to the client? Will the messages be lost?
The messages' fate depends not upon the transaction options outlined earlier, but rather upon the delivery mode. There are two delivery modes: nonpersistent and persistent. Messages with nonpersistent delivery modes are potentially lost if the JMS provider fails. Messages with persistent delivery modes are logged and stored to a stable storage. The JMS provider saves these messages to a stable storage, such as a database or a file system, and eventually delivers them to the application for processing.
In this stage, the application receives the message from the JMS provider and processes it. Consider a failure occurring during message processing. What happens to the message? Will the message be lost or redelivered for successful processing later? The answers to these questions depend upon the transaction options you choose.
Figure 2 depicts the two processing stages. The diagram shows that a message moves from the JMS provider to application processing.

Figure 2. Message delivery stages
Throughout the remainder of the article, I use the action legend shown in Figure 3 to illustrate the different transaction options. As Figure 3 shows, a filled arrow depicts a JMS provider-performed action, whereas an outlined arrow depicts an application-performed action.

Figure 3. Action legend
To demonstrate the impact of various transaction options as well as redelivery, I will use one sender. The sender sends simple
integers as object messages to a queue. Each transaction option has a different receiver. Each receiver demonstrates the impact
of choosing a particular transaction option as well as highlights the impact on message redelivery. The sender and receivers
utilize common administered objects: connection factory and queue. The connection factory is available using the Java Naming
and Directory Interface (JNDI) name jms/QueueConnectionFactory, whereas the queue is available using the jms/Queue JNDI name.
Listing 1 shows the code for the sender:
Listing 1. Sender
package com.malani.examples.jms.transactions;
import javax.naming.InitialContext;
import javax.jms.*;
public class Sender {
public static void main(String[] args) {
System.out.println("Starting...");
QueueConnectionFactory aQCF = null;
QueueConnection aQC = null;
QueueSession aQS = null;
QueueSender aSender = null;
try {
InitialContext aIC = new InitialContext(Resource.getResources());
aQCF = (QueueConnectionFactory) aIC.lookup(
iConstants.FACTORY_NAME
);
aQC = aQCF.createQueueConnection();
aQS = aQC.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue aQueue = (Queue) aIC.lookup(iConstants.QUEUE_NAME);
aSender = aQS.createSender(aQueue);
aQC.start();
for (int i = 0; i < 10; i++) {
aSender.send(aQS.createObjectMessage(new Integer(i)));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (aSender != null) {
aSender.close();
}
if (aQS != null) {
aQS.close();
}
if (aQC != null) {
aQC.stop();
aQC.close();
}
} catch (JMSException e) {
e.printStackTrace();
}
}
System.out.println("Ending...");
}
}
The following sections describe each acknowledgement mode in detail. A receiver demonstrates each acknowledgement mode. Each case uses the sender above to demonstrate the impact and implications of implementing a specific transaction option.
To implement the auto acknowledgement mode, when you create the receiver's session, specify false as the first argument and Session.AUTO_ACKNOWLEDGE as the second argument of the createSession() factory method. Specifying false creates a nontransacted session. The second parameter creates a session that automatically acknowledges messages. A message
is automatically acknowledged when it successfully returns from the receive() method. If the receiver uses the MessageListener interface, the message is automatically acknowledged when it successfully returns from the onMessage() method. If a failure occurs while executing the receive() method or the onMessage() method, the message is automatically redelivered. The JMS provider carefully manages message redelivery and guarantees once-only
delivery semantics.
Listing 2 describes the Receiver class. The Receiver is the AutoReceiver class's superclass. The Receiver superclass does most of the heavy lifting. It receives the object messages sent by the Sender class. In the processMessage() method, the receiver prints the message:
Listing 2. Receiver
package com.malani.examples.jms.transactions;
import javax.jms.*;
import javax.naming.InitialContext;
import java.io.InputStreamReader;
public abstract class Receiver {
protected void doAll() {
QueueConnectionFactory aQCF = null;
QueueConnection aQC = null;
QueueSession aQS = null;
QueueReceiver aQR = null;
try {
InitialContext aIC = new InitialContext(Resource.getResources());
aQCF = (QueueConnectionFactory) aIC.lookup(
iConstants.FACTORY_NAME
);
aQC = aQCF.createQueueConnection();
aQS = createQueueSession(aQC);
final QueueSession aQS1 = aQS;
Queue aQueue = (Queue) aIC.lookup(iConstants.QUEUE_NAME);
aQR = aQS.createReceiver(aQueue);
MessageListener aML = new MessageListener() {
public void onMessage(Message aMessage) {
try {
processMessage(aMessage, aQS1);
} catch (JMSException e) {
e.printStackTrace();
}
}
};
aQR.setMessageListener(aML);
aQC.start();
InputStreamReader aISR = new InputStreamReader(System.in);
char aAnswer = ' ';
do {
aAnswer = (char) aISR.read();
if ((aAnswer == 'r') || (aAnswer == 'R')) {
aQS.recover();
}
} while ((aAnswer != 'q') && (aAnswer != 'Q'));
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (aQR != null) {
aQR.close();
}
if (aQS != null) {
aQS.close();
}
if (aQC != null) {
aQC.stop();
aQC.close();
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
protected void processMessage(Message aMessage, QueueSession aQS) throws JMSException {
if (aMessage instanceof ObjectMessage) {
ObjectMessage aOM = (ObjectMessage) aMessage;
System.out.print(aOM.getObject() + " ");
}
}
protected abstract QueueSession createQueueSession(
QueueConnection aQC
) throws JMSException;
}
Listing 3 describes the AutoReceiver class. As shown, the AutoReceiver creates a nontransacted session that automatically acknowledges messages in the createQueueSession() method:
Listing 3. AutoReceiver
package com.malani.examples.jms.transactions;
import javax.naming.InitialContext;
import javax.jms.*;
import java.io.InputStreamReader;
public class AutoReceiver extends Receiver {
public static void main(String[] args) {
System.out.println("Starting...");
new AutoReceiver().doAll();
System.out.println("Ending...");
}
protected QueueSession createQueueSession(
QueueConnection aQC
) throws JMSException {
return aQC.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
}
}
Executing Listing 3 produces the following output; type character q and press Return to end the program:
Starting... Java (TM) Message Service 1.0.2 Reference Implementation (build b14) 0 1 2 3 4 5 6 7 8 9 q Ending...
In Figure 4, a message is automatically acknowledged after the application successfully processes it, which is after the message
returns from the onMessage() method.

Figure 4. Auto acknowledgement
The duplicates okay acknowledgement mode closely resembles the auto acknowledgement mode. However, rather than pass Session.AUTO_ACKNOWLEDGE, you specify Session.DUPS_OK_ACKNOWLEDGE as the acknowledgement mode of createSession()'s second argument. With less overhead than auto mode, in duplicates okay mode, the JMS provider guarantees at-least-once
message delivery. During failure recovery, certain messages are probably delivered more than once.
Listing 4 describes the DuplicatesOkayReceiver class, which extends the Receiver superclass. As shown, DuplicatesOkayReceiver creates a nontransacted session with duplicates okay acknowledgement mode in the createQueueSession() method:
Listing 4. DuplicatesOkayReceiver
package com.malani.examples.jms.transactions;
import javax.naming.InitialContext;
import javax.jms.*;
import java.io.InputStreamReader;
public class DuplicatesOkayReceiver extends Receiver {
public static void main(String[] args) {
System.out.println("Starting...");
new DuplicatesOkayReceiver().doAll();
System.out.println("Ending...");
}
protected QueueSession createQueueSession(
QueueConnection aQC
) throws JMSException {
return aQC.createQueueSession(false, Session.DUPS_OK_ACKNOWLEDGE);
}
}
Executing Listing 4 produces the following output; type character q and press Return to end the program:
Starting... Java (TM) Message Service 1.0.2 Reference Implementation (build b14) 0 1 2 3 4 5 6 7 8 9 q Ending...
The difference between auto mode and duplicates okay mode is a classic tradeoff between delivery guarantee and throughput. With at-least-once message delivery guarantee, duplicates okay mode achieves higher throughput.
In Figure 5, a message is automatically acknowledged after the application successfully processes it, which is after the message
successfully returns from the onMessage() method. The JMS provider does the same thing as in Figure 4, except in the duplicates okay mode, it acknowledges the message
lazily.

Figure 5. Duplicates okay acknowledgement
To implement client acknowledgement mode, when you create the receiver's session, specify false as createSession()'s first argument and Session.CLIENT_ACKNOWLEDGE as its second argument. Specifying false creates a nontransacted session. In client mode, invoking the Message class's acknowledge() method explicitly acknowledges the message. In fact, using the acknowledge() method makes sense when only using the client mode.
Listing 5 represents the ClientReceiver class. The ClientReceiver class extends the Receiver superclass. As shown, the ClientReceiver creates a nontransacted session where the client acknowledges the messages in the createQueueSession() method. In the processMessage() method, the ClientReceiver acknowledges only message 5:
Listing 5. ClientReceiver
package com.malani.examples.jms.transactions;
import javax.naming.InitialContext;
import javax.jms.*;
import java.io.InputStreamReader;
public class ClientReceiver extends Receiver {
public static void main(String[] args) {
System.out.println("Starting...");
new ClientReceiver().doAll();
System.out.println("Ending...");
}
protected QueueSession createQueueSession(
QueueConnection aQC
) throws JMSException {
return aQC.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
}
protected void processMessage(Message aMessage, QueueSession aQS)
throws JMSException
{
if (aMessage instanceof ObjectMessage) {
ObjectMessage aOM = (ObjectMessage) aMessage;
System.out.print(aOM.getObject() + " " );
Integer i = (Integer) aOM.getObject();
int ii = i.intValue();
if (ii == 5) {
aOM.acknowledge();
}
}
}
}
Executing Listing 5 produces the following output:
Starting... Java (TM) Message Service 1.0.2 Reference Implementation (build b14) 0 1 2 3 4 5 6 7 8 9 r 6 7 8 9 q Ending...
Consider the following scenario: An application receives but does not acknowledge a message. The application receives a subsequent
message and acknowledges it. What happens to the former message? The former message is also considered acknowledged. Generally,
acknowledging a particular message acknowledges all prior messages the session receives. In the above output, only message
5 is explicitly acknowledged. All the messages before message 5 are implicitly acknowledged. Messages after message 5 are not acknowledged.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq