The JMS Simplified API

Previous Next Contents

3 The JMS Simplified API

This chapter describes the JMS Simplified API defined by the Java Message Service (JMS) 2.0 specification and implemented in the Message Queue Java API.

Note

The JMS Classic API offers the same functionality and is described in The JMS Classic API. For detailed reference information, see the JavaDoc documentation for each individual class.

The topics covered include the following:

Using the Simplified API

The Simplified API provides the same basic functionality as the Classic API but requires fewer interfaces and is simpler to use.

The main interfaces are:

  • ConnectionFactory—An administered object used by a client to create a Connection. This interface is also used by the Classic API.

  • JMSContext—An active connection to a JMS provider and a single-threaded context used to send or receive messages.

  • JMSProducer—An object created by a JMSContext to send messages to a queue or topic.

  • JMSConsumer—An object created by a JMSContext to receive messages sent to a.queue or topic

In the Simplified API, the JMSContext combines the behaviors of the Classic API Connection and Session objects. A Connection continues to represent a physical link to a JMS server. A Session continues to represent a single-threaded context for sending or receiving messages. Figure 3-1 shows an overview of the Simplified API.

Figure 3-1 Overview of Simplified API

"[[top]"]

For more information, see "The Java Message Service specification, version 2.0", available from http://jcp.org/en/jsr/detail?id=343.

Using the Autocloseable Interface

Objects from interfaces that extend the java.lang.Autocloseable and use a try-with-resources statement do not need to explicitly call close() when these objects are no longer required.

The following interfaces extend the java.lang.Autocloseable interface:

  • JMSContext

  • JMSConsumer

  • QueueBrowser

For example:

. . .
try (JMSContext context = connectionFactory.createContext();){
   // use context in this try block
   // it will be closed when try block completes
} catch (JMSException e){
   // exception handling
}
. . .

Simplified Extraction of Message Bodies

You can use the getBody method to provide a convenient way to obtain the body from a newly-received Message object. Use getBody to:

  • Return the body of a TextMessage, MapMessage, or BytesMessage as a String, Map, or byte[] without the need to cast the Message first to the appropriate subtype.

  • Return the body of an ObjectMessage without the need to cast the Message to ObjectMessage, extract the body as a Serializable, and cast it to the specified type.

The isBodyAssignableTo method can be used to determine whether a subsequent call to getBody would be able to return the body of a particular Message object as a particular type.

Developing a JMS Client using the Simplified API

This section provides the basic steps required to create a JMS client using the Simplified API.

  • Use JNDI to find a ConnectionFactory object.

  • Use JNDI to find one or more Destination objects.

  • Use the ConnectionFactory to create a JMSContext object.

  • Use the JMSContext to create the JMSProducer and JMSConsumer objects needed.

  • Delivery of message is started automatically.

Example 3-1 Sending a Message using the Simplified API

public void sendMessageNew(String body) throws NamingException{

   InitialContext initialContext = getInitialContext();
   ConnectionFactory connectionFactory = (ConnectionFactory)
      initialContext.lookup("jms/connectionFactory");

   Queue inboundQueue = (Queue) initialContext.lookup("jms/inboundQueue");

   try (JMSContext context = connectionFactory.createContext();){
      context.createProducer().send(inboundQueue,body);
   }
}
. . .

See "Java Message Service Examples" in The Java EE 7 Tutorial for additional information.

Working With Connections

In the simplified API a connection and a session are represented by a single JMSContext object. When a JMSContext is created the underlying session is created automatically.

Since a JMSContext incorporates a session, it is subject to the same threading restrictions as a session. This means that it may only be used by one thread at a time (single-threaded).

  • The JMSContext method createContext does not use its underlying session and is not subject to the single-threading restriction.

  • The close method on JMSContext or JMSConsumer is not single-threaded since closing a session or consumer from another thread is permitted.

  • By default, when createConsumer or createDurableConsumer is used to create a JMSConsumer, the connection is automatically started. If setMessageListener is called to configure the asynchronous delivery of messages, the JMSContext's session immediately becomes dedicated to the thread of control that delivers messages to the listener. The application must not subsequently call methods on the JMSContext from another thread of control. However, this restriction does not apply to applications which call setMessageListener to set a second or subsequent message listener. The JMS provider is responsible for ensuring that a second message listener may be safely configured even if the underlying connection has been started.

See "The JMS API Programming Model" in The Java EE 7 Tutorial for additional information.

Working With Destinations

All Message Queue messages travel from a message producer to a message consumer by way of a destination on a message broker. Message delivery is thus a two-stage process: the message is first delivered from the producer to the destination and later from the destination to the consumer. Physical destinations on the broker are created administratively by a Message Queue administrator, using the administration tools described in "Configuring and Managing Physical Destinations" in Open Message Queue Administration Guide. The broker provides routing and delivery services for messages sent to such a destination.

