Developing a JMS program
In this article we’ll learn on how to develop a JMS program. The step by step explanation is listed below.
A typical JMS program goes through the following steps to begin producing and consuming messages.
1. Look up a ConnectionFactory through JNDI.
2. Look up one or more Destinations through JNDI.
3. Use the ConnectionFactory to create a Connection.
4. Use the Connection to create one or more Sessions.
5. Use a Session and a Destination to create the required MessageProducers and MessageConsumers.
6. Start the Connection.
At this point, messages can begin to flow and the application can receive, process, and send messages, as required. In later sections, we’lldevelop JMS programs and you’llget to see this setup in detail.
At the heart of a messaging system are, of course, messages. JMS provides several message types for different types of content, but all messages derive from the Message interface.
A Message is divided into three constituent parts:
* The header is a standard set of fields that are used by both clients and providers to identify and route messages.
* Properties provide a facility for adding optional header fields to a message. If your application needs to categorize or classify a message in a way not provided by the standard header fields, you can add a property to the message to accomplish that categorization or classification. set<Type>Property(…) and
Property(…) methods are provided to set and get properties of a variety of Java types, including Object. JMS defines a standard set of properties that are optional for providers to supply.
* The body of the message contains the content to be delivered to a receiving application. Each message interface is specialized for the type of content it supports.
The following list gives the name of each header field of Message, its corresponding Java type, and a description of the field.
* JMSMessageID — type string
Uniquely identifies each message that is sent by a provider. This field is set by the provider during the send process; clients cannot determine the JMSMessageID for a message until after it has been sent.
* JMSDestination — type Destination
The Destination to which the message was sent; set by the provider during the send process.
* JMSDeliveryMode — type int
Contains the value DeliveryMode.PERSISTENT or
DeliveryMode.NON_PERSISTENT. A persistent message is delivered “once and only once”; a non-persistent message is delivered “at most once.” Be aware that “at most once” includes not being delivered at all. A non-persistent message may be lost by a provider during application or system failure. Extra care will be taken to assure that a persistent message is not affected by failures. There is often considerable overhead in sending persistent messages, and the trade-offs between reliability and performance must be carefully considered when deciding the delivery mode of a message.
* JMSTimestamp — type long
The time that the message was delivered to a provider to be sent; set by the provider during the send process.
* JMSExpiration — type long
The time when a message should expire. This value is calculated during the send process as the sum of the time-to-live value of the sending method and the current time. Expired messages should not be delivered by the provider. A value of 0 indicates that the message will not expire.
* JMSPriority — type int
The priority of the message; set by the provider during the send process. A priority of 0 is the lowest priority; a priority of 9 is the highest priority.
* JMSCorrelationID — type string
Typically used to link a response message with a request message; set by the JMS program sending the message. A JMS program responding to a message from another JMS program would copy the JMSMessageID of the message it is responding to into this field, so that the requesting program could correlate the response to the particular request that it made.
* JMSReplyTo — type Destination
Used by a requesting program to indicate where a reply message should be sent; set by the JMS program sending the message.
* JMSType — type string
Can be used by a JMS program to indicate the type of the message. Some providers maintain a repository of message types and will use this field to reference the type definition in the repository; in this case, the JMS program should not use this field.
* JMSRedelivered — type boolean
Indicates that the message was delivered earlier to the JMS program, but that the program did not acknowledge its receipt; set by the provider during receive processing.
The following list gives the name of each standard property of Message, its corresponding Java type, and a description of the property. Support for standard properties by a provider is optional. JMS reserves the “JMSX” property name for these and future JMS-defined properties.
* JMSXUserID — type string
Identity of the user sending the message.
* JMSXApplID — type string
Identity of the application sending the message.
* JMSXDeliveryCount — type int
Number of times delivery of the message has been attempted.
* JMSXGroupID — type string
Identity of the message group to which this message belongs.
* JMSXGroupSeq — type int
Sequence number of this message within the message group.
* JMSXProducerTXID — type string
Identity of the transaction within which this message was produced.
* JMSXConsumerTXID — type string
Identity of the transaction within which this message was consumed.
* JMSXRcvTimestamp — type long
The time JMS delivered the message to the consumer.
* JMSXState — type int
Used by providers that maintain a message warehouse of messages; generally not of interest to JMS producers or consumers.
Reserved for provider-specific properties.
There are five forms of message body, and each form is defined by an interface that extends Message. These interfaces are:
* StreamMessage: Contains a stream of Java primitive values that are filled and read sequentially using standard stream operations.
* MapMessage: Contains a set of name-value pairs; the names are of type string and the values are Java primitives.
* TextMessage: Contains a String.
* ObjectMessage: Contains a Serializable Java object; JDK 1.2 collection classes can be used.
* BytesMessage: Contains a stream of uninterpreted bytes; allows encoding a body to match an existing message format.
Each provider supplies classes specific to its product that implement these interfaces. It is important to note that the JMS specification mandates that providers must be prepared to accept and handle a Message object that is not an instance of one of its own Message classes.
While these “alien” objects may not be handled by a provider as efficiently as one of the provider’sown implementations, they must be handled to ensure interoperability of all JMS providers.
A JMS transaction groups a set of produced messages and a set of consumed messages into an atomic unit of work. If an error occurs during a transaction, the production and consumption of messages that occurred before the error can be “undone.”
Session objects control transactions and a Session may be denoted as transacted when it is created. A transacted Session always has a current transaction, that is, there is no begin(); commit() and rollback() end one transaction and automatically begin another.
Distributed transactions may be supported by the Java Transaction API (JTA) XAResource API, though this is optional for providers.
Acknowledgement is the mechanism whereby a provider is informed that a message has been successfully received.
If the Session receiving the message is transacted, acknowledgement is handled automatically. If the Session is not transacted, then the type of acknowledgement is determined when the Session is created.
There are three types of acknowledgement:
* Session.DUPS_OK_ACKNOWLEDGE: Lazy acknowledgement of message delivery; reduces overhead by minimizing work done to prevent duplicates; should only be used if duplicate messages are expected and can be handled.
* Session.AUTO_ACKNOWLEDGE: Message delivery is automatically acknowledged upon completion of the method that receives the message.
* Session.CLIENT_ACKNOWLEDGE: Message delivery is explicitly acknowledged by calling the acknowledge() method on the Message.
JMS provides a mechanism, called a message selector, for a JMS program to filter and categorize the messages it receives.
The message selector is a String that contains an expression whose syntax is based on a subset of SQL92. The message selector is evaluated when an attempt is made to receive a message, and only messages that match the selection criteria of the selector are made available to the program.
Selection is based on matches to header fields and properties; body values cannot be used for selection. The syntax for message selectors is provided in detail in the JMS specification.
JMS and XML
The authors of JMS included the TextMessage message type on the presumption that String messages will be used extensively.
Their reasoning is that XML will be a popular, if not the most popular, means of representing the content of messages. A portable transport mechanism (JMS) coupled with a portable data representation (XML) is proving to be a powerful tool in enterprise application integration (EAI) and other areas of data exchange.
JMS and J2EE
J2EE version 1.2 requires compliant application servers to have the JMS API present, but does not mandate the presence of a JMS provider.
J2EE version 1.3 will require application servers to supply a JMS provider.
Another important development in JMS capabilities is the message-driven bean of the EJB 2.0 specification , which will add asynchronous notification abilities to Enterprise JavaBeans containers. A message-driven bean, which will implement the MessageListener interface (see MessageListener on page 16), will be invoked by the EJB container on the arrival of a message at a destination designated at deployment time. The message-driven bean will contain the business logic to process the message, including, if needed, the invoking of other enterprise beans.