From: www.itworld.com

Understanding Java messaging and JMS

by Frank Teti

May 7, 2001 —

 

Foreword


Java and Java-related technologies continue to be introduced and
continue to mature. As Java becomes more enterprise ready, as
opposed to application-platform centric, we are seeing the
introduction of more sophisticated Java-related middleware. This
month we discuss one such type of middleware, JMS. The JMS
specification will no doubt result in many new products in the
market. We describe what JMS is all about and how it compares with
alternate solutions. IT architects will now need to consider this
technology when designing messaging infrastructures.

--Kara Kapczynski

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 article will attempt 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 operations (see August 1999's IT Architect column for more details). 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:


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.


Remember: a carpenter is known by his tools, but good tools don't
make a good carpenter. JMS can be a good tool, but it should be
deployed within the appropriate framework.

Resources and Related Links