 | Level: Intermediate Bobby Woolf (woolf@acm.org), Independent consultant, Cyberdyne Software, Inc.
01 Aug 2002 JMS forms the foundation of messaging in enterprise Java applications, but has always treated point-to-point messaging and publish/subscribe messaging as completely separate domains with distinctly different types of messaging destinations. The JMS 1.0.2 API provides little support for an application using both domains together, and no support for developing reusable frameworks that can work equally well with destinations of either domain. JMS 1.1 fixes this shortcoming by unifying these domains. Join Bobby Woolf, J2EE architect and author, as he explores how much easier it is to develop JMS client code using the latest version.
The Java Message Service (JMS) API is an integral element of the J2EE platform. JMS 1.0.2 defines
two separate types of messaging domains, point-to-point and publish/subscribe. The latest version of
JMS, version 1.1, which will be part of J2EE 1.4 and will be required by EJB 2.1, unifies these domains.
With JMS 1.1, a client no longer has to be implemented specifically for one domain or the other. Instead,
JMS clients can be implemented to work with destinations from either domain. This significantly simplifies
the JMS API and offers developers an opportunity to create more general, reusable messaging code. Once JMS
providers and J2EE containers that implement JMS 1.1 become available, developers of JMS client code should
start using the version 1.1 APIs in their new code, and may also benefit from porting their existing
JMS 1.0.2 code to the new APIs. We'll be jumping directly into the new spec, so if you need a refresher on JMS, see A quick introduction to JMS. Three sets of interfaces
In JMS 1.0.2, the three channel interfaces -- Destination,
Queue, and Topic -- have the unfortunate consequence of
tripling the number of interfaces in the API. To send or receive messages, a client uses a
connection factory to get a connection, which it uses to create a session and obtain
message producers and consumers on the desired queues and topics. The only problem
is that each kind of destination has its own factory, connection, session, producer, and consumer
interfaces (basically, its own domain of interfaces), as summarized in Table 1 (from the JMS Javadocs).
Table 1. Relationship of point-to-point and publish/subscribe interfaces
| JMS Common | PTP Domain | Pub/Sub Domain | | ConnectionFactory | QueueConnectionFactory | TopicConnectionFactory | | Connection | QueueConnection | TopicConnection | | Destination | Queue | Topic | | Session | QueueSession | TopicSession | | MessageProducer | QueueSender | TopicPublisher | | MessageConsumer | QueueReceiver | TopicSubscriber |
Furthermore, JMS provides another set of interfaces for compatibility with XA (distributed) transactions.
This means that besides the 18 interfaces shown in the table, JMS has yet another nine interfaces --
XA versions of the factory, connection, and session types -- three times as many types as are really
needed.  |
Industry support for JMS 1.1
The next major release of the Java 2 Platform, Enterprise Edition (J2EE 1.4; currently in public draft status) will include JMS 1.1, so J2EE containers (application servers) such as IBM WebSphere and BEA WebLogic will need to implement JMS 1.1 to be certified as J2EE 1.4 compatible. Likewise, the next version of the Enterprise JavaBeans spec (EJB 2.1; also currently public draft status) will require JMS 1.1 to support its JMS message-driven beans. And J2EE 1.4 will include EJB 2.1, so those specs and JMS 1.1 all go together.
A number of products implement JMS 1.0.2, but what about support for JMS 1.1 or intentions to implement it?
Two commercial messaging systems (AshnaMQ 2.1 and the Sun ONE Message Queue, Platform Edition 3.0) and one open source messaging system (JORAM 3.1.0) currently implement JMS 1.1, but none of the other JMS/J2EE vendors, including IBM, BEA Systems, TIBCO Software, and Sonic Software, have announced plans to support JMS 1.1 in future releases of their products. Considering all these companies currently support either JMS 1.0.2 or J2EE 1.2 or 1.3, it seems to be just a matter of time before JMS 1.1 support is offered.
|
|
Of those 27 interfaces, only the six common interfaces (those in the first column) are
truly needed to send and receive messages. Queue and Topic are sometimes useful for distinguishing the point-to-point and publish/subscribe approaches. The other ten interfaces in the table and at least six of the nine XA interfaces are not really needed, at least not for writing client code. For example, with JMS 1.0.2, if a developer were accessing a Queue,
he would use a QueueConnectionFactory to get a
QueueConnection, to create a QueueSession,
which is used to create a QueueSender or
QueueReceiver. But this code is queue-specific and will not work with a
Topic. This approach will also work in JMS 1.1, but it is simpler to
just use ConnectionFactory, Connection,
Session, and MessageProducer or
MessageConsumer, which will also work with a
Topic just as well as a Queue.
So the developer should use the common interfaces and avoid the domain-specific ones, because
the common interfaces make the code simpler, more generic, and more reusable. Non-unified interfaces
In JMS 1.0.2, client code must use the queue and topic domain-specific interfaces. The common interfaces are largely ceremonial and do not declare many of the methods clients need. For example: Destination implements no methods at all; MessageProducer does not implement a
send method; MessageConsumer does implement
receive, but a Session client cannot create a
MessageConsumer; and so on. Thus, for a client to send and receive messages on a Queue, it
has to use the classes in the second column of Table 1, whereas a similar client using a
Topic has to implement very similar code using the classes from
the third column of Table 1. This lack of polymorphism among the common interfaces makes
it impossible to reuse queue clients with topics and vice versa, which leads to the kind of
duplicate code shown in Listing 1.
Domain unification
The major change in JMS 1.1 is the addition of new APIs to support client code that
works simultaneously with either the point-to-point or publish/subscribe domains.
Specifically, the latest release adds methods to the common interfaces to make the queue
and topic extensions polymorphic. For example, MessageProducer now implements
send, so a client can send a message to a destination without
knowing whether the destination is a queue or a topic. Likewise,
MessageConsumer declares the receive
method so that the same client code works whether it's using an implementation of a
queue receiver or a topic subscriber.
Listing 2 shows how to get a producer and consumer using this
unified interface. The JMS 1.0.2 code, shown in Listing 1, required
four methods (one pair for queues and another for topics) whereas the JMS 1.1 code only
requires two methods (one pair for destinations). These new APIs enable the developer to write JMS client code that is much more reusable.
It simply accesses destinations and uses them without needing to know which destinations are
queues and which are topics. Code written to access a queue can also be reused, unchanged, to
access a topic in the same way, and vice versa. This was not possible with JMS 1.0.2. Because the common interfaces are now able to perform almost all of the same tasks as
their domain-specific extensions (for example, MessageProducer
can do just about everything QueueSender and
TopicPublisher can), the domain-specific subinterfaces
are really no longer needed. These interfaces will probably be deprecated in future versions
of JMS. Shared transactions
A subtle but significant consequence of unifying the messaging domains is that queues
and topics can now be accessed through the same session and thus in the same transaction.
In JMS 1.0.2, a QueueSession could access more than one
Queue, and a TopicSession could access multiple
Topics, but a single session could not access both queues and topics.
Because sessions manage transactions, a single transaction could not be used to control
both a queue and a topic. In JMS 1.1, not only can a single Session access either a
Queue or a Topic
(either kind of Destination), a single session instance can
be used to manipulate one or more queues and one or more topics, all in a single transaction.
This means that a single session can, for example, create producers on both a queue and a topic,
and then use a single transaction to simultaneously send messages on both. Because of the
single transaction spanning both destinations, either the queue's message and the
topic's message both get sent, or neither of the messages gets sent. Likewise, a single
transaction can be used to receive a message on a queue and send it on a topic, or vice versa,
as shown in Listing 3. Consider a customer tracking application providing information to other applications
that use customer information, one of which is a shipping application. The tracking application
may need to tell the other applications that a particular customer's address has changed.
If using messaging, the application would publish this change on a topic,
CustomerChanges, and all of the applications that use customer
information would subscribe to this topic. The customer tracking application may want each
subscriber to report back whether it was able to process the change successfully. It would
specify a queue, ChangeProcessed, that each subscriber application
would use to send a reply. A subscriber application, such as the shipping application, would receive a change message on the
CustomerChanges topic, process it, and send a reply on the
ChangeProcessed queue. To ensure that no changes are lost, these three
steps (receive request, process request, and send reply) should be performed in a single atomic transaction.
This means that the shipping application must access both the CustomerChanges
topic and the ChangeProcessed queue using the same session. A session cannot
access both a topic and a queue in JMS 1.0.2, but can do so in JMS 1.1.
Conclusions
JMS 1.0.2 suffers from an explosion of subtypes; for each type, there is an interface
for the type itself, a queue extension, and a topic extension. Three times as many interfaces
means three times as many APIs for developers to learn. Client code has to use one domain or the
other, either the queue or topic set of extensions, so code written for one cannot be used for
the other. JMS 1.1 unifies the domains so that each common interface can be used instead of
its domain-specific extensions. This means there are fewer interfaces for developers to learn,
and the same client code can be used for both queues and topics. Furthermore, a JMS transaction
can now more easily span a topic and a queue, something that was not possible until the domains
were unified. The unified API in JMS 1.1 makes JMS client code simpler, easier to maintain, and more reusable.
Once vendors of JMS providers and J2EE containers implement JMS 1.1, developers writing new client
code should definitely use the unified APIs. While old client code written for JMS 1.0.2 will still
work fine in JMS 1.1, it may well be worth porting that code to the unified APIs to make it simpler,
too.
Download | Name | Size | Download method |
|---|
| j-jms11src.zip | | HTTP |
Resources - Download the example classes discussed in this article.
- Learn more about the Java Message Service API (JMS) at the JMS home page.
- Read about the changes in JMS 1.1 (last updated on March 4, 2002).
- Here's a list of vendors with products that implement JMS 1.0.2.
-
Java Message Service
by
Richard Monson-Haefel and David A. Chappell (O'Reilly, 2001) provides a good general introduction to JMS (version 1.0.2).
- In his popular tutorial "Introducing the Java Message Service" (developerWorks, August 2001), e-business architect Willy Farrell gives an excellent overview of JMS and offers the basics for developing programs that use it.
-
Java theory and practice columnist Brian Goetz examines how JMS can improve the flexibility and scalability of your enterprise applications (developerWorks, February 2002).
- In "Implementing vendor-independent JMS solutions " (developerWorks, February 2002), Java architect Nicholas Whitehead shows you how to combine JMS, the Java Naming and Directory Interface, and a well-made properties file to build vendor-neutral JMS solutions.
- "Get the message? Using JMS technology as a data replication solution" (developerWorks, February 2002) outlines how to use JMS for large-scale file replication.
- For more information about J2EE 1.4, which includes JMS 1.1, download the
platform specification and read the
JSR.
- For more information about EJB 2.1, which requires JMS 1.1, download the
specification and documentation and read the
JSR.
-
JORAM 3.1.0 from ObjectWeb is the first open source messaging system to implement JMS 1.1.
- Find hundreds of Java-related resources in the developerWorks
Java technology zone.
About the author  | 
|  |
Bobby Woolf is a J2EE architect and developer, author and speaker, mentor
and mentee, and works as an independent consultant in Raleigh, North
Carolina. He has used just about every part of the JMS client API: queues
and topics, messages delivered synchronously and asynchronously, sessions
transacted and non-transacted. He even experimented with temporary
queues once, but he didn't like them very much. Contact Bobby at woolf@acm.org.
|
Rate this page
|  |