Movatterモバイル変換


[0]ホーム

URL:


Document Information

Preface

Part I Introduction

1.  Overview

2.  Using the Tutorial Examples

Part II The Web Tier

3.  Getting Started with Web Applications

4.  Java Servlet Technology

5.  JavaServer Pages Technology

6.  JavaServer Pages Documents

7.  JavaServer Pages Standard Tag Library

8.  Custom Tags in JSP Pages

9.  Scripting in JSP Pages

10.  JavaServer Faces Technology

11.  Using JavaServer Faces Technology in JSP Pages

12.  Developing with JavaServer Faces Technology

13.  Creating Custom UI Components

14.  Configuring JavaServer Faces Applications

15.  Internationalizing and Localizing Web Applications

Part III Web Services

16.  Building Web Services with JAX-WS

17.  Binding between XML Schema and Java Classes

18.  Streaming API for XML

19.  SOAP with Attachments API for Java

Part IV Enterprise Beans

20.  Enterprise Beans

21.  Getting Started with Enterprise Beans

22.  Session Bean Examples

23.  A Message-Driven Bean Example

Part V Persistence

24.  Introduction to the Java Persistence API

25.  Persistence in the Web Tier

26.  Persistence in the EJB Tier

27.  The Java Persistence Query Language

Part VI Services

28.  Introduction to Security in the Java EE Platform

29.  Securing Java EE Applications

30.  Securing Web Applications

31.  The Java Message Service API

Overview of the JMS API

What Is Messaging?

What Is the JMS API?

When Can You Use the JMS API?

How Does the JMS API Work with the Java EE Platform?

Basic JMS API Concepts

JMS API Architecture

Messaging Domains

Point-to-Point Messaging Domain

Publish/Subscribe Messaging Domain

Programming with the Common Interfaces

Message Consumption

The JMS API Programming Model

JMS Administered Objects

JMS Connection Factories

JMS Destinations

JMS Connections

JMS Sessions

JMS Message Producers

JMS Message Consumers

JMS Message Listeners

JMS Message Selectors

JMS Messages

Message Headers

Message Properties

Message Bodies

JMS Queue Browsers

JMS Exception Handling

Writing Simple JMS Client Applications

A Simple Example of Synchronous Message Receives

Writing the Client Programs for the Synchronous Receive Example

Starting the JMS Provider

Creating JMS Administered Objects for the Synchronous Receive Example

Compiling and Packaging the Clients for the Synchronous Receive Example

Running the Clients for the Synchronous Receive Example

A Simple Example of Asynchronous Message Consumption

Writing the Client Programs for the Asynchronous Receive Example

Compiling and Packaging theAsynchConsumer Client

Running the Clients for the Asynchronous Receive Example

A Simple Example of Browsing Messages in a Queue

Writing the Client Program for the Queue Browser Example

Compiling and Packaging theMessageBrowser Client

Running the Clients for the Queue Browser Example

Running JMS Client Programs on Multiple Systems

Creating Administered Objects for Multiple Systems

Editing, Recompiling, Repackaging, and Running the Programs

Deleting the Connection Factory and Stopping the Server

Creating Robust JMS Applications

Using Basic Reliability Mechanisms

Controlling Message Acknowledgment

Specifying Message Persistence

Setting Message Priority Levels

Allowing Messages to Expire

Creating Temporary Destinations

Using Advanced Reliability Mechanisms

Creating Durable Subscriptions

Using JMS API Local Transactions

Using the JMS API in a Java EE Application

Using@Resource Annotations in Java EE Components

Using Session Beans to Produce and to Synchronously Receive Messages

Resource Management

Transactions

Using Message-Driven Beans to Receive Messages Asynchronously

Managing Distributed Transactions

Using the JMS API with Application Clients and Web Components

Further Information about JMS

32.  Java EE Examples Using the JMS API

33.  Transactions

34.  Resource Connections

35.  Connector Architecture

Part VII Case Studies

36.  The Coffee Break Application

37.  The Duke's Bank Application

Part VIII Appendixes

A.  Java Encoding Schemes

B.  About the Authors

Index

 

The Java EE 5 Tutorial

Java Coffee Cup logo
PreviousContentsNext

Creating Robust JMS Applications

