Quick Refresh : JMS

1.1   What Is Messaging? 
Messaging is a method of communication between software components or applications. A messaging system is a peer-to-peer facility: A messaging client can send messages to, and receive messages from, any other client. Each client connects to a messaging agent that provides facilities for creating, sending, receiving, and reading messages. 
Messaging enables distributed communication that is loosely coupled. A component sends a message to a destination, and the recipient can retrieve the message from the destination. However, the sender and the receiver do not have to be available at the same time in order to communicate. In fact, the sender does not need to know anything about the receiver; nor does the receiver need to know anything about the sender. The sender and the receiver need to know only what message format and what destination to use. In this respect, messaging differs from tightly coupled technologies, such as Remote Method Invocation (RMI), which require an application to know a remote application's methods. 
Messaging also differs from electronic mail (e-mail), which is a method of communication between people or between software applications and people. Messaging is used for communication between software applications or software components. 

1.2   What Is the JMS API? 
The Java Message Service is a Java API that allows applications to create, send, receive, and read messages. The JMS API defines a common set of interfaces and associated semantics that allow programs written in the Java programming language to communicate with other messaging implementations. 
The JMS API minimizes the set of concepts a programmer must learn to use messaging products but provides enough features to support sophisticated messaging applications. It also strives to maximize the portability of JMS applications across JMS providers in the same messaging domain. 
The JMS API enables communication that is not only loosely coupled but also 
· Asynchronous. A JMS provider can deliver messages to a client as they arrive; a client does not have to request messages in order to receive them. 
· Reliable. The JMS API can ensure that a message is delivered once and only once. Lower levels of reliability are available for applications that can afford to miss messages or to receive duplicate messages. 


1.3   When Can You Use the JMS API? 
An enterprise application provider is likely to choose a messaging API over a tightly coupled API, such as Remote Procedure Call (RPC), under the following circumstances. 
· The provider wants the components not to depend on information about other components' interfaces, so that components can be easily replaced. 
· The provider wants the application to run whether or not all components are up and running simultaneously. 
· The application business model allows a component to send information to another and to continue to operate without receiving an immediate response. 
For example, components of an enterprise application for an automobile manufacturer can use the JMS API in situations like these. 
· The inventory component can send a message to the factory component when the inventory level for a product goes below a certain level, so the factory can make more cars. 
· The factory component can send a message to the parts components so that the factory can assemble the parts it needs. 
· The parts components in turn can send messages to their own inventory and order components to update their inventories and to order new parts from suppliers. 
· Both the factory and the parts components can send messages to the accounting component to update their budget numbers. 
· The business can publish updated catalog items to its sales force. 
Using messaging for these tasks allows the various components to interact with one another efficiently, without tying up network or other resources. 
Manufacturing is only one example of how an enterprise can use the JMS API. Retail applications, financial services applications, health services applications, and many others can make use of messaging. 

2    Basic JMS API Concepts 

2.1   JMS API Architecture 
A JMS application is composed of the following parts. 
· A JMS provider is a messaging system that implements the JMS interfaces and provides administrative and control features. An implementation of the J2EE platform at release 1.3 includes a JMS provider. 
· JMS clients are the java programs or components, written to produce and consume messages. 
· Messages are the objects that communicate information between JMS clients. 
· Administered objects are preconfigured JMS objects created by an administrator for the use of clients. The two kinds of administered objects are destinations and connection factories, which are described in Section 3.1, "Administered Objects." 
· Native clients are programs that use a messaging product's native client API instead of the JMS API. An application first created before the JMS API became available and subsequently modified is likely to include both JMS and native clients. 
 Administrative tools allow you to bind destinations and connection factories into a Java Naming and Directory Interface (JNDI) API namespace. A JMS client can then look up the administered objects in the namespace and then establish a logical connection to the same objects through the JMS provider. 

2.2   Messaging Domains 

2.2.1   Point-to-Point Messaging Domain 
A point-to-point (PTP) product or application is built around the concept of message queues, senders, and receivers. Each message is addressed to a specific queue, and receiving clients extract messages from the queue(s) established to hold their messages. Queues retain all messages sent to them until the messages are consumed or until the messages expire. 
· Each message has only one consumer. 
· A sender and a receiver of a message have no timing dependencies. The receiver can fetch the message whether or not it was running when the client sent the message. 
· The receiver acknowledges the successful processing of a message. 
Use PTP messaging when every message you send must be processed successfully by one consumer. 

2.2.2   Publish/Subscribe Messaging Domain 
In a publish/subscribe (pub/sub) product or application, clients address messages to a topic. Publishers and subscribers are generally anonymous and may dynamically publish or subscribe to the content hierarchy. The system takes care of distributing the messages arriving from a topic's multiple publishers to its multiple subscribers. Topics retain messages only as long as it takes to distribute them to current subscribers. 
Pub/sub messaging has the following characteristics. 
· Each message may have multiple consumers. 
· Publishers and subscribers have a timing dependency. A client that subscribes to a topic can consume only messages published after the client has created a subscription, and the subscriber must continue to be active in order for it to consume messages. 
The JMS API relaxes this timing dependency to some extent by allowing clients to create durable subscriptions. Durable subscriptions can receive messages sent while the subscribers are not active. Durable subscriptions provide the flexibility and reliability of queues but still allow clients to send messages to many recipients. 
Use pub/sub messaging when each message can be processed by zero, one, or many consumers.  

2.3   Message Consumption 
Messaging products are inherently asynchronous in that no fundamental timing dependency exists between the production and the consumption of a message. However, the JMS Specification uses this term in a more precise sense. Messages can be consumed in either of two ways: 
· Synchronously. A subscriber or a receiver explicitly fetches the message from the destination by calling the receive method. The receive method can block until a message arrives or can time out if a message does not arrive within a specified time limit. 
· Asynchronously. A client can register a message listener with a consumer. A message listener is similar to an event listener. Whenever a message arrives at the destination, the JMS provider delivers the message by calling the listener's onMessage method, which acts on the contents of the message. 

3    The JMS API Programming Model 
The basic building blocks of a JMS application consist of 
· Administered objects: connection factories and destinations Connections 
· Sessions 
· Message producers 
· Message consumers 
· Messages 
Figure shows how all these objects fit together in a JMS client application. 

3.1   Administered Objects 
Two parts of a JMS application--destinations and connection factories--are best maintained administratively rather than programmatically. The technology underlying these objects is likely to be very different from one implementation of the JMS API to another. Therefore, the management of these objects belongs with other administrative tasks that vary from provider to provider. 
JMS clients access these objects through interfaces that are portable, so a client application can run with little or no change on more than one implementation of the JMS API. 
an administrator configures administered objects in a Java Naming and Directory Interface (JNDI) API namespace, and JMS clients then look them up, using the JNDI API. J2EE applications always use the JNDI API. 

3.1.1   Connection Factories 
A connection factory is the object a client uses to create a connection with a provider. A connection factory encapsulates a set of connection configuration parameters that has been defined by an administrator. Each connection factory is an instance of either the QueueConnectionFactory or the TopicConnectionFactory interface. 
you can use the default connection factory objects, named QueueConnectionFactory and TopicConnectionFactory, to create connections. 
At the beginning of a JMS client program, you usually perform a JNDI API lookup of the connection factory. For example, the following code fragment obtains an InitialContext object and uses it to look up the QueueConnectionFactory and the TopicConnectionFactory by name: 

