New York University

Computer Science Department

Courant Institute of Mathematical Sciences

 

Understanding Java Messaging and JMS

 

Course Title: Application Servers                                     Course Number: g22.3033-011

Instructor: Jean-Claude Franchitti                                      Session: 5

 

Before building an application framework, you must first choose the messaging construct most appropriate to your needs. The JMS Sun specification and model environment has advantages and disadvantages compared to RMI, JavaSpaces, InfoBus, and JSDT.

 

In October 1998, JavaSoft released the Java Message Service (JMS) specification v1.0.1, an API for accessing enterprise messaging systems from Java. Because JMS is equipped to handle both synchronous and asynchronous messaging, it represents a possible alternative to strictly synchronous RMI.

This handout attempts both to define JMS and to compare it with other Java messaging or traditional message-oriented middleware (MOM) messaging paradigms. The main objective is to help you understand where JMS might fit into a Java-based, enterprise-wide application architecture.

JMS is a set of interfaces and associated semantics that define how a JMS client accesses the facilities of an enterprise messaging product. Enterprise messaging is recognized as an essential tool for building enterprise applications and ecommerce systems, and JMS provides a common way for Java programs to create, send, receive, and read an enterprise messaging system's messages.

With a solid implementation of JMS, one can implement client/server or server/server asynchronous applications without CORBA. However, most ISP implementations of JMS are by small firms that are trying to implement a fairly comprehensive spec. Sun, though, has clearly stated that a vendor does not need to implement the entire spec, only domains within the spec. Sun has also indicated that there are domains outside of the scope of the spec that should be implemented in order to provide a truly enterprise-wide and robust messaging environment.

EAI = MOM = JMS


Enterprise Application Integration (EAI) using MOM products is becoming an essential component for integrating intracompany. While JMS can be used by itself and not just as a wrapper for MOMs, Sun's primary intention is for corporations to use it in conjunction with such MOM products as TIBCO or MQSeries.

The strategic intention of some JMS vendors is to provide Java interfaces to MQSeries and TIBCO -- interfaces that allow the developer to program in pure JMS using Java APIs, while using MQSeries, TIBCO, and the like as the low-level transport. This means an organization might not need to change its underlying transport middleware; JMS gives developers a standard Java API so messages can be sent transparently across the organization via TIBCO or MQSeries.

JMS is clearly the missing piece in the enterprise Java architecture, and Sun has already introduced a number of major service APIs -- JDBC (for database access), JNDI (for naming and directory services), and a Java mail API -- that are required in order to write applications that integrate across the enterprise.

The JMS object model


The two dominant messaging approaches in use today and defined in the spec are the Topic, or point-to-point messages, and the Queue, or publish-and-subscribe messages. Because many message systems support only one of these styles, JMS provides a separate domain and defines compliance for each. On an operational basis, when an asynchronous Queue message is in flight, it goes to the JMS server, which forwards it to all interested applications currently running and stores it for those applications that aren't.

 

 

 


 


Figure 1. JMS Session, Connection, and Message common facilities

 

Figure 1 depicts the JMS objects necessary to provide JMS connectivity to a remote server. The ConnectionFactory is an administered object used by a client to create a Connection, which itself is an active connection to a JMS provider. Because of the authentication and communication setup processed when a Connection is created (most clients will do all their messaging with only one), it is a relatively heavyweight JMS object. The Destination encapsulates the identity of a message destination and contains provider-specific address and configuration information.

Sessions are the JMS entity that support transactions and asynchronous message consumption. JMS does not require that client code be used for asynchronous message consumption, or that it be capable of handling multiple, concurrent messages. Instead, transaction multiplexing within a connection is demarcated and encapsulated within a Session.

A Session is an atomic unit of work similar to a database transaction. It is very difficult to implement multithreaded transactions, and Sessions provide the throughput advantages of concurrency with the ease of single-threaded programming.

MessageProducer and MessageConsumer objects are created by a Session and are used for sending and receiving messages, respectively. In order to guarantee the delivery of a message, messages to and from the remote server object should be sent in persistent mode. The persistent mode instructs the JMS provider to log the message to stable storage as part of the client's send operation. This in turn ensures that the message will survive a JMS provider failure.