Message Queue supports two types of destination, depending on the messaging domain being used:

  • Queues (point-to-point domain)

  • Topics (publish/subscribe domain)

These two types of destination are represented by the Message Queue classes Queue and Topic, respectively. These, in turn, are both subclasses of the generic class Destination. A client program that uses the Destination superclass can thus handle both queue and topic destinations indiscriminately.

See "The JMS API Programming Model" in The Java EE 7 Tutorial for additional information.

Working With Messages

This section describes how to use the Message Queue Java API to compose, send, receive, and process messages. See "The JMS API Programming Model" in The Java EE 7 Tutorial for additional information.

Message Structure

The following section provides information on message structure:

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

For more information, see Message Structure.

Message Headers

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 3-1. 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 3-1 Message Header Fields

Name Description

JMSMessageID

Message identifier

JMSDestination

Destination to which message is sent

JMSReplyTo

Destination to which to reply

JMSCorrelationID

Link to related message

JMSDeliveryMode

Delivery mode (persistent or nonpersistent)

JMSDeliveryTime

The earliest time a provider may make a message visible on a target destination and available for delivery to consumers.

JMSPriority

Priority level

JMSTimestamp

Time of transmission

JMSExpiration

Expiration time

JMSType

Message type

JMSRedelivered

Has message been delivered before?

The JMS Message interface defines the following methods for setting the corresponding value of each header field. Table 3-2 lists all of the available header specification methods for the JMS Message interface.

Table 3-2 JMS 2.0 Message Header Methods for the Message Interface

Name Description

setJMSDestination

Set destination

setJMSReplyTo

Set reply destination

setJMSCorrelationID

Set correlation identifier from string

setJMSCorrelationIDAsBytes

Set correlation identifier from byte array

setJMSType

Set message type

The JMS Producer interface defines the following methods for setting the corresponding value of each header field. Table 3-3 lists all of the available header specification methods.

Table 3-3 JMS 2.0 Message Header Methods for the Producer Interface

Name Description

setJMSMessageID

Set message identifier

setJMSDeliveryMode

Set delivery mode

setJMSPriority

Set priority level

setJMSTimestamp

Set time stamp

setJMSExpiration

Set expiration time

setJMSRedelivered

Set redelivered flag

setJMSDeliveryTime

Set the delivery time for a message

See the "Java Message Service specification, version 2.0", available from http://jcp.org/en/jsr/detail?id=343 for a more detailed discussion of all message header fields.

Changes for Standard JMS 2.0 Message Properties

The JMS specification defines certain standard properties, listed in Table 3-4. 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. These properties are not enabled by default, an application must set the name/value pairs it requires on the appropriate connection factory.

The JMS 2.0 specification requires that JMS producers set the JMSXDeliveryCount. This property was not supported prior to MQ 5.0.

Table 3-4 Standard JMS 2.0 Message Properties

Name Type Required? Set by Description

JMSXUserID

String

Optional

Provider on Send

Identity of user sending message

JMSXAppID

String

Optional

Provider on Send

Identity of application sending message

JMSXDeliveryCount

int

Required

Provider on Receive

Number of delivery attempts

JMSXGroupID

String

Optional

Client

Identity of message group to which this message belongs

JMSXGroupSeq

int

Optional

Client

Sequence number within message group

JMSXProducerTXID

String

Optional

Provider on Send

Identifier of transaction within which message was produced

JMSXConsumerTXID

String

Optional

Provider on Receive

Identifier of transaction within which message was consumed

JMSXRcvTimestamp

long

Optional

Provider on Receive

Time message delivered to consumer

JMSXState

int

Optional

Provider

Message state (waiting, ready, expired, or retained)

Sending Messages

In order to send messages to a message broker, you must create a JMSProducer object using the createProducer() method on JMSContext. For example:

try (JMSContext context = connectionFactory.createContext();){context.createProducer().send(inboundQueue,body)
}

The JMS 2.0 specification allows a client to specify a delivery delay value, in milliseconds, for each message it sends. This value is used to determine a messages’s delivery time which is calculated by adding the delivery delay value specified on the send to the time the message was sent. See Message Headers.

Table 3-5 shows the methods defined in the JMSProducer interface.

Table 3-5 JMSProducer Methods

Name Description

getDestination

Get default destination

setDeliveryMode

Set default delivery mode

getDeliveryMode

Get default delivery mode

getDeliveryDelay

Get delivery delay value in milliseconds

setDeliveryDelay

Set delivery delay value in milliseconds

setPriority

Set default priority level

getPriority

Get default priority level

setTimeToLive

Set default message lifetime

getTimeToLive

Get default message lifetime

setDisableMessageID

Set message identifier disable flag

getDisableMessageID

Get message identifier disable flag