Context ctx = new InitialContext();

QueueConnectionFactory queueConnectionFactory = 
  (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");

TopicConnectionFactory topicConnectionFactory = 
  (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");

Calling the InitialContext method with no parameters results in a search of the current classpath for a vendor-specific file named jndi.properties. This file indicates which JNDI API implementation to use and which namespace to use. 

3.1.2   Destinations 
A destination is the object a client uses to specify the target of messages it produces and the source of messages it consumes. In the PTP messaging domain, destinations are called queues.
In the pub/sub messaging domain, destinations are called topics.
A JMS application may use multiple queues and/or topics. 

In addition to looking up a connection factory, you usually look up a destination. 

the following line performs a JNDI lookup of topic named MyTopic and assigns it to a Topic object: 
Topic myTopic = (Topic) ctx.lookup("MyTopic");

The following line looks up a queue named MyQueue and assigns it to a Queue object: 
Queue myQueue = (Queue) ctx.lookup("MyQueue");

3.2   Connections 
A connection encapsulates a virtual connection with a JMS provider. A connection could represent an open TCP/IP socket between a client and a provider service daemon. You use a connection to create one or more sessions. 

connections come in two forms, implementing either the QueueConnection or the TopicConnection interface. 
For example, once you have a QueueConnectionFactory or a TopicConnectionFactory object, you can use it to create a connection: 
QueueConnection queueConnection =  queueConnectionFactory.createQueueConnection();

TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();

When an application completes, you need to close any connections that you have created. Failure to close a connection can cause resources not to be released by the JMS provider. Closing a connection also closes its sessions and their message producers and message consumers.
queueConnection.close();
topicConnection.close();

Before your application can consume messages, you must call the connection's start method.
If you want to stop message delivery temporarily without closing the connection, you call the stop method. 

3.3   Sessions 
A session is a single-threaded context for producing and consuming messages. You use sessions to create message producers, message consumers, and messages. Sessions serialize the execution of message listeners.
A session provides a transactional context with which to group a set of sends and receives into an atomic unit of work. 
Sessions come in two forms, implementing either the QueueSession or the TopicSession interface. 
For example: 
TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
The first argument means that the session is not transacted; the second means that the session automatically acknowledges messages when they have been received successfully. 

QueueSession queueSession = queueConnection.createQueueSession(true, 0);
Here, the first argument means that the session is transacted; the second indicates that message acknowledgment is not specified for transacted sessions. 

3.4   Message Producers 
A message producer is an object created by a session and is used for sending messages to a destination. The PTP form of a message producer implements the QueueSender interface. The pub/sub form implements the TopicPublisher interface. 
For example:
QueueSender queueSender = queueSession.createSender(myQueue);

TopicPublisher topicPublisher = topicSession.createPublisher(myTopic);
You can create an unidentified producer by specifying null as the argument to createSender or createPublisher. With an unidentified producer, you can wait to specify which destination to send the message to until you send or publish a message. 
Once you have created a message producer, you can use it to send messages. 

With a QueueSender, you use the send method: 
                                                                   queueSender.send(message);
With a TopicPublisher, you use the publish method: 
                                                                   topicPublisher.publish(message);
If you created an unidentified producer, use the overloaded send or publish method that specifies the destination as the first parameter. 

3.5   Message Consumers 
A message consumer is an object created by a session and is used for receiving messages sent to a destination. A message consumer allows a JMS client to register interest in a destination with a JMS provider. The JMS provider manages the delivery of messages from a destination to the registered consumers of the destination. 
The PTP form of message consumer implements the QueueReceiver interface. The pub/sub form implements the TopicSubscriber interface. 
For example: 
QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);

TopicSubscriber topicSubscriber = topicSession.createSubscriber(myTopic);

You use the TopicSession.createDurableSubscriber method to create a durable topic subscriber.

Once you have created a message consumer, it becomes active, and you can use it to receive messages. You can use the close method for a QueueReceiver or a TopicSubscriber to make the message consumer inactive. Message delivery does not begin until you start the connection you created by calling the start method.
With either a QueueReceiver or a TopicSubscriber, you use the receive method to consume a message synchronously. You can use this method at any time after you call the start method: 

queueConnection.start();
Message m = queueReceiver.receive();

topicConnection.start();
Message m = topicSubscriber.receive(1000); // time out after a second
To consume a message asynchronously, you use a message listener.

3.5.1   Message Listeners 
A message listener is an object that acts as an asynchronous event handler for messages. This object implements the MessageListener interface, which contains one method, onMessage. In the onMessage method, you define the actions to be taken when a message arrives. 
You register the message listener with a specific QueueReceiver or TopicSubscriber by using the setMessageListener method. For example, if you define a class named TopicListener that implements the MessageListener interface, you can register the message listener as follows: 

TopicListener topicListener = new TopicListener();
topicSubscriber.setMessageListener(topicListener);

After you register the message listener, you call the start method on the QueueConnection or the TopicConnection to begin message delivery. (If you call start before you register the message listener, you are likely to miss messages.) 
Once message delivery begins, the message consumer automatically calls the message listener's onMessage method whenever a message is delivered. The onMessage method takes one argument of type Message, which the method can cast to any of the other message types.

A message listener is not specific to a particular destination type. The same listener can obtain messages from either a queue or a topic, depending on whether the listener is set by a QueueReceiver or a TopicSubscriber object. A message listener does, however, usually expect a specific message type and format. Moreover, if it needs to reply to messages, a message listener must either assume a particular destination type or obtain the destination type of the message and create a producer for that destination type. 
Your onMessage method should handle all exceptions. It must not throw checked exceptions, and throwing a RuntimeException, though possible, is considered a programming error. 
The session used to create the message consumer serializes the execution of all message listeners registered with the session. At any time, only one of the session's message listeners is running. 
a message-driven bean is a special kind of message listener. 

3.5.2   Message Selectors 
If your messaging application needs to filter the messages it receives, you can use a JMS API message selector, which allows a message consumer to specify the messages it is interested in. Message selectors assign the work of filtering messages to the JMS provider rather than to the application. 
A message selector is a String that contains an expression. The syntax of the expression is based on a subset of the SQL92 conditional expression syntax. The createReceiver, createSubscriber, and createDurableSubscriber methods each have a form that allows us to specify a message selector as an argument when you create a message consumer. 
The message consumer then receives only messages whose headers and properties match the selector. A message selector cannot select messages on the basis of the content of the message body. 

3.6   Messages 
The ultimate purpose of a JMS application is to produce and to consume messages that can then be used by other software applications. JMS messages have a basic format that is simple but highly flexible, allowing you to create messages that match formats used by non-JMS applications on heterogeneous platforms. 
A JMS message has three parts
· A header 
· Properties (optional) 
· A body (optional) 

3.6.1   Message Headers 
A JMS message header contains a number of predefined fields that contain values that both clients and providers use to identify and to route messages. 
For example, every message has a unique identifier, represented in the header field JMSMessageID. The value of another header field, JMSDestination, represents the queue or the topic to which the message is sent. Other fields include a timestamp and a priority level
Each header field has associated setter and getter methods, which are documented in the description of the Message interface. Some header fields are intended to be set by a client, but many are set automatically by the send or the publish method, which overrides any client-set values. 
Table 3.1:    How JMS Message Header Field Values Are Set
Header Field                           Set By
JMSDestination                 send or publish method
JMSDeliveryMode              send or publish method
JMSExpiration             send or publish method
JMSPriority                     send or publish method
JMSMessageID                 send or publish method
JMSTimestamp                 send or publish method
JMSCorrelationID             Client
JMSReplyTo                     Client
JMSType                     Client
JMSRedelivered                JMS provider

3.6.2   Message Properties 
You can create and set properties for messages if you need values in addition to those provided by the header fields. You can use properties to provide compatibility with other messaging systems, or you can use them to create message selectors. 
The JMS API provides some predefined property names that a provider may support. The use of either predefined properties or user-defined properties is optional. 

3.6.3   Message Bodies 
The JMS API defines five message body formats, also called message types, which allow you to send and to receive data in many different forms and provide compatibility with existing messaging formats. Table 3.2 describes these message types. 
Table 3.2:    JMS Message Types
Message Type       Body Contains
TextMessage             A java.lang.String object (for example, the contents of an Extensible Markup Language file).
MapMessage       A set of name/value pairs, with names as String objects and values as primitive types in the Java programming language. 
                              The entries can be accessed sequentially by enumerator or randomly by name. The order of the entries is undefined.
BytesMessage           A stream of uninterpreted bytes. This message type is for literally encoding a body to match an existing message format.
StreamMessage       A stream of primitive values in the Java programming language, filled and read sequentially.
ObjectMessage       A Serializable object in the Java programming language.
Message                Nothing. Composed of header fields and properties only. This message type is useful when a message body is not required.

The JMS API provides methods for creating messages of each type and for filling in their contents. For example, to create and send a TextMessage to a queue, you might use the following statements: 

TextMessage message = queueSession.createTextMessage();
message.setText(msg_text);     // msg_text is a String
queueSender.send(message);

At the consuming end, a message arrives as a generic Message object and must be cast to the appropriate message type. You can use one or more getter methods to extract the message contents. The following code fragment uses the getText method: 

Message m = queueReceiver.receive();
if (m instanceof TextMessage) {
    TextMessage message = (TextMessage) m;
    System.out.println("Reading message: " + message.getText());
} else {
    // Handle error
}

3.7   Exception Handling 
The root class for exceptions thrown by JMS API methods is JMSException. Catching JMSException provides a generic way of handling all exceptions related to the JMS API. The JMSException class includes the following subclasses: 
· IllegalStateException 
· InvalidClientIDException 
· InvalidDestinationException 
· InvalidSelectorException 
· JMSSecurityException 
· MessageEOFException 
· MessageFormatException 
· MessageNotReadableException 
· MessageNotWriteableException 
· ResourceAllocationException 
· TransactionInProgressException 
· TransactionRolledBackException 

4    Writing Simple JMS Client Applications 
simple standalone programs that run outside the server as class files. The clients demonstrate the basic tasks that a JMS application must perform: 
· Creating a connection and a session 
· Creating message producers and consumers 
· Sending and receiving messages 
In a J2EE application, some of these tasks are performed, in whole or in part, by the EJB container.  

4.1   Setting Your Environment for Running Applications 
Before you can run the examples, you need to make sure that your environment is set appropriately. Table 4.1 shows how to set the environment variables needed to run J2EE applications on Microsoft Windows and UNIX® platforms. 
Table 4.1:    Environment Settings for Compiling and Running 
J2EE Applications
Platform Variable Name Values
Microsoft Windows  %JAVA_HOME%  Directory in which the JavaTM 2 SDK, Standard Edition, version 1.3.1, is installed
%J2EE_HOME% Directory in which the J2EE SDK 1.3.1 is installed, usually C:\j2sdkee1.3.1
%CLASSPATH% Include the following:
.;%J2EE_HOME%\lib\j2ee.jar;
%J2EE_HOME%\lib\locale
%PATH% Include %J2EE_HOME%\bin
UNIX
$JAVA_HOME Directory in which the Java 2 SDK, Standard Edition, version 1.3.1, is installed
$J2EE_HOME   Directory in which the J2EE SDK 1.3.1 is installed, usually $HOME/j2sdkee1.3.1
$CLASSPATH Include the following:
.:$J2EE_HOME/lib/j2ee.jar:
$J2EE_HOME/lib/locale
$PATH         Include $J2EE_HOME/bin

4.2   A Simple Point-to-Point Example 
This section describes the sending and receiving programs in a PTP example that uses the receive method to consume messages synchronously. 
The following sections describe the steps in creating and running the example: 
· Writing the PTP client programs 
· Compiling the PTP clients 
· Starting the JMS provider 
· Creating the JMS administered objects 
· Running the PTP clients 
· Deleting the queue 

4.2.1   Writing the PTP Client Programs 
The sending program, SimpleQueueSender.java, performs the following steps: 
1. Performs a Java Naming and Directory Interface (JNDI) API lookup of the QueueConnectionFactory and queue 
2. Creates a connection and a session 
3. Creates a QueueSender 
4. Creates a TextMessage 
5. Sends one or more messages to the queue 
6. Sends a control message to indicate the end of the message stream 
7. Closes the connection in a finally block, automatically closing the session and QueueSender 

The receiving program, SimpleQueueReceiver.java, performs the following steps: 
1. Performs a JNDI API lookup of the QueueConnectionFactory and queue 
2. Creates a connection and a session 
3. Creates a QueueReceiver 
4. Starts the connection, causing message delivery to begin 
5. Receives the messages sent to the queue until the end-of-message-stream control message is received 
6. Closes the connection in a finally block, automatically closing the session and QueueReceiver 
The receive method can be used in several ways to perform a synchronous receive. If you specify no arguments or an argument of 0, the method blocks indefinitely until a message arrives: 
Message m = queueReceiver.receive();

Message m = queueReceiver.receive(0);
For a simple client program, this may not matter. But if you do not want your program to consume system resources unnecessarily, use a timed synchronous receive. Do one of the following: 
· Call the receive method with a timeout argument greater than 0: 
· Message m = queueReceiver.receive(1); // 1 millisecond
· Call the receiveNoWait method, which receives a message only if one is available: 
· Message m = queueReceiver.receiveNoWait();
The SimpleQueueReceiver program uses an indefinite while loop to receive messages, calling receive with a timeout argument. Calling receiveNoWait would have the same effect. 

4.2.2   Compiling the PTP Clients 
To compile the PTP example, do the following. 
1. Make sure that you have set the environment variables shown in Table 4.1. 
2. At a command line prompt, compile the two source files: 
3. javac SimpleQueueSender.java
4. javac SimpleQueueReceiver.java

4.2.3   Starting the JMS Provider 
When you use the J2EE SDK 1.3.1, your JMS provider is the SDK. At another command line prompt, start the J2EE server as follows: 
j2ee -verbose
Wait until the server displays the message "J2EE server startup complete." 

4.2.4   Creating the JMS Administered Objects 
In the window in which you compiled the clients, use the j2eeadmin command to create a queue named MyQueue. The last argument tells the command what kind of destination to create. 
j2eeadmin -addJmsDestination MyQueue queue
To make sure that the queue has been created, use the following command: 
j2eeadmin -listJmsDestination
This example uses the default QueueConnectionFactory object supplied with the J2EE SDK 1.3.1. With a different J2EE product, you might need to create a connection factory yourself. 

4.2.5   Running the PTP Clients 
Run the clients as follows. 
1. Run the SimpleQueueSender program, sending three messages. You need to define a value for jms.properties. 
o On a Microsoft Windows system, type the following command: 
o java -Djms.properties=%J2EE_HOME%\config\jms_client.properties SimpleQueueSender MyQueue 3
o On a UNIX system, type the following command: 
o java -Djms.properties=$J2EE_HOME/config/jms_client.properties SimpleQueueSender MyQueue 3
The output of the program looks like this: 
Queue name is MyQueue
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
2. In the same window, run the SimpleQueueReceiver program, specifying the queue name. The java commands look like this:
o Microsoft Windows systems: 
o java -Djms.properties=%J2EE_HOME%\config\jms_client.properties SimpleQueueReceiver MyQueue
o UNIX systems: 
o java -Djms.properties=$J2EE_HOME/config/jms_client.properties SimpleQueueReceiver MyQueue
The output of the program looks like this: 
Queue name is MyQueue
Reading message: This is message 1
Reading message: This is message 2
Reading message: This is message 3
3. Now try running the programs in the opposite order. Start the SimpleQueueReceiver program. It displays the queue name and then appears to hang, waiting for messages.
4. In a different terminal window, run the SimpleQueueSender program. When the messages have been sent, the SimpleQueueReceiver program receives them and exits.

4.2.6   Deleting the Queue 
You can delete the queue you created as follows: 
j2eeadmin -removeJmsDestination MyQueue

4.3   A Simple Publish/Subscribe Example 
This section describes the publishing and subscribing programs in a pub/sub example that uses a message listener to consume messages asynchronously
The following sections describe the steps in creating and running the example: 
· Writing the pub/sub client programs 
· Compiling the pub/sub clients 
· Starting the JMS provider 
· Creating the JMS administered objects 
· Running the pub/sub clients 
· Deleting the topic and stopping the server 

4.3.1   Writing the Pub/Sub Client Programs 
The publishing program, SimpleTopicPublisher.java, performs the following steps: 
1. Performs a JNDI API lookup of the TopicConnectionFactory and topic 
2. Creates a connection and a session 
3. Creates a TopicPublisher 
4. Creates a TextMessage 
5. Publishes one or more messages to the topic 
6. Closes the connection, which automatically closes the session and TopicPublisher 

The receiving program, SimpleTopicSubscriber.java, performs the following steps: 
1. Performs a JNDI API lookup of the TopicConnectionFactory and topic 
2. Creates a connection and a session 
3. Creates a TopicSubscriber 
4. Creates an instance of the TextListener class and registers it as the message listener for the TopicSubscriber 
5. Starts the connection, causing message delivery to begin 
6. Listens for the messages published to the topic, stopping when the user enters the character q or Q 
7. Closes the connection, which automatically closes the session and TopicSubscriber 

The message listener, TextListener.java, follows these steps: 
1. When a message arrives, the onMessage method is called automatically. 
2. The onMessage method converts the incoming message to a TextMessage and displays its content. 

4.3.2   Compiling the Pub/Sub Clients 
To compile the pub/sub example, do the following. 
1. Make sure that you have set the environment variables shown in Table 4.1. 
2. Compile the programs and the message listener class: 
3. javac SimpleTopicPublisher.java
4. javac SimpleTopicSubscriber.java
5. javac TextListener.java

4.3.3   Starting the JMS Provider 
If you did not do so before, start the J2EE server in another terminal window: 
j2ee -verbose
Wait until the server displays the message "J2EE server startup complete." 

4.3.4   Creating the JMS Administered Objects 
In the window in which you compiled the clients, use the j2eeadmin command to create a topic named MyTopic. The last argument tells the command what kind of destination to create. 
j2eeadmin -addJmsDestination MyTopic topic
To verify that the queue has been created, use the following command: 
j2eeadmin -listJmsDestination
This example uses the default TopicConnectionFactory object supplied with the J2EE SDK 1.3.1. With a different J2EE product, you might need to create a connection factory. 

4.3.5   Running the Pub/Sub Clients 
Run the clients as follows. 
1. Run the SimpleTopicSubscriber program, specifying the topic name. You need to define a value for jms.properties. 
o On a Microsoft Windows system, type the following command: 
o java -Djms.properties=%J2EE_HOME%\config\jms_client.properties SimpleTopicSubscriber MyTopic
o On a UNIX system, type the following command: 
o java -Djms.properties=$J2EE_HOME/config/jms_client.properties SimpleTopicSubscriber MyTopic
The program displays the following lines and appears to hang: 
Topic name is MyTopic
To end program, enter Q or q, then <return>
2. In another terminal window, run the SimpleTopicPublisher program, publishing three messages. The java commands look like this: 
o Microsoft Windows systems: 
o java -Djms.properties=%J2EE_HOME%\config\jms_client.properties SimpleTopicPublisher MyTopic 3
o UNIX systems: 
o java -Djms.properties=$J2EE_HOME/config/jms_client.properties SimpleTopicPublisher MyTopic 3
The output of the program looks like this: 
Topic name is MyTopic
Publishing message: This is message 1
Publishing message: This is message 2
Publishing message: This is message 3
In the other window, the program displays the following: 
Reading message: This is message 1
Reading message: This is message 2
Reading message: This is message 3
Enter Q or q to stop the program. 

4.3.6   Deleting the Topic and Stopping the Server 
1. You can delete the topic you created as follows: 
2. j2eeadmin -removeJmsDestination MyTopic
You will use it again in Section 4.4.2, "Communicating Between a J2EE Server and a System Not Running a J2EE Server," however. 
3. If you wish, you can stop the J2EE server as well: 
4. j2ee -stop

4.4   Running JMS Client Programs on Multiple Systems 
JMS client programs can communicate with each other when they are running on different systems in a network. The systems must be visible to each other by name--the UNIX host name or the Microsoft Windows computer name--and must both be running the J2EE server. 
This section explains how to produce and to consume messages in two different situations: 
· When a J2EE server is running on both systems 
· When a J2EE server is running on only one system 

4.4.1   Communicating Between Two J2EE Servers 
Suppose that you want to run the SimpleQueueSender program on one system, mars, and the SimpleQueueReceiver program on another system, earth. To do so, follow these steps. 
1. Start the J2EE server on both systems. Enter the following command in a terminal window on each system: 
2. j2ee -verbose
3. On earth, create a QueueConnectionFactory object, using a command like the following: 
4. j2eeadmin -addJmsFactory jms/EarthQCF queue
5. On mars, create a connection factory with the same name that points to the server on earth. Enter, on one line, a command like the following: 
6. j2eeadmin -addJmsFactory jms/EarthQCF queue -props url=corbaname:iiop:earth:1050#earth
You can modify the script setup.bat or setup.sh, which you will use in Chapter 10, to automate this command. 
7. In each source program, change the line that looks up the connection factory so that it refers to the new connection factory: 
8. queueConnectionFactory = 
9.     (QueueConnectionFactory) jndiContext.lookup("jms/EarthQCF");
10. Recompile the programs; then run them by using the instructions in Section 4.2.5, "Running the PTP Clients." Because both connection factories have the same name, you can run either the sender or the receiver on either system. (Note: A bug in the JMS provider in the J2EE SDK may cause a runtime failure to create a connection to systems that use the Dynamic Host Configuration Protocol [DHCP] to obtain an IP address.) 
You can run the pub/sub example in the same way by creating a TopicConnectionFactory object on both systems. For an example showing how to deploy J2EE applications on two different systems, see Chapter 10. 

4.4.2   Communicating Between a J2EE Server and a System Not Running a J2EE Server 
In order for two standalone client programs to communicate, both must have the J2EE SDK installed locally. However, the J2EE server does not have to be running on both systems. Suppose that you want to run the SimpleTopicPublisher and the SimpleTopicSubscriber programs on two systems called earth and mars, as in Section 4.4.1, but that the J2EE server will be running only on earth. To specify the system running the server, you can either 
· Use the command line, which allows you to access different applications on different servers for maximum flexibility 
· Set a configurable property, which allows applications to run only on the system specified in the property 
When the server is running only on the remote system, you do not have to create a connection factory on the local system that refers to the remote system. 
The procedure for using the command line is as follows: 
1. Start the J2EE server on earth: 
2. j2ee -verbose
3. Set the J2EE_HOME environment variable and the classpath on mars so that they point to the J2EE SDK 1.3.1 installation on mars (see Table 4.1). 
4. To access a client program on a system running the server from a client program on a system not running the server, use the following option, where hostname is the name of the system running the J2EE server: 
5. -Dorg.omg.CORBA.ORBInitialHost=hostname
This option allows you to access the naming service on the remote system. For example, if the server is running on earth, use a command like the following to run the SimpleTopicSubscriber program on mars. Make sure that the destination you specify exists on the server running on earth. 
o On a Microsoft Windows system, type the following command: 
o java -Djms.properties=%J2EE_HOME%\config\jms_client.properties -Dorg.omg.CORBA.ORBInitialHost=earth SimpleTopicSubscriber MyTopic
o On a UNIX system, type the following command: 
o java -Djms.properties=$J2EE_HOME/config/jms_client.properties -Dorg.omg.CORBA.ORBInitialHost=earth SimpleTopicSubscriber MyTopic
If all the remote programs you need to access are on the same system, you can edit the file %J2EE_HOME%\config\orb.properties (on Microsoft Windows systems) or $J2EE_HOME/config/orb.properties (on UNIX systems) on the local system. The second line of this file looks like this: 
host=localhost
Change localhost to the name of the system on which the J2EE server is running--for example, earth: 
host=earth
You can now run the client program as before, but you do not need to specify the option -Dorg.omg.CORBA.ORBInitialHost. 

5    Creating Robust JMS Applications 
Many JMS applications cannot tolerate dropped or duplicate messages and require that every message be received once and only once. 
The most reliable way to produce a message is to send a PERSISTENT message within a transaction. JMS messages are PERSISTENT by default. A transaction is a unit of work into which you can group a series of operations, such as message sends and receives, so that the operations either all succeed or all fail. 
The most reliable way to consume a message is to do so within a transaction, either from a nontemporary queue--in the PTP messaging domain--or from a durable subscription--in the pub/sub messaging domain. For other applications, a lower level of reliability can reduce overhead and improve performance. You can send messages with varying priority levels and you can set them to expire after a certain length of time 
The JMS API provides several ways to achieve various kinds and degrees of reliability. 
Two categories: 
· Basic reliability mechanisms 
· Advanced reliability mechanisms 
The following sections describe these features as they apply to JMS clients

5.1   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. 

5.1.1   Controlling Message Acknowledgment 
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. 
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 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 depends on the value specified as the second argument of the createQueueSession or createTopicSession method. The three possible argument values are: 
· 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. 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 it redelivers a message, the JMS provider 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 but not acknowledged when a QueueSession 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 TopicSession with a durable TopicSubscriber. 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 higher-priority messages have arrived. For a nondurable TopicSubscriber, the provider may drop unacknowledged messages when its session is recovered. 

5.1.2   Specifying Message Persistence 
The JMS API supports two delivery modes for messages to specify whether messages are lost if the JMS provider fails. These delivery modes are fields of the DeliveryMode interface. 
· The PERSISTENT 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. 
· The NON_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 the setDeliveryMode method of the MessageProducer interface--the parent of the QueueSender and the TopicPublisher interfaces--to set the delivery mode for all messages sent by that producer. 
· You can use the long form of the send or the publish method to set the delivery mode for a specific message. The second argument sets the delivery mode. For example, the following publish call sets the delivery mode for message to NON_PERSISTENT: 
· topicPublisher.publish(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 is PERSISTENT. Using the NON_PERSISTENT delivery mode may improve performance and reduce storage overhead, but you should use it only if your application can afford to miss messages. 

5.1.3   Setting Message Priority Levels 
You can use message priority levels to instruct the JMS provider to deliver urgent messages first. You can set the priority level in either of two ways. 
· You can use the setPriority method of the MessageProducer interface to set the priority level for all messages sent by that producer. 
· You can use the long form of the send or the publish method to set the priority level for a specific message. The third argument sets the priority level. For example, the following publish call sets the priority level for message to 3: 
· topicPublisher.publish(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 not have to deliver messages in exact order of priority. 

5.1.4   Allowing Messages to Expire 
By default, a message never expires. If a message will become obsolete after a certain period, however, you may want to set an expiration time. You can do this in either of two ways. 
· You can use the setTimeToLive method of the MessageProducer interface to set a default expiration time for all messages sent by that producer. 
· You can use the long form of the send or the publish method to set an expiration time for a specific message. The fourth argument sets the expiration time in milliseconds. For example, the following publish call sets a time to live of 10 seconds: 
· topicPublisher.publish(message, DeliveryMode.NON_PERSISTENT, 3, 10000);
If the specified timeToLive value is 0, the message never expires
When the message is published, the specified timeToLive is added to the current time to give the expiration time. Any message not delivered before the specified expiration time is destroyed. The destruction of obsolete messages conserves storage and computing resources. 

5.1.5   Creating Temporary Destinations 
Normally, you create JMS destinations--queues and topics--administratively rather than programmatically. Your JMS or J2EE provider includes a tool that you use to create and to remove destinations, and it is common for destinations to be long lasting. 
The JMS API also enables you to create destinations--TemporaryQueue and TemporaryTopic objects--that last only for the duration of the connection in which they are created. 
You create these destinations dynamically, using the QueueSession.createTemporaryQueue and the TopicSession.createTemporaryTopic methods. 

5.2   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. 

5.2.1   Creating Durable Subscriptions 
To make sure that a pub/sub application receives all published messages, use PERSISTENT delivery mode for the publishers. In addition, use durable subscriptions for the subscribers. 
The TopicSession.createSubscriber method creates a nondurable subscriber. A nondurable subscriber can receive only messages that are published while it is active. 
At the cost of higher overhead, you can use the TopicSession.createDurableSubscriber method to create a durable subscriber. A durable subscription can have only one active subscriber at a time. 
A durable subscriber registers a durable subscription with a unique identity that is retained by the JMS provider. Subsequent subscriber objects with the same identity resume the subscription in the state in which it was left by the previous subscriber. If a durable subscription has no active subscriber, the JMS provider retains the subscription's messages until they are received by the subscription or until 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 the j2eeadmin command. 
For example: 
j2eeadmin -addJmsFactory MY_CON_FAC topic -props clientID=MyID
After using this connection factory to create the connection and the session, you call the createDurableSubscriber method with two arguments--the topic and a string that specifies the name of the subscription: 
String subName = "MySub";
TopicSubscriber topicSubscriber = 
  topicSession.createDurableSubscriber(myTopic, subName);
The subscriber becomes active after you start the TopicConnection. Later on, you might close the TopicSubscriber: 
topicSubscriber.close();

The JMS provider stores the messages published to the topic, as it would store messages sent to a queue. If the program or another application calls createDurableSubscriber with the same connection factory and its client ID, the same topic, and the same subscription name, the subscription is reactivated, and the JMS provider delivers the messages that were published while the subscriber was inactive. 
To delete a durable subscription, first close the subscriber, and then use the unsubscribe method, with the subscription name as the argument: 
topicSubscriber.close();
topicSession.unsubscribe("MySub");
The unsubscribe method deletes the state that the provider maintains for the subscriber. 
Figure 5.1 and Figure 5.2 show the difference between a nondurable and a durable subscriber. With an ordinary, nondurable, subscriber, the subscriber and the subscription are coterminous and, in effect, identical. When a subscriber is closed, the subscription ends as well. Here, create stands for a call to TopicSession.createSubscriber, and close stands for a call to TopicSubscriber.close. Any messages published to the topic between the time of the first close and the time of the second create are not consumed by the subscriber. In Figure 5.1, the subscriber consumes messages M1, M2, M5, and M6, but messages M3 and M4 are lost. 
Figure 5.1   Nondurable Subscribers and Subscriptions
With a durable subscriber, the subscriber can be closed and recreated, but the subscription continues to exist and to hold messages until the application calls the unsubscribe method. In Figure 5.2, create stands for a call to TopicSession.createDurableSubscriber, close stands for a call to TopicSubscriber.close, and unsubscribe stands for a call to TopicSession.unsubscribe. Messages published while the subscriber is closed are received when the subscriber is created again. So even though messages M2, M4, and M5 arrive while the subscriber is closed, they are not lost. 
Figure 5.2   A Durable Subscriber and Subscription
See Chapter 8 for an example of a J2EE application that uses durable subscriptions. See Section A.1, "Durable Subscriptions," for an example of a client application that uses durable subscriptions. 

5.2.2   Using JMS API Local Transactions 
You can group a series of operations together into an atomic unit of work called a transaction. If any one of the operations fails, the transaction can be rolled back, and the operations can be attempted again from the beginning. If all the operations succeed, the transaction can be committed. 
In a JMS client, you can use local transactions to group message sends and receives. The JMS API Session interface provides commit and rollback methods that you can use in a JMS client. A transaction commit means that all produced messages are sent and all consumed messages are acknowledged. A transaction rollback means that all produced messages are destroyed and all consumed messages are recovered and redelivered unless they have expired (see Section 5.1.4, "Allowing Messages to Expire"). 
A transacted session is always involved in a transaction. As soon as the commit or the rollback method is called, one transaction ends and another transaction begins. Closing a transacted session rolls back its transaction in progress, including any pending sends and receives. 
In an Enterprise JavaBeansTM component, you cannot use the Session.commit and Session.rollback methods. Instead, you use distributed transactions, which are described in Chapter 6. 
You can combine several sends and receives in a single JMS API local transaction. If you do so, you need to be careful about the order of the operations. You will have no problems if the transaction consists of all sends or all receives or if the receives come before the sends. But if you try to use a request-reply mechanism, whereby you send a message and then try to receive a reply to the sent message in the same transaction, the program will hang, because the send cannot take place until the transaction is committed. Because a message sent during a transaction is not actually sent until the transaction is committed, the transaction cannot contain any receives that depend on that message's having been sent. 
It is also important to note that the production and the consumption of a message cannot both be part of the same transaction. The reason is that the transactions take place between the clients and the JMS provider, which intervenes between the production and the consumption of the message. Figure 5.3 illustrates this interaction. 
The sending of one or more messages to a queue by Client 1 can form a single transaction, because it forms a single set of interactions with the JMS provider. Similarly, the receiving of one or more messages from the queue by Client 2 also forms a single transaction. But because the two clients have no direct interaction, no transactions take place between them. Another way of putting this is that the act of producing and/or consuming messages in a session can be transactional, but the act of producing and consuming a specific message across different sessions cannot be transactional. 
This is the fundamental difference between messaging and synchronized processing. Instead of tightly coupling the sending and receiving of data, message producers and consumers use an alternative approach to reliability, one that is built on a JMS provider's ability to supply a once-and-only-once message delivery guarantee. 
When you create a session, you specify whether it is transacted. The first argument to the createQueueSession and the createTopicSession methods is a boolean value. A value of true means that the session is transacted; a value of false means that it is not transacted. The second argument to these methods is the acknowledgment mode, which is relevant only to nontransacted sessions (see Section 5.1.1, "Controlling Message Acknowledgment"). If the session is transacted, the second argument is ignored, so it is a good idea to specify 0 to make the meaning of your code clear. For example: 
topicSession = topicConnection.createTopicSession(true, 0);
Because the commit and the rollback methods for local transactions are associated with the session, you cannot combine queue and topic operations in a single transaction. For example, you cannot receive a message from a queue and then publish a related message to a topic in the same transaction, because the QueueReceiver and the TopicPublisher are associated with a QueueSession and a TopicSession, respectively. You can, however, receive from one queue and send to another queue in the same transaction, assuming that you use the same QueueSession to create the QueueReceiver and the QueueSender. You can pass a client program's session to a message listener's constructor function and use it to create a message producer, so that you can use the same session for receives and sends in asynchronous message consumers. For an example of the use of JMS API local transactions, see Section A.2, "Transactions." 

6    Using the JMS API in a J2EE Application

6.1   Using Enterprise Beans to Produce and to Synchronously Receive Messages
A J2EE application that produces messages or synchronously receives them may use any kind of enterprise bean to perform these operations. The example in Chapter 8 uses a stateless session bean to publish messages to a topic.
Because a blocking synchronous receive ties up server resources, it is not a good programming practice to use such a receive call in an enterprise bean. Instead, use a timed synchronous receive, or use a message-driven bean to receive messages asynchronously. For details about blocking and timed synchronous receives, see Section 4.2.1, "Writing the PTP Client Programs."
Using the JMS API in a J2EE application is in many ways similar to using it in a standalone client. The main differences are in administered objects, resource management, and transactions.

6.1.1   Administered Objects

The Platform Specification recommends that you use java:comp/env/jms as the environment subcontext for Java Naming and Directory Interface (JNDI) API lookups of connection factories and destinations. With the J2EE SDK 1.3.1, you use the Application Deployment Tool, commonly known as the deploytool, to specify JNDI API names that correspond to those in your source code.
Instead of looking up a JMS API connection factory or destination each time it is used in a method, it is recommended that you look up these instances once in the enterprise bean's ejbCreate method and cache them for the lifetime of the enterprise bean.

6.1.2   Resource Management

A JMS API resource is a JMS API connection or a JMS API session. In general, it is important to release JMS resources when they are no longer being used. Here are some useful practices to follow.

  •  If you wish to maintain a JMS API resource only for the life span of a business method, it is a good idea to close the resource in a finally block within the method.
  •  If you would like to maintain a JMS API resource for the life span of an enterprise bean instance, it is a good idea to use the component's ejbCreate method to create the resource and to use the component's ejbRemove method to close the resource. If you use a stateful session bean or an entity bean and you wish to maintain the JMS API resource in a cached state, you must close the resource in the ejbPassivate method and set its value to null, and you must create it again in the ejbActivate method.

6.1.3   Transactions

Instead of using local transactions, you use the deploytool to specify container-managed transactions for bean methods that perform sends and receives, allowing the EJBTM container to handle transaction demarcation. (You can use bean-managed transactions and the javax.transaction.UserTransaction interface's transaction demarcation methods, but you should do so only if your application has special requirements and you are an expert in using transactions. Usually, container-managed transactions produce the most efficient and correct behavior.)

6.2   Using Message-Driven Beans

Message-driven bean allows asynchronous processing of JMS messages . Session beans and entity beans allow you to send messages and to receive them synchronously but not asynchronously.
A message-driven bean is a message listener that can reliably consume messages from a queue or a durable subscription. a message-driven bean contains an onMessage method that is called automatically when a message arrives. a message-driven bean class may implement helper methods invoked by the onMessage method to aid in message processing.
A message-driven bean differs from a standalone client's message listener in five ways, however.
  •  The EJB container automatically performs several setup tasks that a standalone client has to do:
    •  Creating a message consumer (a QueueReceiver or a TopicSubscriber) to receive the messages. You associate the message-driven bean with a destination and a connection factory at deployment time. If you want to specify a durable subscription or use a message selector, you do this at deployment time also.
    •  Registering the message listener. (You must not call setMessageListener.)
    •  Specifying a message acknowledgment mode. 
  •  Your bean class must implement the javax.ejb.MessageDrivenBean and the javax.jms.MessageListener interfaces.
  •  Your bean class must implement the ejbCreate method in addition to the onMessage method.
                          public void ejbCreate() {}
    
    If your message-driven bean produces messages or does synchronous receives from another destination, you use its ejbCreate method to look up JMS API connection factories and destinations and to create the JMS API connection.
  •  Your bean class must implement an ejbRemove method. 
                          public void ejbRemove() {}
    
    If you used the message-driven bean's ejbCreate method to create the JMS API connection, you ordinarily use the ejbRemove method to close the connection.
  •  Your bean class must implement the setMessageDrivenContext method. A MessageDrivenContext object provides some additional methods that you can use for transaction management. The method has the following signature:
    public void setMessageDrivenContext(MessageDrivenContext mdc) {}
    
The main difference between a message-driven bean and other enterprise beans is that a message-driven bean has no home or remote interface. Rather, it has only a bean class.
A message-driven bean is similar in some ways to a stateless session bean: its instances are relatively short-lived and retain no state for a specific client. The instance variables of the message-driven bean instance can contain some state across the handling of client messages: for example, a JMS API connection, an open database connection, or an object reference to an enterprise bean object. Like a stateless session bean, a message-driven bean can have many interchangeable instances running at the same time. The container can pool these instances to allow streams of messages to be processed concurrently. Concurrency can affect the order in which messages are delivered, so you should write your application to handle messages that arrive out of sequence.
To create a new instance of a message-driven bean, the container instantiates the bean and then
  1.  Calls the setMessageDrivenContext method to pass the context object to the instance
  2.  Calls the instance's ejbCreate method
Figure shows the life cycle of a message-driven bean.

6.3   Managing Distributed Transactions

JMS client applications use JMS API local transactions which allow the grouping of sends and receives within a specific JMS session. J2EE applications commonly use distributed transactions in order to ensure the integrity of accesses to external resources. For example, distributed transactions allow multiple applications to perform atomic updates on the same database, and they allow a single application to perform atomic updates on multiple databases.
In a J2EE application that uses the JMS API, you can use transactions to combine message sends or receives with database updates and other resource manager operations. You can access resources from multiple application components within a single transaction. For example, a servlet may start a transaction, access multiple databases, invoke an enterprise bean that sends a JMS message, invoke another enterprise bean that modifies an EIS system using the Connector architecture, and finally commit the transaction. Your application cannot, however, both send a JMS message and receive a reply to it within the same transaction; 
Distributed transactions can be either of two kinds:
  •  Container-managed transactions. The EJB container controls the integrity of your transactions without your having to call commit or rollback. Container-managed transactions are recommended for J2EE applications that use the JMS API. You can specify appropriate transaction attributes for your enterprise bean methods.Use the Required transaction attribute to ensure that a method is always part of a transaction. If a transaction is in progress when the method is called, the method will be part of that transaction; if not, a new transaction will be started before the method is called and will be committed when the method returns.
  •  Bean-managed transactions. You can use these in conjunction with the javax.transaction.UserTransaction interface, which provides its own commit and rollback methods that you can use to delimit transaction boundaries.
To ensure that all messages are received and handled within the context of a transaction, use container-managed transactions and specify the Required transaction attribute for the onMessage method. This means that a new transaction will be started before the method is called and will be committed when the method returns. An onMessage call is always a separate transaction, because there is never a transaction in progress when the method is called.
When you use container-managed transactions, you can call the following MessageDrivenContext methods:
  •  setRollbackOnly. Use this method for error handling. If an exception occurs, setRollbackOnly marks the current transaction so that the only possible outcome of the transaction is a rollback.
  •  getRollbackOnly. Use this method to test whether the current transaction has been marked for rollback.
If you use bean-managed transactions, the delivery of a message to the onMessage method takes place outside of the distributed transaction context. The transaction begins when you call theUserTransaction.begin method within the onMessage method and ends when you call UserTransaction.commit. If you call UserTransaction.rollback, the message is not redelivered, whereas calling setRollbackOnly for container-managed transactions does cause a message to be redelivered.
Neither the JMS API Specification nor the Enterprise JavaBeansTM Specification (available from http://java.sun.com/products/ejb/) specifies how to handle calls to JMS API methods outside transaction boundaries. The Enterprise JavaBeans Specification does state that the EJB container is responsible for acknowledging a message that is successfully processed by the onMessage method of a message-driven bean that uses bean-managed transactions. Using bean-managed transactions allows you to process the message by using more than one transaction or to have some parts of the message processing take place outside a transaction context. In most cases, however, container-managed transactions provide greater reliability and are therefore preferable.
When you create a session in an enterprise bean, the container ignores the arguments you specify, because it manages all transactional properties for enterprise beans. It is still a good idea to specify arguments of true and 0 to the createQueueSession or the createTopicSession method to make this situation clear:
queueSession = queueConnection.createQueueSession(true, 0);
When you use container-managed transactions, you usually specify the Required transaction attribute for your enterprise bean's business methods.
You do not specify a message acknowledgment mode when you create a message-driven bean that uses container-managed transactions. The container acknowledges the message automatically when it commits the transaction.
If a message-driven bean uses bean-managed transactions, the message receipt cannot be part of the bean-managed transaction, so the container acknowledges the message outside of the transaction. When you package a message-driven bean using the deploytool, the Message-Driven Bean Settings dialog box allows you to specify the acknowledgment mode, which can be either AUTO_ACKNOWLEDGE (the default) or DUPS_OK_ACKNOWLEDGE.
If the onMessage method throws a RuntimeException, the container does not acknowledge processing the message. In that case, the JMS provider will redeliver the unacknowledged message in the future.

6.4   Using the JMS API with Application Clients and Web Components

An application client can use the JMS API in much the same way a standalone client program does. It can produce messages, and it can consume messages by using either synchronous receives or message listeners. See Chapter 7 for an example of an application client that produces messages; see Chapter 9 and Chapter 10 for examples of using application clients to produce and to consume messages.
The J2EE Platform Specification does not define how Web components implement a JMS provider. In the J2EE SDK 1.3.1, a Web component--one that uses either the Java Servlet API or JavaServerPagesTM (JSPTM) technology--may send messages and consume them synchronously but may not consume them asynchronously.
Because a blocking synchronous receive ties up server resources, it is not a good programming practice to use such a receive call in a Web component. Instead, use a timed synchronous receive. For details about blocking and timed synchronous receives.

=================
Q:What is the use of BytesMessage?
A: BytesMessage contains an array of primitive bytes in it's payload. Thus it can be used for transfer of data between two applications in their native format which may not be compatible with other Message types. It is also useful where JMS is used purely as a transport between two systems and the message payload is opaque to the JMS client. Whenever you store any primitive type, it is converted into it's byte representation and then stored in the payload. There is no boundary line between the different data types stored. Thus you can even read a long as short. This would result in erroneous data and hence it is advisable that the payload be read in the same order and using the same type in which it was created by the sender.

Q:What is the use of StreamMessage?
A: StreamMessage carries a stream of Java primitive types as it's payload. It contains some conveient methods for reading the data stored in the payload. However StreamMessage prevents reading a long value as short, something that is allwed in case of BytesMessage. This is so because the StreamMessage also writes the type information alonwgith the value of the primitive type and enforces a set of strict conversion rules which actually prevents reading of one primitive type as another.
 
Q:What is the use of TextMessage?
A: TextMessage contains instance of java.lang.String as it's payload. Thus it is very useful for exchanging textual data. It can also be used for exchanging complex character data such as an XML document.

Q:What is the use of ObjectMessage?
A: ObjectMessage contains a Serializable java object as it's payload. Thus it allows exchange of Java objects between applications. This in itself mandates that both the applications be Java applications. The consumer of the message must typecast the object received to it's appropriate type. Thus the consumer should before hand know the actual type of the object sent by the sender. Wrong type casting would result in ClassCastException. Moreover the class definition of the object set in the payload should be available on both the machine, the sender as well as the consumer. If the class definition is not available in the consumer machine, an attempt to type cast would result in ClassNotFoundException. Some of the MOMs might support dynamic loading of the desired class over the network, but the JMS specification does not mandate this behavior and would be a value added service if provided by your vendor. And relying on any such vendor specific functionality would hamper the portability of your application. Most of the time the class need to be put in the classpath of both, the sender and the consumer, manually by the developer.

Q: What is the use of MapMessage?
A: A MapMessage carries name-value pair as it's payload. Thus it's payload is similar to the java.util.Properties object of Java. The values can be Java primitives or their wrappers.

Q: What is the difference between BytesMessage and StreamMessage??
A: BytesMessage stores the primitive data types by converting them to their byte representation. Thus the message is one contiguous stream of bytes. While the StreamMessage maintains a boundary between the different data types stored because it also stores the type information along with the value of the primitive being stored. BytesMessage allows data to be read using any type. Thus even if your payload contains a long value, you can invoke a method to read a short and it will return you something. It will not give you a semantically correct data but the call will succeed in reading the first two bytes of data. This is strictly prohibited in the StreamMessage. It maintains the type information of the data being stored and enforces strict conversion rules on the data being read.

Q:Can two different JMS services talk to each other? For instance, if A and B are two different JMS providers, can Provider A send messages directly to Provider B? If not, then can a subscriber to Provider A act as a publisher to Provider B?
A: The answers are no to the first question and yes to the second. The JMS specification does not require that one JMS provider be able to send messages directly to another provider. However, the specification does require that a JMS client must be able to accept a message created by a different JMS provider, so a message received by a subscriber to Provider A can then be published to Provider B. One caveat is that the publisher to Provider B is not required to handle a JMSReplyTo header that refers to a destination that is specific to Provider A.

Q) What encryption options are there for sending messages through JMS?
A) Encryption is not handled by the JMS specification. It is left to the JMS provider to implement and provide encryption and decryption of messages. These days, Progress Software’s SonicMQ is a leading JMS provider and they have a robust encryption mechanism called Quality of Protection. They also provide an SSL-related feature, which also has build in encryption.

Q) Does Tomcat support JMS (Java Messaging Service)?
A) Tomcat is just a servlet container, not an EJB container nor an application server, so it does not contains any JMS basic support.
However, there’s nothing stopping you from using another JMS provider.

Q) Is it possible to send email messages using JMS?
A) JMS has no inherent support for email operations.