This section explains how to use features of the JMS API toachieve the level of reliability and performance your application requires. Many people choose toimplement JMS applications because they cannot tolerate dropped or duplicate messages and requirethat every message be received once and only once. The JMS API providesthis functionality.

The most reliable way to produce a message is to send aPERSISTENT message within a transaction. JMS messages arePERSISTENT by default. Atransactionis a unit of work into which you can group a series ofoperations, such as message sends and receives, so that the operations either allsucceed or all fail. For details, seeSpecifying Message Persistence andUsing JMS API Local Transactions.

The most reliable way to consume a message is to do sowithin a transaction, either from a queue or from a durable subscription toa topic. For details, seeCreating Temporary Destinations,Creating Durable Subscriptions, andUsing JMS API Local Transactions.

For other applications, a lower level of reliability can reduce overhead and improveperformance. You can send messages with varying priority levels (seeSetting Message Priority Levels) and you canset them to expire after a certain length of time (seeAllowing Messages to Expire).

The JMS API provides several ways to achieve various kinds and degrees ofreliability. This section divides them into two categories:

The following sections describe these features as they apply to JMS clients. Someof the features work differently in Java EE applications; in these cases, thedifferences are noted here and are explained in detail inUsing the JMS API in a Java EE Application.

This section includes three sample programs, which you can find in the directorytut-install/javaeetutorial5/examples/jms/advanced/. Each sample uses a utility class calledSampleUtilities.java.

Using Basic Reliability Mechanisms

The basic mechanisms for achieving or affecting reliable message delivery are as follows:

  • Controlling message acknowledgment: You can specify various levels of control over message acknowledgment.

  • Specifying message persistence: You can specify that messages are persistent, meaning that they must not be lost in the event of a provider failure.

  • Setting message priority levels: You can set various priority levels for messages, which can affect the order in which the messages are delivered.

  • Allowing messages to expire: You can specify an expiration time for messages so that they will not be delivered if they are obsolete.

  • Creating temporary destinations: You can create temporary destinations that last only for the duration of the connection in which they are created.

Controlling Message Acknowledgment

Until a JMS message has been acknowledged, it is not considered tobe successfully consumed. The successful consumption of a message ordinarily takes place in threestages.

  1. The client receives the message.

  2. The client processes the message.

  3. 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 (seeUsing JMS API Local Transactions), acknowledgment happens automatically when a transaction is committed.If a transaction is rolled back, all consumed messages areredelivered.

In nontransacted sessions, when and how a message is acknowledged depend on thevalue specified as the second argument of thecreateSession method. The three possibleargument 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 toreceive or when theMessageListener it has called to process the message returns successfully. A synchronous receive in anAUTO_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’sacknowledge method. In this mode, acknowledgment takes place on the session level: Acknowledging a consumed message automatically acknowledges the receipt ofall 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 theJMSRedelivered message header totrue.) 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 asession terminates, the JMS provider retains them and redelivers them when a consumernext accesses the queue. The provider also retains unacknowledged messages for a terminatedsession that has a durableTopicSubscriber. (SeeCreating Durable Subscriptions.) Unacknowledged messages for a nondurableTopicSubscriberare dropped when the session is closed.

If you use a queue or a durable subscription, you can usetheSession.recover method to stop a nontransacted session and restart it with itsfirst unacknowledged message. In effect, the session’s series of delivered messages is resetto the point after its last acknowledged message. The messages it now deliversmay be different from those that were originally delivered, if messages have expiredor if higher-priority messages have arrived. For a nondurableTopicSubscriber, the provider maydrop unacknowledged messages when its session is recovered.

The sample program in the next section demonstrates two ways to ensure thata message will not be acknowledged until processing of the message is complete.

A Message Acknowledgment Example

TheAckEquivExample.java program shows how both of the following two scenarios ensure thata message will not be acknowledged until processing of it is complete:

  • Using an asynchronous message consumer (a message listener) in anAUTO_ACKNOWLEDGE session

  • Using a synchronous receiver in aCLIENT_ACKNOWLEDGE session