setDisableMessageTimestamp

Set time stamp disable flag

getDisableMessageTimestamp

Get time stamp disable flag

send

Send message

close

Close message producer

Simplified API methods for Asynchronous Sends

In the Simplified API, a JMS provider sends a message asynchronously by calling setAsync(CompletionListener completionListener) on the JMSProducer prior to calling one of the following send methods:

  • send(Destination destination, Message message)

  • send(Destination destination, String body)

  • send(Destination destination, Map<String,Object> body)

  • send(Destination destination, byte[] body)

  • send(Destination destination, Serializable body)

  • send(Destination destination, String body)

Note

These send methods are the same as methods that are used for a synchronous send. However, calling setAsync beforehand changes their behavior.

For more information on how to convert common synchronous send design patterns to use asynchronous sends, see Asynchronous send.

Receiving Messages

This section provides information on new behaviors and two new subscription types for clients to use when consuming messages.

Using Shared Non-durable Subscriptions

A shared non-durable subscription is used by a client that needs to be able to share the work of receiving messages from a non-durable topic subscription across multiple consumers. Each message from the subscription is delivered to only one of the consumers that may exist on that subscription.

Shared non-durable subscriptions are created and a consumer crated on the subscription using one of the following:

  • Classic API: One of the createSharedConsumer methods on Session which return a MessageConsumer object.

  • Simplified API: One of the createSharedConsumer methods on JMSContext which returns a JMSContext object.

A shared non-durable subscription exists only as long as there is an active consumer on the subscription. It is identified by name and an optional client identifier (clientId). If the client identifier was set when the subscription was created, any client that creates a consumer on that shared non-durable subscription must use the same client identifier. This type of subscription is not persisted and is deleted, along with any undelivered messages, when the last consumer on the subscription is deleted. The noLocal parameter is not supported for shared non-durable subscriptions.

Using Shared Durable Subscriptions

A shared durable subscription is used by an application that needs to share the work of receiving all the messaged published on a topic, including messages published when no consumers are associated with the subscription. Each message from the subscription is delivered to only one of the consumers that may exist on that subscription. For this subscription type, the JMS provider ensures all the messages from the topic’s publishers:

  • Are Delivered and acknowledged or

  • Have expired

Shared durable subscriptions are created and a consumer crated on the subscription using one of the following:

  • Classic API: One of the createSharedDurableConsumer methods on Session which return a MessageConsumer object.

  • Simplified API: One of the createSharedDurableConsumer methods on JMSContext which returns a JMSContext object.

A shared durable e subscription persists and accumulates messages until it is explicitly deleted using the unsubscribe method on either Session or JMSContext. You cannot delete a durable subscription with an active consumer or while a message is received from the subscription is part of a transaction. It is identified by name and an optional client identifier (clientId). If the client identifier was set when the subscription was created, any client that creates a consumer on that shared non-durable subscription must use the same client identifier. The noLocal parameter is not supported for shared durable subscriptions.

Starting Message Delivery

An application using the Classic API to consume messages needs to call the connection’s start method to start delivery of incoming messages. It may temporarily suspend delivery by calling stop, after which a call to start will restart delivery.

The Simplified API provides corresponding start and stop methods on JMSContext. The start method is be called automatically when createConsumer or createDurableConsumer are called on the JMSContext object. There is no need for the application to call start when the consumer is first established. An application may temporarily suspend delivery by calling stop, after which a call to start will restart delivery.

In some situations, an application using the Simplified API may need a connection to remain in stopped mode while setup is being completed and not commence message delivery until the start method is explicitly called. You can configure this behavior by calling setAutoStart(false) on the JMSContext prior to calling createConsumer or createDurableConsumer.

Processing Messages

Processing a message after you have received it may entail examining its header fields, properties, and body.

Retrieving Message Header Fields

The standard JMS message header fields are described in Table 3-4. Table 3-6 shows the methods provided by the JMS Message interface for retrieving the values of these fields: for instance, you can obtain a message’s reply destination with the statement:

Destination replyDest = inMsg.getJMSReplyTo();

Table 3-6 Message Header Retrieval Methods

Name Description

getJMSMessageID

Get message identifier

getJMSDestination

Get destination

getJMSReplyTo

Get reply destination

getJMSCorrelationID

Get correlation identifier as string

getJMSCorrelationIDAsBytes

Get correlation identifier as byte array

getJMSDeliveryMode

Get delivery mode

getJMSDeliveryTime

Get the delivery time

getJMSPriority

Get priority level

getJMSTimestamp

Get time stamp

getJMSExpiration

Get expiration time

getJMSType

Get message type

getJMSRedelivered

Get redelivered flag


Previous Next Contents
Eclipse Foundation Logo  Copyright © 2019, Oracle and/or its affiliates. All rights reserved.