JMS: An infrastructure for XML-based business-to-business communication

Learn how the Java Messaging Service can provide a flexible, reliable, and secure means of exchanging XML-based transactions

XML has quickly established itself as the lingua franca of information exchange, and is rapidly being applied to a wide variety of data-representation needs. XML embodies qualities that directly promote broad classes of application integration and interaction. Yet XML itself does not include or imply a transactional or communication infrastructure.

Oddly, there is remarkably little discussion of this need, especially when you consider the how much public debate there has been over what XML can represent and how it could or should represent it. The XML-RPC (Remote Procedure Call) initiative promotes the notion of an RPC-like mechanism for exchanging XML over HTTP. But as we shall see, RPC for largely distributed systems is a highly limited mechanism -- particularly when those systems connect multiple businesses across the Internet.

In contrast, there is a natural fit between XML and Java messaging -- from the problems they try to solve to the design philosophies behind their use. This article aims to illuminate how well these technologies work together.

The problem with RPC

As organizations deploy distributed Java applications on ever-larger scales -- across offices of an enterprise or between businesses in a business-to-business (B2B) capacity -- the demands placed upon their communication and transaction infrastructures expand geometrically. Upon examination, direct RMI or RPC mechanisms quickly fail to meet the challenges presented in such environments.

Consider, for example, a B2B scenario wherein information on changing prices is to be communicated from a supplier to a number of retailers, and the retailers may in turn wish to place orders for items at a new price. While this is perhaps the most simplistic of B2B scenarios, could you imagine trying to implement such an infrastructure using a bare RPC mechanism?

You would need to create a listener that would respond to all incoming orders, which doesn't sound so bad. You would also need to manage the list of price change recipients, with appropriate provisions for easily adding new ones -- again, not an impossible task, but perhaps a bit tedious.

Next, you would need to ensure that each party receives and processes all the transactions that are sent its way. Now things get sticky. What if one of the retailers is offline, or network routing to its server fails? Your application would need to keep trying to establish communications with all such recipients until the transaction could be successfully sent. What if the power on the supplier's server dropped, or the server required a reboot prior to all recipients receiving a price change? Or, even worse, prior to the supplier receiving an order?

Clearly, you would need to provide persistence for critical transactions until all required recipients acknowledge them. And, of course, you'd want to ensure that all parties performing transactions are allowed access and are who they say they are, and that no transaction is compromised during transmission. RPC does not provide assistance for any of these problems, requiring the application to carry the additional weight itself.

Enter JMS

Virtually all XML-based B2B transactions will take place in a loosely coupled environment such as the one outlined above, where connectivity can't be guaranteed, unpredictable latency is the course of the day, transactions require security, and the frenetic pace of business demands constant change. Inserting Java messaging between business nodes in a B2B network insulates your application code from these issues. The Java Message Service (JMS) specification addresses the demands of loosely coupled distributed systems in a coherent manner. JMS offers an API and a set of semantics that prescribe the interface and general behavior of a messaging service. The underlying wire protocol is not specified by JMS, but, in practice, Java messaging is often performed over TCP/IP or HTTP. Java messaging solutions that conform to the JMS specification provide the implementation of JMS behavior over these protocols.

Of the Java messaging solutions currently available, there are two architectural approaches: a standalone messaging server or a JMS service embedded within an application server. A standalone JMS server allows the developer to place messaging servers where they can optimize network bandwidth usage and topology, provide fail-safe operation, or incorporate the messaging server infrastructure entirely within a value-added application. In contrast, integrating JMS as an additional service within an application server environment offers the convenience of a single solution, though without the flexibility described above.

A foundation for evolving business systems

