HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

The Java Message Service, by Dave Chappell

The Java Message Service (JMS) is an enterprise-capable middleware component based on message-oriented middleware (MOM) fundamentals. Since its introduction as a Java software specification in November 1998, vendor implementations have brought JMS forward as a first class, e-business messaging communications platform suitable for exchanging critical business data over the Internet.

This article is the first in a series of three that explain the application program interfaces (APIs), the message delivery semantics, and the deployment environments that are well suited to JMS applications.

What Is JMS and Where Did It Come From?
JMS defines the first and only standard for asynchronous MOM implementations. The specification defines a common set of APIs and message delivery semantics. A developer can write an application using the JMS APIs and enjoy the freedom of choosing among many vendor implementations (JMS providers) on the market today.

The JMS specification was an industry effort, and JavaSoft worked closely with the messaging vendors to produce it. The intent of the effort was to standardize on a common set of APIs and message delivery semantics across all messaging products. That intent changed over the course of the work to provide a specification for a first-class middleware on equal footing with RPC-like solutions such as RMI, CORBA, and EJB. The result is not a least common-denominator compromise but a powerful list of features. These features are a superset of the capabilities provided by the messaging vendors who participated in the effort. Since then, a new breed of JMS-based products, such as SonicMQ, have been built from the ground up with the goal of delivering high volumes of messages across the Internet in a secure, reliable fashion.

JMS As Part of the J2EE Strategy
Thus far JMS has been an optional part of the J2EE platform. Until recently both EJB and JMS servers were not explicitly related or tied to one another. With the introduction of the upcoming 1.3 J2EE specification, JMS will become a required component of the J2EE strategy. The recent renditions of the EJB 2.0 specification introduce the notion of a MessageDrivenBean. The MessageDrivenBean is a special kind of EJB that exists solely for producing and consuming JMS messages in an EJB server environment. More details on this new model will be discussed in an upcoming article.

Standards Enable Best-of-Breed
Application server vendors have been clamoring to meet this new J2EE requirement through building, buying, and partnering in order to round out their J2EE offering and provide a JMS server in the box. The good news is that regardless of what JMS offering is provided in the box of an EJB vendor, the integration points between an EJB server and a JMS provider are fairly well defined. You may choose your own best-of-breed JMS vendor offering for stand-alone messaging applications and still enjoy the convenience of integrating with the EJB server when EJB and messaging need to be used together.

The JMS Specification
The JMS specification defines such things as multiple messaging models in terms of publish and subscribe (pub/sub) and point-to-point queuing. While largely intended to be an asynchronous form of communication between applications, there's also a set of design patterns and helper classes to perform a synchronous and an asynchronous request/reply model on top of pub/sub and point-to-point. There's also a rich and flexible definition of what a message is composed of, and strict rules governing store-and-forward messaging, guaranteed delivery, message acknowledgments, transactions, and recovery from failures.

JMS applications use the JMS API to communicate with one another using producers and consumers. Senders produce messages and receivers consume them. An application may be both a producer and a consumer at the same time. For instance, a manufacturer may broadcast a request for price quotes to interested suppliers (consumers). At the same time, suppliers may be responding with proposals in the form of XML documents.

