A message consists of the following parts:
A header containing identifying and routing information
Optional properties that can be used to convey additional identifying information beyond that contained in the header
A body containing the actual content of the message
The following sections discuss each of these in greater detail.
Every message must have a header containing identifying and routing information. The header consists of a set of standard fields, which are defined in the Java Message Service Specification and summarized in Table 2–4. Some of these are set automatically by Message Queue in the course of producing and delivering a message, some depend on settings specified when a message producer sends a message, and others are set by the client on a message-by-message basis.
Table 2–4 Message Header Fields
Name |
Description |
---|---|
Message identifier |
|
Destination to which message is sent |
|
Destination to which to reply |
|
Link to related message |
|
Delivery mode (persistent or nonpersistent) |
|
Priority level |
|
Time of transmission |
|
Expiration time |
|
Message type |
|
Has message been delivered before? |
The JMS Message interface defines methods for setting the value of each header field: for instance,
outMsg.setJMSReplyTo(replyDest);
Table 2–5 lists all of the available header specification methods.
Table 2–5 Message Header Specification Methods
Name |
Description |
---|---|
Set message identifier |
|
Set destination |
|
Set reply destination |
|
Set correlation identifier from string |
|
Set correlation identifier from byte array |
|
Set delivery mode |
|
Set priority level |
|
Set time stamp |
|
Set expiration time |
|
Set message type |
|
Set redelivered flag |
The message identifier (JMSMessageID) is a string value uniquely identifying the message, assigned and set by the message broker when the message is sent. Because generating an identifier for each message adds to both the size of the message and the overhead involved in sending it, and because some client applications may not use them, the JMS interface provides a way to suppress the generation of message identifiers, using the message producer method setDisableMessageID (see Sending Messages).
The JMSDestination header field holds a Destination object representing the destination to which the message is directed, set by the message broker when the message is sent. There is also a JMSReplyTo field that you can set to specify a destination to which reply messages should be directed. Clients sending such a reply message can set its JMSCorrelationID header field to refer to the message to which they are replying. Typically this field is set to the message identifier string of the message being replied to, but client applications are free to substitute their own correlation conventions instead, using either the setJMSCorrelationID method (if the field value is a string) or the more general setJMSCorrelationIDAsBytes (if it is not).
The delivery mode (JMSDeliveryMode) specifies whether the message broker should log the message to stable storage. There are two possible values, PERSISTENT and NON_PERSISTENT, both defined as static constants of the JMS interface DeliveryMode: for example,
outMsg.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
The default delivery mode is PERSISTENT, represented by the static constant Message.DEFAULT_DELIVERY_MODE.
The choice of delivery mode represents a tradeoff between performance and reliability:
In persistent mode, the broker logs the message to stable storage, ensuring that it will not be lost in transit in the event of transmission failure; the message is guaranteed to be delivered exactly once.
In nonpersistent mode, the message is not logged to stable storage; it will be delivered at most once, but may be lost in case of failure and not delivered at all. This mode does, however, improve performance by reducing the broker’s message-handling overhead. It may thus be appropriate for applications in which performance is at a premium and reliability is not.
The message’s priority level (JMSPriority) is expressed as an integer from 0 (lowest) to 9 (highest). Priorities from 0 to 4 are considered gradations of normal priority, those from 5 to 9 of expedited priority. The default priority level is 4, represented by the static constant Message.DEFAULT_PRIORITY.
The Message Queue client runtime sets the JMSTimestamp header field to the time it delivers the message to the broker, expressed as a long integer in standard Java format (milliseconds since midnight, January 1, 1970 UTC). The message’s lifetime, specified when the message is sent, is added to this value and the result is stored in the JMSExpiration header field. (The default lifetime value of 0, represented by the static constant Message.DEFAULT_TIME_TO_LIVE, denotes an unlimited lifetime. In this case, the expiration time is also set to 0 to indicate that the message never expires.) As with the message identifier, client applications that do not use a message’s time stamp can improve performance by suppressing its generation with the message producer method setDisableMessageTimestamp (see Sending Messages).
The header field JMSType can contain an optional message type identifier string supplied by the client when the message is sent. This field is intended for use with other JMS providers; Message Queue clients can simply ignore it.
When a message already delivered must be delivered again because of a failure, the broker indicates this by setting the JMSRedelivered flag in the message header to true. This can happen, for instance, when a session is recovered or a transaction is rolled back. The receiving client can check this flag to avoid duplicate processing of the same message (such as when the message has already been successfully received but the client’s acknowledgment was missed by the broker).
See the Java Message Service Specification for a more detailed discussion of all message header fields.
A message property consists of a name string and an associated value, which must be either a string or one of the standard Java primitive data types (int, byte, short, long, float, double, or boolean). The Message interface provides methods for setting properties of each type (see Table 2–6). There is also a setObjectProperty method that accepts a primitive value in objectified form, as a Java object of class Integer, Byte, Short, Long, Float , Double, Boolean, or String . The clearProperties method deletes all properties associated with a message; the message header and body are not affected.
Table 2–6 Message Property Specification Methods
Name |
Description |
---|---|
Set integer property |
|
Set byte property |
|
Set short integer property |
|
Set long integer property |
|
Set floating-point property |
|
Set double-precision property |
|
Set boolean property |
|
Set string property |
|
Set property from object |
|
Clear properties |
The JMS specification defines certain standard properties, listed in Table 2–7 . By convention, the names of all such standard properties begin with the letters JMSX; names of this form are reserved and must not be used by a client application for its own custom message properties. Similarly, property names beginning with JMS_SUN are reserved for provider-specific properties defined by Message Queue itself; these are discussed in Chapter 3, Message Queue Clients: Design and Features
Table 2–7 Standard JMS Message Properties
Name |
Description |
---|---|
Identity of user sending message |
|
Identity of application sending message |
|
Number of delivery attempts |
|
Identity of message group to which this message belongs |
|
Sequence number within message group |
|
Identifier of transaction within which message was produced |
|
Identifier of transaction within which message was consumed |
|
Time message delivered to consumer |
|
Message state (waiting, ready, expired, or retained) |
The actual content of a message is contained in the message body. JMS defines six classes (or types) of message, each with a different body format:
A text message (interface TextMessage) contains a Java string.
A stream message (interface StreamMessage) contains a stream of Java primitive values, written and read sequentially.
A map message (interface MapMessage) contains a set of name-value pairs, where each name is a string and each value is a Java primitive value. The order of the entries is undefined; they can be accessed randomly by name or enumerated sequentially.
An object message (interface ObjectMessage) contains a serialized Java object (which may in turn be a collection of other objects).
A bytes message (interface BytesMessage) contains a stream of uninterpreted bytes.
A null message (interface Message) consists of a header and properties only, with no message body.
Each of these is a subinterface of the generic Message interface, extended with additional methods specific to the particular message type.