The benefits of a Java messaging infrastructure extend far beyond communications reliability and security. The pairing of XML and Java messaging promotes highly flexible and scalable designs that can better accommodate the rapid change that distributed systems face in today's business environments. Data represented in XML is intrinsically polymorphic -- that is, the same data can be used in a variety of contexts. By designing an XML schema, developers are planning for this eventuality; therefore, they typically design XML content in a highly cogent, reusable manner. This philosophy maps directly onto the design of a distributed application with messaging at its core. Distributed systems built upon messaging are inherently polymorphic. They can easily be extended and refactored, largely due to the decoupling of events from processing semantics.

Consider the case of an insurance company datacenter that must provide information on new rate plans as they are created and approved. The immediate requirement is to publish new rate-plan information to a specific client application outside the datacenter in order to accommodate the needs of a specific sales department. With Java messaging, this information can be sent to the client by publishing XML messages to what in JMS parlance is referred to as a topic. These XML messages are then retrieved by the client application through subscription to the designated topic (we'll discuss messaging models, topics, subscriptions, and the like in more detail later).

What is the immediate benefit of this approach? The sales department is guaranteed to receive all the rate-change information, regardless of any problems with the physical communication between it and the datacenter. Moreover, the long-term benefits are even more profound. It's easy to imagine that, several months later, another department will determine that it too needs this rate-plan information in order to create a periodic report to management. After that, a marketing group may decide to provide new rate plans on a secured extranet site for the company's partners. Each of these new applications will perform radically different actions based on the published information, but they can obtain it by simply subscribing to the original topic and receiving XML messages. Note that the original datacenter application doesn't need to change to support these new uses. In fact, it doesn't even to be aware of the new applications or how they intend to use the data. Separating the event of sending a message from the semantics of processing it allows the message to be used in a multitude of ways unknown or unimagined at the time the publishing application is designed.

Key JMS features

A number of key characteristics of JMS make it a good fit for B2B communication, enterprise application integration, and a score of uses in between. Let's take a look at these important features.

Flexible programming model

JMS supports two primary messaging paradigms: publish/subscribe, or pub/sub, and point-to-point. Pub/sub messaging is a one-to-many publishing paradigm, in which client applications publish messages to topics, to which other interested clients in turn subscribe. All subscribed clients will receive each message (subject to quality of service, connectivity, and selection factors). Point-to-point messaging, on the other hand, provides a traditional queuing mechanism in which a client application sends messages through a queue to (typically) one receiving client that obtains the messages sequentially.

Both paradigms are articulated through nearly identical programming models, wherein quality of service, security, acknowledgement modes (indicating how and when the messaging system is informed that a client has received a message), and the like are specified in a manner independent of other properties and the messaging paradigm employed.

Resilience

Java messaging services that fully implement the JMS specification provide multiple forms of resilience for the applications they service. For example, a sender can indicate that a given message should persist within a broker-managed data store until all subscribed recipients receive the message. Subscriptions can also be made durable, meaning that a client application will automatically receive messages that are sent to the subscribed topics whenever the client attaches to the message broker -- including any persistent messages that may have been sent while the client was offline. The Java messaging service manages the details of the persistence underlying these capabilities. The JMS specification itself does not prescribe how persistence should be implemented -- the implementation design is left to the provider of a Java messaging service.

Flexible event-based mechanisms

JMS supports a wide range of system behaviors, from tightly coupled request-reply patterns to loosely coupled scenarios in which the publisher does not care if a given subscriber receives the message. Both the sending and receipt of messages can be either synchronous or asynchronous. For example, an application may handle message reception synchronously, thereby blocking until a message is received. Alternately, JMS messages can invoke asynchronous handlers in the calling application, which then perform operations on behalf of the sender and, optionally, produce a reply. Replies can be sent to temporary unnamed queues for anonymous request-reply scenarios. Hence, the JMS programming model can be employed for such disparate uses as a synchronous invocation mechanism for middleware services or the multicasting of stock ticker information to thousands of Web clients.

Transaction support

JMS provides a transaction model, allowing the client application to bundle messages into transactional groups. The broker will hold the transacted messages until the client application either commits the transaction or rolls it back.

Subject-based routing

JMS transcends the limits of destination-based routing by providing a properties-based message selection mechanism. User-definable properties in message headers can be filtered by the JMS implementation on behalf of client applications. Selectors are specified using a SQL-like syntax, and can be used to filter information based on a variety of factors. A filter could look for particularly sharp price drop, for example.

Java messaging framework

The JMS specification refers to a JMS provider, which provides the actual implementation of the JMS APIs and semantics. Commercial (and noncommercial, for that matter) JMS providers can take many shapes and forms, but the dominant model is that of a Java messaging broker that fulfills the role of the provider. Providers can also take the form of multiple brokers in a clustered configuration, although not all commercial implementations of JMS provide this capability.

Figure 1. Java messaging architecture

As seen in Figure 1 above, the Java messaging architecture presents a hub-and-spoke model, with multiple clients sending and receiving messages through a central JMS provider. In JMS, both messaging paradigms (pub/sub and point-to-point) are derived from a common messaging framework based on the concept of message producers and consumers. In this framework, client applications access the provider through the JMS API. Typically, each client contains a messaging client runtime library that implements the JMS interface and communicates with the broker on behalf of the client.

Aspects of the programming framework that are common to both the pub/sub and point-to-point models include connection and session management. Let's begin our exploration of the JMS framework by taking a look at these common underpinnings. After that, we'll take a look at the specifics of pub/sub and point-to-point programming. Finally, we'll examine the target of all these machinations: JMS messages themselves.

Connection management

Each client application opens a single connection to the message broker. The connection provides a conduit for communication with the messaging system. Multiple connections are possible, but this typically happens only when clients connect to multiple distinct message brokers, as connections are relatively heavy when compared with sessions. (We will discuss sessions momentarily.) Typically, a client will locate a broker through JNDI, and then establish a connection through its connection factory.

Session management

Within the context of a connection, the client application establishes one or more sessions, each with its own transactional characteristics and acknowledgement modes. All actual messaging activity is performed via the session object. It is considerably more efficient to employ multiple sessions per connection than multiple connections to the same broker. Connections require more resources to establish and maintain than sessions, and can easily be reused for communication through different topics or queues, as well as for different transactional or acknowledgement behavior.

The JMS syntax for creating a session on an established connection is:

   public javax.jms.[Topic|Queue]Session create[Topic|Queue]Session
   (boolean transacted, int acknowledgeMode)

Where:

  • transacted is a boolean value; if it is true, the session will be transacted
  • acknowledgeMode indicates whether the consumer or the client will acknowledge any messages they receive

Transactional behavior

Transactional behavior is controlled at the session level. When a session is transacted, the message broker stages the message traffic until the client application either commits or rolls back the transaction. The completion of a session's current transaction automatically begins a new transaction.

The use of transactions affects producers and consumers of messages in the following manner:

  • Producers:

    • Commit: The broker sends the set of messages that have been staged
    • Rollback: The broker disposes of the set of messages that have been staged
  • Consumers:
    • Commit: The broker disposes of the set of messages that have been staged
    • Rollback: The broker resends the set of messages that have been staged

When a rollback is performed in a session that is both a producer and a consumer, its produced messages are destroyed, and its consumed messages are resent.

Acknowledgement modes

Acknowledgment modes are also controlled at the session level. Acknowledgment is distinct from replies in the request-reply model; they instead inform the message broker that a given client has successfully received a message. Replies, on the other hand, are additional messages sent by a receiver in response to an incoming message. Acknowledgement can be thought of as analogous to handshaking in hardware communication. JMS supports the following acknowledgement modes for receiving messages:

  • AUTO_ACKNOWLEDGE: The session automatically acknowledges receipt of each message. In synchronous mode, this indicates a successful return from a call to receive. In asynchronous mode, it indicates that the asynchronous message handler indicated a successful return.

  • CLIENT_ACKNOWLEDGE: Allows the client application to indicate that it received the message successfully, possibly delaying the acknowledgement. The application must invoke the acknowledge() method on each message successfully received.

  • DUPS_OK_ACKNOWLEDGE: A variation on AUTO_ACKNOWLEDGE that provides a lazy mechanism that can result in duplicate message deliveries in failure situations. While this mode is only appropriate for insensitive data, it can provide increased efficiency in a messaging system.

Pub/sub programming

In the pub/sub paradigm, each session object publishes and/or subscribes to one or more topics. An authorized publisher produces messages through a specified topic, and authorized subscribers receive messages by subscribing to that topic. This model promotes the independence of producers and consumers from one another, and allows for both one-to-many and many-to-many configurations. Topics may be static objects under administrative control, dynamic objects created as needed, or temporary objects created for more transitory or anonymous uses.

In order to publish messages, a session must create a publisher object for the selected topic. Likewise, to consume messages published to a topic, a session must create subscriber objects that subscribe to the desired topic. In Figure 2 below, the pub/sub session contains publisher objects producing messages to topics maintained by the message broker and subscribers consuming messages from topics to which the session is subscribed.

Figure 2. Pub/sub model

Publishing a message

When publishing a message, the publishing application specifies the quality of service to be used (factors involved here include the message's delivery mode, time-to-live, and priority) as well as whether the subscriber requests a reply:

publish(Message message, int deliveryMode, int priority, long timeToLive)

Where:

  • message is a javax.jms message
  • deliveryMode is either NON_PERSISTENT or PERSISTENT
  • priority is between 0 and 9, with 0 being lowest and 9 highest
  • timeToLive is between 0 and n, with 0 being forever and any other positive value of n being n milliseconds

Delivery modes

The delivery mode is one of several aspects that determine quality of service for message delivery and receipt:

  • NON_PERSISTENT: This is the most efficient delivery mode, because it does not require that the message be logged to stable storage. The JMS specification indicates that a JMS provider must deliver a NON_PERSISTENT message with an at-most-once guarantee, meaning that the broker may lose the message (due to a power outage, for example), but it must not deliver it twice.

  • PERSISTENT: This mode instructs the broker to place the message in a data store as an extension of the send operation. This ensures that the message will survive power outages and other system failures. The JMS specification indicates that a JMS provider must deliver a PERSISTENT message with a once-and-only-once guarantee. It must not lose the message and it must not deliver it twice.

Priority

When several messages await consumption by a subscriber, higher priority messages are presented to the client prior to those of lower priority, resulting in non-FIFO (first in, first out) behavior.

Time-to-live

The time-to-live parameter specifies how long the message broker should retain the message in order to ensure that all subscribers receive it. If, after initial delivery, any durable subscribers did not acknowledge delivery, the message is retained for the time-to-live duration in anticipation of those durable subscribers reconnecting to the message broker and accepting delivery. If the time-to-live is specified as zero, the message is said to live forever; it will not expire.

When a message's time-to-live is reached, the broker will typically discard it. The JMS specification does not define any form of notification of message expiration. Clients should not receive messages that have expired; however, the JMS specification does not guarantee that message brokers will not allow this to happen. Typically, a message set to live forever will be discarded as soon as delivery to all current subscribers and all durable subscribers is complete.

Nondurable subscriptions

To create a nondurable subscription to a topic, the client application invokes the following method provided by the session object:

TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal)

Where:

  • topic is a string that specifies the name of a topic
  • messageSelector is a string that defines selection criteria
  • noLocal is a boolean; a value of true indicates that the client application will not receive messages from subscribed topics that were published locally

Message selection

Subscribers can filter the messages they receive by qualifying their subscriptions with so-called message selectors. Message selectors cause the JMS provider to evaluate message headers and properties prior to sending messages to the client application. Message selectors employ a syntax based on a subset of SQL-92 conditional expressions. Because the JMS provider handles the filtering, the application and its communication links are more efficient and consume less bandwidth.

The following message selector might filter a subscription on a topic to retrieve only high-priority quotes that are requesting a reply:

"Property_Priority > 7 AND Property_Type='Quote' AND
   Property_Reply is NOT NULL"

Durable subscriptions

To create a durable subscription to a topic, the client application invokes the following method provided by the session object:

TopicSubscriber createDurableSubscriber (Topic topic,
   String name, String messageSelector, boolean noLocal)

Where:

  • topic is a string that specifies the name of a topic
  • name is an arbitrary string (not necessarily the username, although that is not uncommon) that indicates the name under which to maintain the durable subscription to the specified topic

  • messageSelector is a string that defines selection criteria

  • noLocal is a boolean; a value of true indicates that the client application will not receive messages from subscribed topics that were published locally

A durable subscription indicates that the client wants to receive all the messages published to a topic even if the client connection is not active. The broker ensures that all messages published to the topic are retained until the durable subscriber acknowledges them or the messages have expired.

Pub/sub code sample

Let's take a look at this in action. The following code sample illustrates the basic steps required to create a publisher and a subscriber for a sample topic, and publish a message:

String APP_TOPIC = "sample_topic";
//The session method is used to create the topic.
javax.jms.Topic topic = session.createTopic (APP_TOPIC);
//The subscriber uses the session method to create a subscriber to it.
javax.jms.TopicSubscriber subscriber =
   session.createDurableSubscriber(topic, user);
//The subscriber sets a listener for the topic.
subscriber.setMessageListener(myListener);
//The publisher uses the session method to create a publisher.
publisher = session.createPublisher(topic);
// Publish a message to the topic.
private void jmsPublish (String aMessage)
{
   try
   {
      javax.jms.TextMessage msg = session.createTextMessage();
         msg.setText( user + ": " + aMessage );
      publisher.publish( msg );
   }
   catch ( javax.jms.JMSException jmse )
   {
      jmse.printStackTrace();
   }
}

(Note: This article can only provide the briefest of introductions to JMS programming in the context of enabling B2B communication with XML. The JMS API is quite useful for the development of a wide variety of synchronous and asynchronous transaction models. I encourage you to check the Resources listed at the end of this article for more information.)

Point-to-point programming

In the point-to-point (PTP) paradigm, each session object sends and/or receives through one or more queues. Prospective consumers of messages sent to a queue can either receive the message that is first in line (thereby removing it from the queue) or browse through all the messages in the queue, causing no changes.

Figure 3. Point-to-point model

In Figure 3 above, the PTP session employs sender objects that send messages to queues maintained by the message broker, and receivers that receive messages addressed to specific queues.

In the PTP paradigm, the first message received by the broker is the first message delivered to a consumer. This FIFO technique requires that the broker retain the second message and any subsequent messages until the first message is consumed. Even when there are no clients associated with a queue, messages are retained. Hence, unlike the pub/sub semantics, durability and persistence are implicit queue concepts. There is only one message consumer for a given message. In some JMS implementations, multiple prospective receivers can attach to a queue, but only one takes delivery of each message. When each message is acknowledged as delivered, the broker disposes of it. No other client sees it and no other client can receive it.

JMS specifies a queue browser mechanism. A queue browser allows authorized clients to examine queues (counting messages, for example) without destroying the examined messages.

In Figure 4 below, three message queues are shown within a message broker. The queues are shown to have different depths, indicating the stack of messages that are retained until receivers consume them. The receiver could be one of many standing by to receive the first message in the queue. On the red queue, multiple receivers are attached, but only one will receive the next message: a message queued through PTP is delivered only once.

Figure 4. Point-to-point messaging in action

The JMS programming model for PTP is virtually identical to that for pub/sub, except for the inherent semantic differences between the two models. As such, we will not go into the details of PTP programming here.

JMS messages

Now let's take a look at the messages themselves. All JMS messages are composed of the following three sections:

  • Header fields: All messages support the same set of header fields. Header fields contain values used by both client applications and JMS providers to identify and route messages.
  • Properties: These contain JMS-specified and user-defined name-value pairs that can be used for message filtering/routing and application requirements. These named properties are used by the message selection mechanism described earlier. The JMS specification does not require the use of any message properties, even those defined by the specification. Property names must obey the rules for a message-selector identifier. Property values, which are set prior to sending a message, can be booleans, bytes, shorts, ints, longs, floats, doubles, and Strings.
  • Body: The body section contains the application-specific portion of the message. JMS defines several types of message bodies that correspond with the JMS-supported message types:

    • BytesMessage: A stream of uninterpreted bytes.
    • MapMessage: A set of name-value pairs, in which the names are strings and the values are Java primitive types. The entries can be accessed sequentially or randomly by name.
    • TextMessage: A message containing a java.util.StringBuffer.
    • StreamMessage: A stream of Java primitive types, filled and read sequentially.
    • ObjectMessage: A message that contains a serializable Java object.

    These five types cover the majority of messaging styles currently in use.

XML message type -- where is it?

You may have noticed by now that there is no XML message type specified in JMS. Given our enthusiasm for XML transported by JMS, you may ask, "What gives?" In practice, XML messages can be placed in TextMessage messages, and enjoy all the identified benefits of a messaging infrastructure for their transport -- resilience, security, increased system design flexibility, and so on. A step toward deeper XML support in Java messaging would be to extend the TextMessage object in order to provide additional convenience for XML handling.

Bear in mind, though, that the JMS specification will need to be extended through the Java Community Process (JCP) if XML content itself is to play a role in a messaging system's behavior (without client application involvement, that is). As specified by JavaSoft, the JMS message system itself does not provide programmatic access to the message body. Rather, any content that should be exposed to the subscriber for message selection or routing must be enclosed in the header fields and message properties. Content-based routing can be synthesized within client applications by extracting appropriate XML properties from the body of the message and placing them within the properties of the message header prior to sending it.

The future

Java messaging currently provides an excellent mechanism for the exchange of XML transactions. We have seen that the transport of XML can greatly benefit from awareness of -- and support for -- the loosely coupled, dynamic environments inherent in large-scale deployments. JMS addresses the needs of such environments beautifully, offering an elegant programming model for a wide variety of tightly and loosely coupled scenarios.

Potential enhancements to the JMS specification can deepen the relationship between these two technologies. For example, current JMS implementations provide subject-based routing, without any awareness of the XML being transported. Without this awareness, the XML content of a message cannot directly affect its routing, or any other aspect of messaging-system behavior. This is a strong motivation for the adoption of a full-fledged XML message type -- and value-added semantics around it -- within the JMS specification itself. This is indeed something that should be addressed by the JCP.

In addition, the JMS specification -- as it stands -- does not address wire protocols and non-JMS message interchange (though it is important to note that JMS implementations are already interchangeable at the API level). JMS solution providers are actively working on technology that will bridge their JMS messaging systems and other messaging and nonmessaging infrastructures. With JMS, it will be possible to obtain all the benefits of messaging within a large deployment domain, yet integrate with other legacy messaging systems and XML interchange protocols. Stay tuned -- and don't drop any XML transactions in the meantime!

Gordon Van Huizen is a seasoned software developer with 19 years of industry experience. His background fuses object technology with realtime, operating system, and network software internals experience. He has designed and developed solutions for Website generation, distributed electronic forms systems, network-based object licensing, and realtime data merging and imaging. As principal product manager for Progress Software, Mr. Van Huizen is responsible for the definition of the company's next-generation application server strategies.

Learn more about this topic

  • Other JavaWorld articles related to JMS

Join the discussion
Be the first to comment on this article. Our Commenting Policies