he Java Messaging Service (JMS) API, a Sun Microsystems interface for connecting Java programs to enterprise messaging middleware, is composed of multiple object interfaces with a hierarchy of relationships. The JMS class hierarchy in particular is extensive and can seem confusing at first glance. (Figure 1 illustrates the relationships among the classes within JMS.) However, this complexity is necessary for JMS to:
![]() |
|
Figure 1: The JMS Class Hierarchy (UML) |
Although the reasons for its complexity are sound, the relationships among JMS classes make writing code to the JMS API tedious and confusing at times. Applying the Facade pattern offers a solution to this problem.
A Facade is a design pattern that hides the details and complexities of the lower-level software service for which it is written, making the service easier to use. In fact, the lower-level classes need not be classes at all. They can be an API in the form of a code library or a Web service.
A Facade also provides a unified entry point into the layers of the software. This reduces your application’s dependency on the software service details and allows the Facade to hide future changes in the software service itself. JMS Class Model Complexity: Simplification Needed
The JMS class model is a complex structure that can be tedious to code to and difficult to remember. It can also result in a lot of duplicate code within your application, some for working with JMS topics and the rest for JMS queues. This section describes the highly involved sequence of code that JMS requires.
To use JMS, you first must get a connection to your JMS provider. Through JNDI, retrieve the javax.jms.ConnectionFactory
object, which you’ll use to get this connection in the form of a javax.jms.Connection
object (For an overview of JNDI, read the sidebar, “Java Naming and Directory Interface (JNDI)“.).
In JMS, messages are sent to, or received from, a destination. The javax.jms.Destination
class is the base class to the more familiar javax.jms.Topic
or javax.jms.Queue
classes. We’ll discuss these classes in more detail as we go along.
You must create a javax.jms.Session
object for every javax.jms.Destination
in which your application is interested. To create a Session object you must call the appropriate method on the Connection object. Each Session can be used by only one thread at a time. This means that for two or more threads to listen to the same Destination, they each must retrieve their own instance of a Session object for that Destination.
In turn, you use a Session object to create a javax.jms.MessageProducer
object to send messages to a Destination, a javax.jms.MessageConsumer
object to receive messages, and the javax.jms.Message
objects themselves.
All the classes discussed so far are actually abstract interfaces, thus they cannot be instantiated themselves. Instead, JMS defines more specific classes that extend these interfaces.
To clarify, the UML diagram in Figure 2 illustrates the extended class model for the ConnectionFactory
, Connection
, and Session
classes.
![]() |
|
Figure 2: The JMS Connection and Session Types |
You must know ahead of time whether you will need a TopicConnectionFactory
, a QueueConnectionFactory
, or both. References to these objects also are retrieved through JNDI. The only difference between the two connection factory classes is the type of Connection object each one creates: a TopicConnection
or a QueueConnection
. In turn, the only difference between these two connection objects is the type of Session object each one creates: a TopicSession
or a QueueSession
.
The UML diagram in Figure 3 illustrates the class model for the remaining classes, Destination
, MessageProducer
, and MessageConsumer
.
![]() |
|
Figure 3: Topic and Queue Subclasses |
The Topic
and Queue
classes are subclasses of the Destination super class. Typically, destinations are created ahead of time through an administration interface on your JMS Provider. However, a TopicSession
or QueueSession
object can create Topic
or Queue
objects at runtime, respectively.
The TopicPublisher
and QueueSender
classes extend MessageProducer
, and they send messages to a Topic
or Queue
, respectively. Similarly, the TopicSubscriber
and QueueReceiver
classes extend MessageConsumer
, and they receive messages from a Topic
or Queue
, respectively.
For the sakes of improvement and simplification, you should create a JMS Facade class.The JMS Facade
The JMS Facade attempts to merge the publish/subscribe and point-to-point message models into one interface, hiding the model itself from the programmer. In my experience, application code written around the publish/subscribe model is very similar to that written around the point-to-point model. The difference lies in the details of how each delivers the messages themselves. This difference can be considered an implementation detail and, hence, should be hidden from developers in most cases. (For an overview of the JMS message models, read the sidebar, “The Java Message Service (JMS)“.)
To use the JMS Facade, start by importing the com.JMSFacade
package. Next, create an instance of the com.JMSFacade.JMSManager
class, as shown in Listing 4. JMSManager
does all the work.
Listing 1. The com.JMSFacade PackageThis is an example of importing and creating the JMS Facade class, JMSManager :
|
Subjects
The JMS Facade attempts to abstract the concepts of publish/subscribe (Topic) and point-to-point (Queue) using the term “subject.” Very simply, code written around the JMS Facade listens to, or sends messages to, a subject that is nothing more than a text name. It is not required to denote whether the destination is a topic or queue at this point?or ever.
Subject Creation
You don’t need to create subjects explicitly, even though the JMS Facade does allow it. The Facade creates subjects automatically when you call the listen
or send
methods. The only reason to explicitly create a subject is to control the message-delivery model, publish/subscribe or point-to-point. The default model is publish/subscribe.
To specify the message-delivery model, your code must call the createSubject
method on the JMSManager
class. This method requires two parameters:
String
com.JMSFacade.JMSManager.BROADCAST_SUBJECT
or com.JMSFacade.JMSManager.SEND_ONCE_SUBJECT
A subject type specified as BROADCAST_TYPE
is equivalent to a JMS Topic
, which is the publish/subscribe model. A subject type of SEND_ONCE_SUBJECT
is equivalent to a JMS Queue
, which is the point-to-point model.Receiving Messages
To receive messages for a particular subject, you simply call one of the two listen
methods that the JMSManager
class provides. One version of the method delivers messages synchronously, while the other delivers messages asynchronously.
Notice that as I’ve described the listen
methods, I haven’t mentioned topics or queues. This is because, as discussed above, these details of message delivery don’t need to be exposed at this level.
Asynchronous Message Delivery
To receive messages asynchronously, call the version of the listen
method that requires both a subject name and a callback reference. This call returns right away, and your code is free to do whatever processing it needs to do.
When a message arrives for the specified subject, a method is called on the provided callback reference. The callback reference must be an object that implements the javax.jms.MessageListener
interface. The only method defined by this interface is onMessage
, which provides the message itself through a parameter defined as javax.jms.Message
.
The callback reference is continuously called for each message that arrives until your application instructs the JMS Facade to stop. To stop listening to messages on a subject, simply call the stop
method and provide the applicable subject name as the parameter.
You don’t have to create multiple instances of the JMSManager
class to asynchronously listen to more than one subject at a time. One instance will do the job. However, your code will need to call listen
once for each subject.
Synchronous Message Delivery
If the code you’re writing has no other purpose but to receive messages and perform processing only when they arrive, you may chose to use the synchronous version of the listen
method. You call this version of listen
by providing only the subject name to which the method will listen. The call will not return until a message arrives for the subject. When a message does arrive, it is returned from the call in the form of a javax.jms.Message
object.
With synchronous message delivery, your code must call listen
again after a message arrives in order to receive additional messages for the specified subject. To stop receiving messages for a subject, you simply do not call listen
after a message arrives. Therefore, with the synchronous version of listen
, you never need to call the stop
method of the JMS Facade.
Sending Messages
To provide flexibility, the JMSManager class defines three send
methods. The difference between them is the type of message payload each sends:
String
javax.jms.Message
objectBesides the message payload type, each send
method works the same way, requiring a subject name to send the message to.
As with receiving messages, topics or queues aren’t mentioned. Only a subject is specified. Again, the details of message delivery are hidden at this level. However, it is normally important for a message sender to specify the message-delivery paradigm. The sender may want the message broadcast to all listeners (publish/subscribe) or only to one listener, one time (point-to-point).
Still, you can’t specify this option at the time a message is sent. The message-delivery model is a characteristic of the subject itself. To control it, your code can specify the model by creating the subject before sending or receiving messages for the applicable subject (see the previous section, Subject Creation).
You shouldn’t need more than one instance of JMSManager
, even if your code needs to send messages to more than one subject. You may call the send
method as many times as you need, specifying the same or different subject names as required each time.
JMS Made Easy
The Facade class provides a good starting point for making JMS easier to work with in your code. To see how truly easy it makes working with JMS, download my JMS Fa