Simplify JMS with the Facade Design Pattern

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:

  • Abstract the implementation details of the underlying messaging software
  • Interface with existing messaging systems such as IBM’s MQSeries, using familiar JavaBean paradigms
  • Provide and enforce thread-safe code practices
  • 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 Package
    This is an example of importing and creating the JMS Facade class, JMSManager:

    import com.JMSFacade;import javax.jms.*;public class myClass{    JMSManager jmsMgr = new 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:

  • A unique subject name in the form of a String
  • A subject type (the message-delivery model), which is either 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:

  • A simple text message in the form of a String
  • A serializable Java object
  • A javax.jms.Message object
  • Besides 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

    Share the Post:
    Share on facebook
    Share on twitter
    Share on linkedin

    Overview

    Recent Articles:

    ©2023 Copyright DevX - All Rights Reserved. Registration or use of this site constitutes acceptance of our Terms of Service and Privacy Policy.

    Sitemap