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