With a message listener, the automatic acknowledgment happens when theonMessage methodreturns (that is, after message processing has finished). With a synchronous receiver, theclient acknowledges the message after processing is complete. If you useAUTO_ACKNOWLEDGE with asynchronous receive, the acknowledgment happens immediately after thereceive call; if anysubsequent 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 aSynchSender class, aSynchReceiver class, anAsynchSubscriber classwith aTextListener class, aMultiplePublisher class, amain method, and a methodthat runs the other classes’ threads.

The program uses the following objects:

To create the new queue and connection factory, you can use Anttargets defined in the filetut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/build.xml.

To run this example, follow these steps:

  1. In a terminal window, go to the following directory:

    tut-install/javaeetutorial5/examples/jms/advanced/ackequivexample/
  2. To create the objects needed in this example, type the following commands:

    ant create-control-queue ant create-durable-cf
  3. To compile and package the program using NetBeans IDE, follow these steps:

    1. In NetBeans IDE, choose Open Project from the File menu.

    2. In the Open Project dialog, navigate totut-install/javaeetutorial5/examples/jms/advanced/.

    3. Select theackequivexample folder.

    4. Select the Open as Main Project check box.

    5. Click Open Project.

    6. Right-click the project and choose Build.

    To compile and package the program using Ant, type the following command:

    ant
  4. To run the program using NetBeans IDE, right-click theackequivexample project and choose Run.

    To run the program from the command line, follow these steps:

    1. Go to thedist directory:

      cd dist
    2. Type the following command:

      appclient -client ackequivexample.jar

The program output looks something like this:

Queue name is jms/ControlQueueQueue name is jms/QueueTopic name is jms/TopicConnection 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 messageSUBSCRIBER: Created auto-acknowledge sessionSUBSCRIBER: Sending synchronize message to control queuePUBLISHER: Created auto-acknowledge sessionPUBLISHER: Receiving synchronize messages from control queue; count = 1PUBLISHER: Received synchronize message;  expect 0 morePUBLISHER: Publishing message: Here is an auto-acknowledge message 1PUBLISHER: Publishing message: Here is an auto-acknowledge message 2SUBSCRIBER: Processing message: Here is an auto-acknowledge message 1PUBLISHER: Publishing message: Here is an auto-acknowledge message 3SUBSCRIBER: Processing message: Here is an auto-acknowledge message 2SUBSCRIBER: Processing message: Here is an auto-acknowledge message 3

After you run the program, you can delete the destination resourcejms/ControlQueue.Go to the directorytut-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 NetBeansIDE, right-click the project and choose Clean.

To delete the class and JAR files for the program using Ant,type the following:

ant clean
Specifying Message Persistence

The JMS API supports two delivery modes for messages to specify whether messagesare lost if the JMS provider fails. These delivery modes are fields oftheDeliveryMode interface.

  • ThePERSISTENT delivery mode, which is the default, instructs the JMS provider to take extra care to ensure that a message is not lost in transit in case of a JMS provider failure. A message sent with this delivery mode is logged to stable storage when it is sent.

  • TheNON_PERSISTENT delivery mode does not require the JMS provider to store the message or otherwise guarantee that it is not lost if the provider fails.

You can specify the delivery mode in either of two ways.

  • You can use thesetDeliveryMode method of theMessageProducer interface to set the delivery mode for all messages sent by that producer. For example, the following call sets the delivery mode toNON_PERSISTENT for a producer:

    producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
  • You can use the long form of thesend or thepublish method to set the delivery mode for a specific message. The second argument sets the delivery mode. For example, the followingsend call sets the delivery mode formessage toNON_PERSISTENT:

    producer.send(message, DeliveryMode.NON_PERSISTENT, 3, 10000);

    The third and fourth arguments set the priority level and expiration time, which are described in the next two subsections.

If you do not specify a delivery mode, the default isPERSISTENT. UsingtheNON_PERSISTENT delivery mode may improve performance and reduce storage overhead, but youshould use it only if your application can afford to miss messages.

Setting Message Priority Levels

You can use message priority levels to instruct the JMS provider to deliverurgent messages first. You can set the priority level in either of twoways.

  • You can use thesetPriority method of theMessageProducer interface to set the priority level for all messages sent by that producer. For example, the following call sets a priority level of 7 for a producer:

    producer.setPriority(7);
  • You can use the long form of thesend or thepublish method to set the priority level for a specific message. The third argument sets the priority level. For example, the followingsend call sets the priority level formessage to 3:

    producer.send(message, DeliveryMode.NON_PERSISTENT, 3, 10000);