Producers and consumers are loosely coupled with each other (they're not directly tied to each other). They're abstractly connected through virtual channels that are administratively defined and accessed programmatically via a JNDI lookup().

Messaging Domains
JMS defines two messaging models - publish-and-subscribe and point-to-point queuing. In JMS terms these are referred to as messaging domains. As shown in Figure 1, the pub/sub domain is intended for a one-to-many broadcast of information, while the point-to-point domain is intended for a one-to-one communication between two specific applications.


Figure 1

In the pub/sub model, multiple consumers may register an interest with, or subscribe to, a virtual channel called a Topic. A producer uses the publish() method to send a message on that Topic. Each subscriber receives a copy of that message.

In the point-to-point model, only one consumer may receive a message that's sent to a queue. As shown in Figure 1, a point-to-point queue may have multiple consumers listening on a queue for the purposes of load-balancing or "hot backup"; still only one receiver may consume each individual message.

Quality of Service (QoS)
The message delivery semantics cover a range of once-and-only-once to at-most-once delivery. In the once-and-only-once delivery mode, a message is guaranteed by the JMS provider to always arrive at the intended destination no matter what, and it's sent only once. Even in the pub/sub model in which multiple receivers may consume a copy of a broadcasted message, the rules still apply within the relative view of each consumer. Once-and-only-once delivery guarantee is accomplished by the JMS provider through the combination of a store-and-forward mechanism and a rigidly defined set of message acknowledgments (see Figure 2).


Figure 2

At-most-once delivery is a less stringent QoS setting on a message - the JMS provider is allowed to occasionally lose a message. A classic example I like to use is a stock feed application. If the broadcast of a particular ticker symbol doesn't reach its intended destination, another one will be along shortly.

Whether it's once-and-only-once or at-most-once, the key word is once. Regardless of the guaranteed-ness of the delivery mode, the JMS provider is responsible for ensuring that the messages are delivered in the exact order in which they are sent.

What's in a Message?
A message is composed of three basic parts: headers, properties, and the message payload. The headers are used by the JMS provider and the application developer to provide information about such things as the destination, a reply-to destination, the message type, and the message expiration time.

The property section contains a set of application-defined name/value pairs that are accessible via an extensive assortment of setters and getters on the Message object.

The message payload can contain any type of application data and is accessible in a number of forms. There are five prescribed message types:

  • BytesMessage: A stream of bytes intended for any arbitrary data, binary or otherwise. Typically useful for data that's opaque to the messaging system (not Java accessible), yet structured in some native format that's known to the sending and receiving application.
  • ObjectMessage: A set of objects accessible by Java programs.
  • MapMessage: A set of name/value pairs in a variety of data types.
  • StreamMessage: Similar to BytesMessage and ObjectMessage, with the added value that a message may be read from and written to using a familiar file stream metaphor.
  • TextMessage: Plain text.
  • XMLMessage: Not part of the JMS standard. However, many JMS vendors now include an XMLMessage type. It allows an application to construct and deconstruct a message using a DOM tree.

JMS and XML - An Ideal Marriage
XML is fast becoming the lingua franca for describing business data for interapplication communication. However, XML on its own doesn't carry with it a reliable way of getting your critical XML documents through the treacherous waters of today's B2B or geographically dispersed intracompany communications environment. Hardware issues can occur, such as network or server machine failures. Applications that participate in a distributed application environment can crash or have scheduled downtimes. Applications need a way of transmitting data between one another reliably. JMS provides the guaranteed delivery semantics to ensure that critical business data gets delivered across a sometimes hostile environment in a once-and-only-once guaranteed fashion.

JMS As the Basis for an E-Business Messaging Environment
The term e-business messaging is intended to describe the type of communication infrastructure that's necessary for doing B2B communications over the Internet. Although the term B2B is overloaded and overused, the generally accepted - and simplest - definition of B2B is the ability to conduct business electronically between applications that span corporations.

Whether dealing directly with suppliers or communicating through a trading exchange, a manufacturer or a wholesaler may have thousands of suppliers to deal with. With that size of a trading partner community, there may be thousands, even hundreds of thousands, of electronic data exchanges between multiple parties.

There are many challenges to consider when building an e-business messaging infrastructure:

  • Guaranteed delivery of data
  • Massive scalability
  • High availability and reliability
  • Security, authentication, and access control
  • Internet firewalls
  • Standards and connectivity
A JMS communications layer provides a key ingredient for such a communication infrastructure. It provides the guaranteed once-and-only-once delivery and guaranteed ordering of messages in an asynchronous fashion between applications, and a simple yet flexible API to connect applications into the messaging system. It strongly dictates message delivery behavior with regard to message persistence, acknowledgments of message receipt, transactional groups of messages, failure conditions, and recovery rules.

However, JMS by itself doesn't provide all the additional elements to meet the described requirements of e-business messaging. It's a specification that's intentionally agnostic with regard to wire transport protocols and deployment architectures. It doesn't dictate a security model beyond a simple username and password at connection time. In recognition of this, many JMS vendors are providing these additional capabilities on their own.

I'm Sold on JMS! What Does This API Look Like?
The JMS API is conceptually simple to understand. There are three things you need to learn: connect, send, and receive. Beyond that are a handful of interfaces, such as ConnectionFactorys beget Connection objects. A connection may have one or more Session objects. A session is responsible for managing producers and consumers (senders and receivers).

A ConnectionFactory may either be a TopicConnectionFactory for pub/sub or a QueueConnectionFactory for point-to-point. Likewise, a connection may either be a TopicConnection or a QueueConnection. Figure 3 illustrates the interfaces.


Figure 3

The publish() method sends a message to a pub/sub topic. The send() method sends a message to a point-to-point queue. From the consumer's perspective, the message may be passively consumed via the onMessage() callback, or a message may be proactively received using the receive(), receive (long timeout), and receiveNoWait() methods.

The code snippet in Listing 1 shows the steps necessary for setting up a connection, session, TopicPublisher, and sending a message. This simple example sends a message to itself.

That's all that's required to set up a sender and a receiver. It's quite simple. The onMessage() handler is responsible for receiving the message, which is invoked automatically by the JMS provider. It looks like this:

public void onMessage( javax.jms.Message message){
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.get
Text());
}

The point-to-point queue version of this is very similar. The structure of the code remains the same, and the names of some of the objects are slightly different. That's one of the nice things about JMS. Even though there are two different messaging models, the naming conventions and the API usage model are extremely similar. It's easy to switch from one to the other if you change your mind.

Now that you see how easy it is to use the JMS specification, you're well on your way to becoming an expert in the J2EE platform's hottest new addition to its family. Get the message!

Author Bio
Dave Chappell is chief technology evangelist for Progress Software's SonicMQ, and coauthor of O'Reilly's Java Message Service. chappell@progress.com

	


Listing 1

Properties env = new Properties();
// ... specify the JNDI properties specific to the JNDI SPI being used
...
jndi = new InitialContext(env);
// obtain a connection factory
factory =
    (TopicConnectionFactory)jndi.lookup("TopicConnectionFactory");
// create a connection
connect = factory.createTopicConnection (username, password);


// create a session for publishing, and one for subscriptions
pubSession =



connect.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
subSession =
    connect.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);


myTopic = (Topic)jndi.lookup("My First Topic");


// create the publisher and the subscriber
publisher = pubSession.createPublisher(myTopic);
subscriber = subSession.createSubscriber(myTopic);


// associate the onMessage() handler with this subscriber
subscriber.setMessageListener(this);


// start the flow of incoming messages
connect.start();


TextMessage textMsg = pubSession.createTextMessage();
textMsg.setText("My first JMS message!);


publisher.publish(
    textMsg,
    javax.jms.DeliveryMode.PERSISTENT,          // delivery mode
    javax.jms.Message.DEFAULT_PRIORITY,    // message priority
    1800000); // Time-to-live (30 minutes)

  
 

Download Assoicated Source Files (Zip format ~ 59.5 KB)

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: info@sys-con.com

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.