Q)Is there any relationship between javax.jms.Message and javax.mail.Message?
A)There is no direct relationship between javax.mail.Message and javax.jms.Message. If your requirement is to map (correlate) them, here is what you can do:
From JMS domain to JavaMail domain (a javax.jms.Message is received):
A JMS topic/queue can be associated with one or many e-mail id(s).
The JMS Message Header can be mapped to ‘custom’ JavaMail Message Header.
The JMS Message Body can be associated with the JavaMail Message body.
A JavaMail client application should be able to process these ‘custom’ headers and the content of the message body.
From JavaMail domain to JMS domain (a javax.mail.Message is received):
An e-mail id can be associated with one or more JMS topics/queues.
The JavaMail Message Header can be mapped to ‘custom’ JMS Message Header.
The JavaMail Message Body can be associated with the JMS Message body.
The JMS client application should be able to process these ‘custom’ headers and the content of the message body.
In a simple application that I tried, I removed the ‘custom’ header scenario and just forwarded the contents of the message (text message), which worked without any problems.Try using SonicMQ bridges, which already has something like that.

Q) Is it possible to acknowledge individual messages on a queue without affecting previously received, but as yet unacknowledged, messages?
A) If you acknowledge a message, all previously received messages will also be acknowledged. From the javax.jms.Message Javadoc, the acknowledge method will "Acknowledge this and all previous messages received." 
So the answer to your question is no, if what you meant by "affecting" is not-yet acknowledged. 
I suggest an alternative. You should look at javax.jms.QueueBrowser to review queued messages. QueueBrowser has getEnumeration, which "Gets an enumeration for browsing the current queue messages in the order they would be received".

Comments

Popular posts from this blog

Ramoji Film City, Hyderabad, India

Ashtavinayak Temples | 8 Ganpati Temples of Maharashtra | Details Travel Reviews

Quick Refresh : Hibernate