The ten levels of priority range from 0 (lowest) to 9 (highest).If you do not specify a priority level, the default level is 4.A JMS provider tries to deliver higher-priority messages before lower-priority ones but does nothave to deliver messages in exact order of priority.

Allowing Messages to Expire

By default, a message never expires. If a message will become obsolete aftera certain period, however, you may want to set an expiration time.You can do this in either of two ways.

  • You can use thesetTimeToLive method of theMessageProducer interface to set a default expiration time for all messages sent by that producer. For example, the following call sets a time to live of one minute for a producer:

    producer.setTimeToLive(60000);
  • You can use the long form of thesend or thepublish method to set an expiration time for a specific message. The fourth argument sets the expiration time in milliseconds. For example, the followingsend call sets a time to live of 10 seconds:

    producer.send(message, DeliveryMode.NON_PERSISTENT, 3, 10000);

If the specifiedtimeToLive value is0, the message never expires.

When the message is sent, the specifiedtimeToLive is added to the currenttime to give the expiration time. Any message not delivered before the specifiedexpiration time is destroyed. The destruction of obsolete messages conserves storage and computingresources.

Creating Temporary Destinations

Normally, you create JMS destinations (queues and topics) administratively rather than programmatically. YourJMS provider includes a tool that you use to create and remove destinations,and it is common for destinations to be long-lasting.

The JMS API also enables you to create destinations (TemporaryQueue andTemporaryTopicobjects) that last only for the duration of the connection in which theyare created. You create these destinations dynamically using theSession.createTemporaryQueue and theSession.createTemporaryTopic methods.

The only message consumers that can consume from a temporary destination are thosecreated by the same connection that created the destination. Any message producer cansend to the temporary destination. If you close the connection that a temporarydestination belongs to, the destination is closed and its contents are lost.

You can use temporary destinations to implement a simple request/reply mechanism. If youcreate a temporary destination and specify it as the value of theJMSReplyTomessage header field when you send a message, then the consumer of themessage can use the value of theJMSReplyTo field as the destination towhich it sends a reply. The consumer can also reference the original requestby setting theJMSCorrelationID header field of the reply message to the value oftheJMSMessageID header field of the request. For example, anonMessage method cancreate a session so that it can send a reply to the messageit receives. It can use code such as the following:

producer = session.createProducer(msg.getJMSReplyTo());replyMsg = session.createTextMessage("Consumer " +    "processed message: " + msg.getText());replyMsg.setJMSCorrelationID(msg.getJMSMessageID());producer.send(replyMsg);

For more examples, seeChapter 32, Java EE Examples Using the JMS API.

Using Advanced Reliability Mechanisms

The more advanced mechanisms for achieving reliable message delivery are the following:

  • Creating durable subscriptions: You can create durable topic subscriptions, which receive messages published while the subscriber is not active. Durable subscriptions offer the reliability of queues to the publish/subscribe message domain.

  • Using local transactions: You can use local transactions, which allow you to group a series of sends and receives into an atomic unit of work. Transactions are rolled back if they fail at any time.

Creating Durable Subscriptions

To ensure that a pub/sub application receives all published messages, usePERSISTENT deliverymode for the publishers. In addition, use durable subscriptions for the subscribers.

TheSession.createConsumer method creates a nondurable subscriber if a topic is specified asthe destination. A nondurable subscriber can receive only messages that are published whileit is active.

At the cost of higher overhead, you can use theSession.createDurableSubscriber methodto create a durable subscriber. A durable subscription can have only one activesubscriber at a time.

A durable subscriber registers a durable subscription by specifying a unique identity thatis retained by the JMS provider. Subsequent subscriber objects that have the sameidentity resume the subscription in the state in which it was left bythe preceding subscriber. If a durable subscription has no active subscriber, the JMSprovider retains the subscription’s messages until they are received by the subscription oruntil they expire.

You establish the unique identity of a durable subscriber by setting the following:

  • A client ID for the connection

  • A topic and a subscription name for the subscriber