Session, MessageProducer, and MessageConsumer JMS objects do not support concurrent use, while ConnectionFactory, Destination, and Connection objects do. After these objects and common facilities are in place, a client application has the basic JMS setup needed to produce and consume messages.

JMS has five types of message, and while the type used depends on the requirements of the application, most client implementations use either MapMessage or ObjectMessage. ObjectMessages -- messages containing a serializable Java object -- make it clear to programmers which data type and field they're receiving and setting. MapMessages use a set of name-value pairs, where names are strings and values are Java primitive types. Alternatively, JMS TextMessages might be more appropriate for XML-based messages, where JMS is used for the transport layer, but not data definition.

All JMS messages support the acknowledged method for use; if a client uses automatic acknowledgment, calls to acknowledge are ignored. JMS messages sent by a Session to a Destination must be received in the order in which they were sent, so their implementations must provide for the sequencing of incoming messages.

The JMS specification does not address the following functionalities:

A wire protocol for messaging

A message metadata repository

Load balancing criteria

Fault tolerance mechanisms

Administration API or monitor security

Sun seems to have opened the door for these extensions to be implemented by JMS vendors on a proprietary basis.

The JMS model specification versus implementation


The conceptual model shown in Figure 1 was developed using the Sun JMS specification, and assumes that JMS vendor implementations provide the appropriate functionality as described in that specification. It is recommended that an organization run appropriate tests on multiple JMS implementations before choosing one.

Test suites are extremely important because they gauge the quality of the JMS implementation an organization is planning to use, and also perform compliance, robustness, and reliability testing. For example, some JMS vendors have suites that include tests for each line of the draft specification. The strategy here should include test suites that check for durable subscriptions, persistent messages, commit/rollback of transactions, etc.

 

Synchronous messaging code fragment

This code fragment implements a synchronous receiver (subscriber) that synchronously receives messages published on the topic (i.e., primaryTopic). Note that no exception handling code is included, which makes it easier to see what's happening. The fragment loosely implements the objects depicted in Figure 1.

 

 

// 1. Create the InitialContext object used for looking up JMS administered objects located on // the default host.

 

 

InitialContext ic = null;

 

 

ic = new InitialContext ();

ic.bind ();

 

 

// 2. Lookup Connection Factory and Topic names

 

 

TopicConnectionFactory tcf =

    (TopicConnectionFactory) ic.lookup ("primaryTCF");

Topic topic = (Topic)ic.lookup("primaryTopic");

 

 

// 3. Dispose of the InitialContext resources

 

 

ic.dispose();

 

 

// 4. Create and start a topic connection

 

 

System.out.println("Creating topic connection");

TopicConnection topicConnection = tcf.createTopicConnection();

topicConnection.start ();

 

 

// 5. Create topic session on the connection just created

 

 

System.out.println("Creating topic session: not transacted, auto ack");

TopicSession topicSession = topicConnection.createTopicSession(false,1);

 

 

// 6. Create subscriber

 

 

System.out.println("Creating topic, subscriber");

TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);

 

 

// 7. Listen for messages

 

 

System.out.println ("Ready to listen for messages synchronously (blocking

receive)");

    while (true)

    {

      TextMessage textmsg2 = (TextMessage)topicSubscriber.receive();

      System.out.println("Received : " + textmsg2.getText() );

    }

 

 

...

 

 

JMS versus RMI


Remote method invocation (RMI) provides the semantics of object invocation within a distributed object system. In such systems, a local surrogate (stub) object manages the invocation on a remote object. While other RMI-type systems (e.g., CORBA) can be adapted to handle Java objects, they fall short of seamless integration due to their interoperability requirement with other languages. In contrast, the Java RMI system assumes the homogeneous environment of the Java Virtual Machine, and can therefore take advantage of the Java object model whenever possible.

Because of RMI's inherent weaknesses -- limited client connections, poor performance due to lack of resource pooling, no store-and-forward or load balancing, lack of guaranteed messaging and security, as well as static clients and servers with location-dependent code -- asynchronous JMS messaging provides a better way to implement distributed solutions. Some of these architectural weaknesses are addressed within the JMS specification, while others are implemented by JMS vendors. For example, Fiorano Software's JMS implementation provides a form of load balancing through a server-clustering architecture that connects neighboring servers.

