Until a JMS message has been acknowledged, it is not considered to be successfully consumed. The successful consumption of a message ordinarily takes place in three stages.
The client receives the message.
The client processes the message.
The message is acknowledged. Acknowledgment is initiated either by the JMS provider or by the client, depending on the session acknowledgment mode.
In transacted sessions (see Using JMS API Local Transactions), acknowledgment happens automatically when a transaction is committed. If a transaction is rolled back, all consumed messages are redelivered.
In nontransacted sessions, when and how a message is acknowledged depend on the value specified as the second argument of the createSession method. The three possible argument values are as follows:
Session.AUTO_ACKNOWLEDGE: The session automatically acknowledges a client’s receipt of a message either when the client has successfully returned from a call to receive or when the MessageListener it has called to process the message returns successfully. A synchronous receive in an AUTO_ACKNOWLEDGE session is the one exception to the rule that message consumption is a three-stage process as described earlier.
In this case, the receipt and acknowledgment take place in one step, followed by the processing of the message.
Session.CLIENT_ACKNOWLEDGE: A client acknowledges a message by calling the message’s acknowledge method. In this mode, acknowledgment takes place on the session level: Acknowledging a consumed message automatically acknowledges the receipt of all messages that have been consumed by its session. For example, if a message consumer consumes ten messages and then acknowledges the fifth message delivered, all ten messages are acknowledged.
Session.DUPS_OK_ACKNOWLEDGE: This option instructs the session to lazily acknowledge the delivery of messages. This is likely to result in the delivery of some duplicate messages if the JMS provider fails, so it should be used only by consumers that can tolerate duplicate messages. (If the JMS provider redelivers a message, it must set the value of the JMSRedelivered message header to true.) This option can reduce session overhead by minimizing the work the session does to prevent duplicates.
If messages have been received from a queue but not acknowledged when a session terminates, the JMS provider retains them and redelivers them when a consumer next accesses the queue. The provider also retains unacknowledged messages for a terminated session that has a durable TopicSubscriber. (See Creating Durable Subscriptions.) Unacknowledged messages for a nondurable TopicSubscriber are dropped when the session is closed.
If you use a queue or a durable subscription, you can use the Session.recover method to stop a nontransacted session and restart it with its first unacknowledged message. In effect, the session’s series of delivered messages is reset to the point after its last acknowledged message. The messages it now delivers may be different from those that were originally delivered, if messages have expired or if higher-priority messages have arrived. For a nondurable TopicSubscriber, the provider may drop unacknowledged messages when its session is recovered.
The sample program in the next section demonstrates two ways to ensure that a message will not be acknowledged until processing of the message is complete.
The AckEquivExample.java program shows how both of the following two scenarios ensure that a message will not be acknowledged until processing of it is complete:
Using an asynchronous message consumer (a message listener) in an AUTO_ACKNOWLEDGE session
Using a synchronous receiver in a CLIENT_ACKNOWLEDGE session
With a message listener, the automatic acknowledgment happens when the onMessage method returns (that is, after message processing has finished). With a synchronous receiver, the client acknowledges the message after processing is complete. If you use AUTO_ACKNOWLEDGE with a synchronous receive, the acknowledgment happens immediately after the receive call; if any subsequent processing steps fail, the message cannot be redelivered.
The program is in the following directory:
tut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/src/java/
The program contains a SynchSender class, a SynchReceiver class, an AsynchSubscriber class with a TextListener class, a MultiplePublisher class, a main method, and a method that runs the other classes’ threads.
The program uses the following objects:
jms/ConnectionFactory, jms/Queue, and jms/Topic: resources that you created in Creating JMS Administered Objects for the Synchronous Receive Example
jms/ControlQueue: an additional queue
jms/DurableConnectionFactory: a connection factory with a client ID (see Creating Durable Subscriptions, for more information)
To create the new queue and connection factory, you can use Ant targets defined in the file tut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/build.xml.
To run this example, follow these steps:
In a terminal window, go to the following directory:
tut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/
To create the objects needed in this example, type the following commands:
ant create-control-queue ant create-durable-cf |
To compile and package the program using NetBeans IDE, follow these steps:
In NetBeans IDE, choose Open Project from the File menu.
In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/jms/advanced/.
Select the ackequivexample folder.
Select the Open as Main Project check box.
Click Open Project.
Right-click the project and choose Build.
To compile and package the program using Ant, type the following command:
ant |
To run the program using NetBeans IDE, right-click the ackequivexample project and choose Run.
To run the program from the command line, follow these steps:
Go to the dist directory:
cd dist |
Type the following command:
appclient -client ackequivexample.jar |
The program output looks something like this:
Queue name is jms/ControlQueue Queue name is jms/Queue Topic name is jms/Topic Connection factory name is jms/DurableConnectionFactory SENDER: Created client-acknowledge session SENDER: Sending message: Here is a client-acknowledge message RECEIVER: Created client-acknowledge session RECEIVER: Processing message: Here is a client-acknowledge message RECEIVER: Now I’ll acknowledge the message SUBSCRIBER: Created auto-acknowledge session SUBSCRIBER: Sending synchronize message to control queue PUBLISHER: Created auto-acknowledge session PUBLISHER: Receiving synchronize messages from control queue; count = 1 PUBLISHER: Received synchronize message; expect 0 more PUBLISHER: Publishing message: Here is an auto-acknowledge message 1 PUBLISHER: Publishing message: Here is an auto-acknowledge message 2 SUBSCRIBER: Processing message: Here is an auto-acknowledge message 1 PUBLISHER: Publishing message: Here is an auto-acknowledge message 3 SUBSCRIBER: Processing message: Here is an auto-acknowledge message 2 SUBSCRIBER: Processing message: Here is an auto-acknowledge message 3 |
After you run the program, you can delete the destination resource jms/ControlQueue. Go to the directory tut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/ and type the following command:
ant delete-control-queue |
You will need the other resources for other examples.
To delete the class and JAR files for the program using NetBeans IDE, right-click the project and choose Clean.
To delete the class and JAR files for the program using Ant, type the following:
ant clean |