You set the client ID administratively for a client-specific connection factory using theAdmin Console.

After using this connection factory to create the connection and the session, youcall thecreateDurableSubscriber method with two arguments: the topic and a string thatspecifies the name of the subscription:

String subName = "MySub";MessageConsumer topicSubscriber =     session.createDurableSubscriber(myTopic, subName);

The subscriber becomes active after you start theConnection orTopicConnection. Later,you might close the subscriber:

topicSubscriber.close();

The JMS provider stores the messages sent or published to the topic, asit would store messages sent to a queue. If the program oranother application callscreateDurableSubscriber using the same connection factory and its client ID, thesame topic, and the same subscription name, the subscription is reactivated, and theJMS provider delivers the messages that were published while the subscriber was inactive.

To delete a durable subscription, first close the subscriber, and then use theunsubscribe method, with the subscription name as the argument:

topicSubscriber.close();session.unsubscribe("MySub");

Theunsubscribe method deletes the state that the provider maintains for the subscriber.

Figure 31-7 andFigure 31-8 show the difference between a nondurable and a durable subscriber.With an ordinary, nondurable subscriber, the subscriber and the subscription begin and endat the same point and are, in effect, identical. When a subscriber isclosed, the subscription also ends. Here,create stands for a call toSession.createConsumerwith aTopic argument, andclose stands for a call toMessageConsumer.close. Anymessages published to the topic between the time of the firstclose andthe time of the secondcreate are not consumed by the subscriber. InFigure 31-7,the subscriber consumes messages M1, M2, M5, and M6, but messages M3 andM4 are lost.

Figure 31-7 Nondurable Subscribers and Subscriptions

Diagram showing messages being lost when nondurable subscriptions are used

With a durable subscriber, the subscriber can be closed and re-created, but thesubscription continues to exist and to hold messages until the application calls theunsubscribe method. InFigure 31-8,create stands for a call toSession.createDurableSubscriber,closestands for a call toMessageConsumer.close, andunsubscribe stands for a calltoSession.unsubscribe. Messages published while the subscriber is closed are received when thesubscriber is created again. So even though messages M2, M4, and M5 arrivewhile the subscriber is closed, they are not lost.

Figure 31-8 A Durable Subscriber and Subscription

Diagram showing messages being preserved when durable subscriptions are used

SeeA Java EE Application That Uses the JMS API with a Session Bean for an example of a Java EE application that uses durablesubscriptions. SeeA Message Acknowledgment Example and the next section for examples of client applicationsthat use durable subscriptions.

A Durable Subscription Example

TheDurableSubscriberExample.java program shows how durable subscriptions work. It demonstrates that a durablesubscription is active even when the subscriber is not active. The program containsaDurableSubscriber class, aMultiplePublisher class, amain method, and a method thatinstantiates the classes and calls their methods in sequence.

The program is in the following directory:

tut-install/javaeetutorial5/examples/jms/advanced/durablesubscriberexample/src/java/

The program begins in the same way as any publish/subscribe program: The subscriberstarts, the publisher publishes some messages, and the subscriber receives them. At thispoint, the subscriber closes itself. The publisher then publishes some messages while thesubscriber is not active. The subscriber then restarts and receives the messages.

Before you run this program, compile and package the source file and createa connection factory that has a client ID. Perform the following steps:

  1. To compile and package the program using NetBeans IDE, follow these steps:

    1. In NetBeans IDE, choose Open Project from the File menu.

    2. In the Open Project dialog, navigate totut-install/javaeetutorial5/examples/jms/advanced/.

    3. Select thedurablesubscriberexample folder.

    4. Select the Open as Main Project check box.

    5. Click Open Project.

    6. Right-click the project and choose Build.

    To compile and package the program using Ant, follow these steps:

    1. Go to the following directory:

      tut-install/javaeetutorial5/examples/jms/advanced/durablesubscriberexample/
    2. Type the following command:

      ant
  2. If you did not do so forA Message Acknowledgment Example, create a connection factory namedjms/DurableConnectionFactory:

    ant create-durable-cf

To run the program using NetBeans IDE, right-click thedurablesubscriberexample project andchoose Run.