Consider JMS a robust alternative to RMI, but not a replacement. JMS can be implemented on top of RMI (java.rmi.server.RMISocketFactory) or Java sockets (java.net.Socket), and its implementations that use sockets directly will provide better message throughput than RMI-type JMS implementations.

JMS versus JavaSpaces


JavaSpaces is a distributed persistence and data exchange mechanism for Java. With JavaSpaces, one writes data in entries that are in fact a typed grouping of fields. Clients operate on a JavaSpace to write new entries, look up existing entries, and remove entries from the space. This allows Java programs to store their state and lets applets store state on servers when they can't store it on the client because of security restrictions.

JavaSpaces is a simple and elegant API that runs on top of RMI and has a set of interfaces for leasing, transactions, and distributed events. Applications requiring these services could be written with JMS, but some developers opt to use JavaSpaces and its associated APIs rather than going out and buying a JMS implementation from another company. Sun has noted the possibility that JMS will define other messaging domains (like distributed events) in a future release; however, this is not the case with JMS 1.0.

JavaSpaces can also be seen as a set of APIs for making transient objects on a small scale, and as a Jini application confined to small local networks (since it can't travel through firewalls). You might also want to position JMS differently than JavaSpaces based on service level agreements (SLAs) with users, in which you guarantee certain performance and response times. JavaSpaces relies on RMI as the communications mechanism and doesn't lend itself to high-speed communications, like collaborative video and voice delivery.

JMS versus InfoBus


InfoBus is a solution for interconnecting such Java components as Lotus's Kona applets; it is also a virtual traffic cop that polices the multiple components executing on a Web page. It dynamically tags applets by content (e.g., name and spreadsheet values), and also includes the data producer, data consumer, and data controller modules. The tags allow information to be exchanged with multiple components at runtime, and any JavaBeans component written to the InfoBus API can exchange data with other applets.

The JavaBeans InfoBus Lotus specification is intended to provide standards by which a wide range of Java components, acting as data producers and consumers, can communicate data. Its architecture facilitates the creation of applications built from JavaBeans that exchange data asynchronously. InfoBus can also be used by arbitrary Java classes, including applets and servlets, and is designed for components working together in the same Java Virtual Machine (whereas JMS is designed for distributed messaging systems).

JMS versus JSDT (Java Shared Data Toolkit)


The Java Shared Data Toolkit is a development library that allows developers to easily add collaboration features to applets and applications written in the Java programming language. Enterprise developers can use JSDT to create network-centric applications, such as shared whiteboards or chat environments. It can also be used for remote presentations and shared simulations, and to easily distribute data for enhanced group workflow.

While JSDT is designed for dealing with many simultaneous users of an application, JMS fits into the groupware category in a nonrealtime fashion. And, just as JSDT uses raw IP as its delivery mechanism, JMS can use higher-level protocols (SMTP, RMI, and Java sockets).

JSDT is designed for highly collaborative, high-bandwidth services, and to work across the Internet by using the HTTP transport mechanism. JSDT can also travel through firewalls, and may use one of many transport mechanisms and lightweight, high-speed protocols.

High on the wish list for JSDT is the implementation of a Jini-based transport mechanism, which would allow its true distributed nature to finally shine through.

Architectural implications


Which particular messaging system you choose to deploy depends on your application requirements. In environments where CORBA has not been embraced, and Java applications need to communicate with each other asynchronously (without concern for whether the remote application is up or not), JMS is probably the way to go. On the other hand, RMI is a viable choice for simple, synchronous messages where performance is not an issue.

For ecommerce solutions, JMS can be used across the firewall through HTTP tunneling (with HTTP, connections die after data is transmitted once). Because synchronous data operations cannot be pushed from the server to the client, using HTTP connections between a JMS client and the JMS server results in major inefficiencies. The system becomes like RMI, based on polling, and although HTTP tunneling is possible with JMS, it's nonetheless inefficient.

The strategic purpose of JMS is to define a specification and an API, then let MOM vendors implement to it. Developers should be able to write Java messaging applications that work on top of all the different MOM providers, without having to change a line of their code. Pursuing this strategy keeps Java programmers productive by insulating them from low-level transport APIs while delivering enterprise-wide messaging.