To run the program from the command line, follow these steps:

  1. Go to thedist directory:

    cd dist
  2. Type the following command:

    appclient -client durablesubscriberexample.jar

The output looks something like this:

Connection factory without client ID is jms/ConnectionFactoryConnection factory with client ID is jms/DurableConnectionFactoryTopic name is jms/TopicStarting subscriberPUBLISHER: Publishing message: Here is a message 1SUBSCRIBER: Reading message: Here is a message 1PUBLISHER: Publishing message: Here is a message 2SUBSCRIBER: Reading message: Here is a message 2PUBLISHER: Publishing message: Here is a message 3SUBSCRIBER: Reading message: Here is a message 3Closing subscriberPUBLISHER: Publishing message: Here is a message 4PUBLISHER: Publishing message: Here is a message 5PUBLISHER: Publishing message: Here is a message 6Starting subscriberSUBSCRIBER: Reading message: Here is a message 4SUBSCRIBER: Reading message: Here is a message 5SUBSCRIBER: Reading message: Here is a message 6Closing subscriberUnsubscribing from durable subscription

After you run the program, you can delete the connection factoryjms/DurableConnectionFactory.Go to the directorytut-install/javaeetutorial5/examples/jms/advanced/durablesubscriberexample/ and type the following command:

ant delete-durable-cf

To delete the class and JAR files for the program using NetBeansIDE, right-click the project and choose Clean.

To delete the class and JAR files for the program using Ant,type the following:

ant clean
Using JMS API Local Transactions

You can group a series of operations into an atomic unit ofwork called a transaction. If any one of the operations fails, the transactioncan be rolled back, and the operations can be attempted again from thebeginning. If all the operations succeed, the transaction can be committed.

In a JMS client, you can use local transactions to group messagesends and receives. The JMS APISession interface providescommit androllback methodsthat you can use in a JMS client. A transaction commit means thatall produced messages are sent and all consumed messages are acknowledged. A transactionrollback means that all produced messages are destroyed and all consumed messages arerecovered and redelivered unless they have expired (seeAllowing Messages to Expire).

A transacted session is always involved in a transaction. As soon as thecommit or therollback method is called, one transaction ends and another transactionbegins. Closing a transacted session rolls back its transaction in progress, including anypending sends and receives.

In an Enterprise JavaBeans component, you cannot use theSession.commit andSession.rollbackmethods. Instead, you use distributed transactions, which are described inUsing the JMS API in a Java EE Application.

You can combine several sends and receives in a single JMS APIlocal transaction. If you do so, you need to be careful about theorder of the operations. You will have no problems if the transaction consistsof all sends or all receives or if the receives come before thesends. But if you try to use a request/reply mechanism, whereby you senda message and then try to receive a reply to the sent messagein the same transaction, the program will hang, because the send cannot takeplace until the transaction is committed. The following code fragment illustrates the problem:

// Don’t do this!outMsg.setJMSReplyTo(replyQueue);producer.send(outQueue, outMsg);consumer = session.createConsumer(replyQueue);inMsg = consumer.receive();session.commit();

Because a message sent during a transaction is not actually sent until thetransaction is committed, the transaction cannot contain any receives that depend on thatmessage’s having been sent.

In addition, the production and the consumption of a message cannot both bepart of the same transaction. The reason is that the transactions take placebetween the clients and the JMS provider, which intervenes between the production andthe consumption of the message.Figure 31-9 illustrates this interaction.

Figure 31-9 Using JMS API Local Transactions

Diagram of local transactions, showing separate transactions for sending and consuming a message

The sending of one or more messages to one or more destinationsby client 1 can form a single transaction, because it forms a singleset of interactions with the JMS provider using a single session. Similarly, thereceiving of one or more messages from one or more destinations by client2 also forms a single transaction using a single session. But because thetwo clients have no direct interaction and are using two different sessions, notransactions can take place between them.

Another way of putting this is that the act of producing and/orconsuming messages in a session can be transactional, but the act of producingand consuming a specific message across different sessions cannot be transactional.

This is the fundamental difference between messaging and synchronized processing. Instead of tightlycoupling the sending and receiving of data, message producers and consumers use analternative approach to reliability, one that is built on a JMS provider’s abilityto supply a once-and-only-once message delivery guarantee.

When you create a session, you specify whether it is transacted. The firstargument to thecreateSession method is aboolean value. A value oftrue means that the session is transacted; a value offalse means thatit is not transacted. The second argument to this method is the acknowledgmentmode, which is relevant only to nontransacted sessions (seeControlling Message Acknowledgment). If the sessionis transacted, the second argument is ignored, so it is a good ideato specify0 to make the meaning of your code clear. For example:

session = connection.createSession(true, 0);

Thecommit and therollback methods for local transactions are associated with thesession. You can combine queue and topic operations in a single transaction ifyou use the same session to perform the operations. For example, you canuse the same session to receive a message from a queue and senda message to a topic in the same transaction.

You can pass a client program’s session to a message listener’s constructor functionand use it to create a message producer. In this way, you canuse the same session for receives and sends in asynchronous message consumers.

The next section provides an example of the use of JMS APIlocal transactions.

A Local Transaction Example

TheTransactedExample.java program demonstrates the use of transactions in a JMS client application.The program is in the following directory:

tut-install/javaeetutorial5/examples/jms/advanced/transactedexample/src/java/

This example shows how to use a queue and a topic ina single transaction as well as how to pass a session to amessage listener’s constructor function. The program represents a highly simplified e-commerce application in whichthe following things happen.

  1. A retailer sends aMapMessage to the vendor order queue, ordering a quantity of computers, and waits for the vendor’s reply:

    producer = session.createProducer(vendorOrderQueue);outMessage = session.createMapMessage();outMessage.setString("Item", "Computer(s)");outMessage.setInt("Quantity", quantity);outMessage.setJMSReplyTo(retailerConfirmQueue);producer.send(outMessage);System.out.println("Retailer: ordered " + quantity + " computer(s)");orderConfirmReceiver = session.createConsumer(retailerConfirmQueue);connection.start();
  2. The vendor receives the retailer’s order message and sends an order message to the supplier order topic in one transaction. This JMS transaction uses a single session, so you can combine a receive from a queue with a send to a topic. Here is the code that uses the same session to create a consumer for a queue and a producer for a topic:

    vendorOrderReceiver = session.createConsumer(vendorOrderQueue);supplierOrderProducer = session.createProducer(supplierOrderTopic);

    The following code receives the incoming message, sends an outgoing message, and commits the session. The message processing has been removed to keep the sequence simple:

    inMessage = vendorOrderReceiver.receive();// Process the incoming message and format the outgoing // message...supplierOrderProducer.send(orderMessage);...session.commit();
  3. Each supplier receives the order from the order topic, checks its inventory, and then sends the items ordered to the queue named in the order message’sJMSReplyTo field. If it does not have enough in stock, the supplier sends what it has. The synchronous receive from the topic and the send to the queue take place in one JMS transaction.

    receiver = session.createConsumer(orderTopic);...inMessage = receiver.receive();if (inMessage instanceof MapMessage) {    orderMessage = (MapMessage) inMessage;}// Process messageMessageProducer producer =     session.createProducer((Queue) orderMessage.getJMSReplyTo());outMessage = session.createMapMessage();// Add content to messageproducer.send(outMessage);// Display message contentssession.commit();
  4. The vendor receives the replies from the suppliers from its confirmation queue and updates the state of the order. Messages are processed by an asynchronous message listener; this step shows the use of JMS transactions with a message listener.

    MapMessage component = (MapMessage) message;...orderNumber = component.getInt("VendorOrderNumber");Order order = Order.getOrder(orderNumber).processSubOrder(component);session.commit();
  5. When all outstanding replies are processed for a given order, the vendor message listener sends a message notifying the retailer whether it can fulfill the order.

    Queue replyQueue = (Queue) order.order.getJMSReplyTo();MessageProducer producer = session.createProducer(replyQueue);MapMessage retailerConfirmMessage = session.createMapMessage();// Format the messageproducer.send(retailerConfirmMessage);session.commit();
  6. The retailer receives the message from the vendor:

    inMessage = (MapMessage) orderConfirmReceiver.receive();

Figure 31-10 illustrates these steps.

Figure 31-10 Transactions: JMS Client Example

Diagram of steps in transaction example

The program contains five classes:Retailer,Vendor,GenericSupplier,VendorMessageListener, andOrder. The programalso contains amain method and a method that runs the threads oftheRetailer,Vendor, and two supplier classes.

All the messages use theMapMessage message type. Synchronous receives are used forall message reception except for the case of the vendor processing the repliesof the suppliers. These replies are processed asynchronously and demonstrate how to usetransactions within a message listener.

At random intervals, theVendor class throws an exception to simulate a databaseproblem and cause a rollback.

All classes exceptRetailer use transacted sessions.

The program uses three queues namedjms/AQueue,jms/BQueue, andjms/CQueue, and onetopic namedjms/OTopic.

Before you run the program, do the following:

  1. In a terminal window, go to the following directory:

    tut-install/javaeetutorial5/examples/jms/advanced/transactedexample/
  2. Create the necessary resources using the following command:

    ant create-resources

    This command creates three destination resources with the namesjms/AQueue,jms/BQueue, andjms/CQueue, all of typejavax.jms.Queue, and one destination resource with the namejms/OTopic, of typejavax.jms.Topic.

  3. To compile and package the program using NetBeans IDE, follow these steps:

    1. In NetBeans IDE, choose Open Project from the File menu.

    2. In the Open Project dialog, navigate totut-install/javaeetutorial5/examples/jms/advanced/.

    3. Select thetransactedexample folder.

    4. Select the Open as Main Project check box.

    5. Click Open Project.

    6. Right-click the project and choose Build.

    To compile and package the program using Ant, follow these steps:

    1. Go to the following directory:

      tut-install/javaeetutorial5/examples/jms/advanced/transactedexample/
    2. Type the following command:

      ant

To run the program using NetBeans IDE, follow these steps:

  1. Right-click thetransactedexample project and choose Properties.

  2. Select Run from the Categories tree.

  3. In the Arguments field, type a number that specifies the number of computers to order:

    3

  4. Click OK.

  5. Right-click the project and choose Run.

To run the program from the command line, follow these steps:

  1. Go to thedist directory:

    cd dist
  2. Use a command like the following to run the program. The argument specifies the number of computers to order:

    appclient -client transactedexample.jar 3

The output looks something like this:

Quantity to be ordered is 3Retailer: ordered 3 computer(s)Vendor: Retailer ordered 3 Computer(s)Vendor: ordered 3 monitor(s) and hard drive(s)Monitor Supplier: Vendor ordered 3 Monitor(s)Monitor Supplier: sent 3 Monitor(s)  Monitor Supplier: committed transaction  Vendor: committed transaction 1Hard Drive Supplier: Vendor ordered 3 Hard Drive(s)Hard Drive Supplier: sent 1 Hard Drive(s)Vendor: Completed processing for order 1  Hard Drive Supplier: committed transactionVendor: unable to send 3 computer(s)  Vendor: committed transaction 2Retailer: Order not filledRetailer: placing another orderRetailer: ordered 6 computer(s)Vendor: JMSException occurred: javax.jms.JMSException: Simulated database concurrent access exceptionjavax.jms.JMSException: Simulated database concurrent access exception        at TransactedExample$Vendor.run(Unknown Source)  Vendor: rolled back transaction 1Vendor: Retailer ordered 6 Computer(s)Vendor: ordered 6 monitor(s) and hard drive(s)Monitor Supplier: Vendor ordered 6 Monitor(s)Hard Drive Supplier: Vendor ordered 6 Hard Drive(s)Monitor Supplier: sent 6 Monitor(s)  Monitor Supplier: committed transactionHard Drive Supplier: sent 6 Hard Drive(s)  Hard Drive Supplier: committed transaction  Vendor: committed transaction 1Vendor: Completed processing for order 2Vendor: sent 6 computer(s)Retailer: Order filled  Vendor: committed transaction 2

After you run the program, you can delete the physical destinations and thedestination resources. Go to the directorytut-install/javaeetutorial5/examples/jms/advanced/transactedexample/ and type the following command:

ant delete-resources

Use the following command to remove the class and JAR files:

ant clean
PreviousContentsNext

Copyright © 2010, Oracle and/or its affiliates. All rights reserved.Legal Notices


[8]ページ先頭

©2009-2025 Movatter.jp