JavaData & JavaBuilding Messaging Systems with JMS

Building Messaging Systems with JMS

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

To begin with, it’s necessary to mention that we expect from the reader a rather solid knowledge of Java programming to understand this article. We will try to easily explain what JMS is, but before you can create your own programs and understand them correctly, you need to have experience in developing real applications working with JNDI.

JMS (Java Message Service) is a standard of message exchange that allows J2EE application components to create, send, receive, and read messages. It supposes that the distributed communications have a free connection, reliable and asynchronous.

The Exchange System

The message exchange represents a way of interaction between program components or applications. The system of message exchange is a system with equal rights: The client of a similar system can both send and accept messages from any other client. Each client incorporates to the agent of the system that provides an opportunity to create, send, accept, and read messages.

The exchange system makes the distributed interaction possible. The component sends the message in Destination, and the addressee can take this message from the same Destination. Nevertheless, the sender and the addressee should not necessarily be accessible at one time to cooperate with each other. In other words, the sender is not obliged to know something about the addressee and the addressee is not obliged to know something about the sender. The sender and the addressee should know only about what format of messages and what Destination to use. In this respect, the described system differs from technologies closely connected to it, such as Remote Method Invocation (RMI), demanding from the application a knowledge of the remote application’s methods.

The Messaging System

Messaging System—is a distributed system based on an asynchronous messages exchange between system components. Message-Oriented Middleware (MOM) is that product, on the basis of which Messaging System is built.

Messaging System applications do not communicate directly (in comparison to traditional systems (RMI based)), but with the help of MOM. If one component of the system wants to send the message to another component, it sends the given message to MOM, and MOM then sends the message to the addressee.

The following advantages compare with the traditional systems constructed on basis of RMI:

  • The application that sent the message should not expect a reply, and can continue activity.
  • Neither the application that sent the message nor the addressee of the given message are obliged to be active at a given time. If the message addressee is not active, MOM guarantees that the message will be delivered as soon as the addressee becomes active.
  • System components are not connected directly with each other. They are decoupled; that is why transferring components from one host on another in runtime is possible without breaking the system’s serviceability.

The Models of Exhange: Point-to-Point and Publish-Subscribe

There are two “basic” models of message exchange: the point-to-point model and the publish-subscribe (pub-sub) model. A point-to-point model is applied when it is necessary for one or several component senders to send the message only to one component, the addressee (receiver). The model is based on the concept of a message queue: Senders send messages into the queue, and the receiver reads messages from this queue. In the point-to-point model, several receivers can exist, attached to the same queue. However, MOM will deliver the message only to one of them. To which depends on the MOM implementation.

A publish-subscribe model is applicable when it is necessary for one or several components—publishers—to send the message to one or several components—addressees (subscribers). The given model is based on the message topic concept: Publishers send messages in a topic, and all subscribers of the given topic receive these messages.

The pub-sub model seems to be more “elegant,” but many pub-sub systems do not guarantee delivery of messages in the order in which they have been sent (as opposed to point-to-point, where the queue realizes the FIFO (first-in/first-out) principle). Therefore, in the case of pub-sub, models should be avoided whenever possible in situations when the order of following the messages is important (or it will be necessary to use headers and properties sections of messages for synchronization).

Java Message Service (JMS) is a Java API for working with Message-Oriented Middleware, allowing your applications to create, send, accept, and read messages. The given set is located in a javax.jms package in a tree of J2EE packages. JMS is implemented in many MOM-products, among which iPlanet Message Queue, IBM MQSeries, Progress Software SonicMQ, BEA WebLogic Server, Prism Technologies OpenFusion, and so forth are best known. A freeware implementation also exists.

JMS supports both “basic” models of message exchange. However, the specification does not require the manufacturer to implement both models, although the majority of JMS products implement the point-to-point and pub-sub models.

JMS Applications

The main parts of JMS applications are:

  • ConnectionFactory and Destination
  • Connection
  • Session
  • MessageProducer
  • MessageConsumer
  • Message

ConnectionFactory is the object responsible for creating JMS Connection. Each such ConnectionFactory is a copy of QueueConnectionFactory or TopicConnectionFactory. The MOM manager creates the given object and connects it with the JNDI tree so the JMS client can get access to ConnectionFactory using a standard JNDI lookup. In the case of a point-to-point model, it is using javax.jms.QueueConnectionFactory; in the case of pub-sub models, javax.jms.TopicConnectionFactory.

Destination—it’s a queue or topic, depending on which model we are using: javax.jms.Queue or javax.jms.Topic.

Connection—it can be an open TCP/IP between the client and supplier service. It can be used to create one or few sessions. Before your application can receive messages, you need to call the start() method. To pause sending messages, you need to call stop().

Session—the object created with help of JMS Connection and used by clients to send and receive messages.

MessageProducer—the object created by the session and used to send messages in Destination.

MessageConsumer—the object created by the session and used to receive messages. To synchronously receive the message, the receive() method is used. For asynchronous, MessageListener is used with only one method—onMessage(). In this method, actions that should be executed after the arrival of the message are defined.

Message—the message itself. The JMS message will consist of three parts:

  • Header
  • Properties (not necessary)
  • Body (not necessary)

A more detailed explanation is beyond the scope of this article; you can specify these details with the help of official documentation.

When working with EJB 2.0

It’s necessary to note the following:

In the new EJB 2.0 specification, integration with JMS was done with the help of creating a new EJB type: the Message Driven Bean (MDB). The feature of MDB is that the client does not communicate with it with a remote interface. The only way of interaction is through message sending. MDB is just MessageListener, and nothing else: a class implements javax.ejb.MessageDrivenBean and javax.jms.MessageListener. The first of these interfaces has only two methods: setMessageDrivenContext() and ejbRemove(). The second interface has only one method: onMessage(). The specification also requires the creation of a ejbCreate() method without parameters. The client does not communicate directly with MDB; it does not create it. The container itself will decide when and how many MDBs are required to process messages from the given destination. The main shortcoming of MDB is that it can accept messages only from one destination.

Code Example

We suppose that you already have installed J2SE (which can be found at http://java.sun.com/j2se/), and have installed and are running JBoss Application Server (which can be found at http://www.jboss.org/).

To compile the following example, you need to type:

javac -classpath .;C:jboss-3.2.3clientjbossall-client.jar
      SimpleSender.java

To run it, you need to type:

java -classpath .;C:jboss-3.2.3clientjbossall-client.jar
     SimpleSender

(Please type, instead of C:jboss-3.2.3, the path to your JBoss directory. Also, remember that JBoss server needs to be running before you can run these examples.)

So, let’s create a simple sender and receiver.

// SimpleSender.java
import java.util.Properties;
import javax.jms.*;
import javax.naming.*;

public class SimpleSender {

  public static void main(String argv[]) {
    new SimpleSender();
  }

  public SimpleSender() {
    try {
      QueueConnectionFactory myQConnFactory;
      Queue myQueue;

      Properties properties = new Properties();
      properties.put(Context.INITIAL_CONTEXT_FACTORY,
                     "org.jnp.interfaces.NamingContextFactory");
      properties.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
      properties.put(Context.PROVIDER_URL, "localhost");

      Context ctx = new InitialContext(properties);
 
      myQConnFactory = (QueueConnectionFactory)ctx.lookup
                       ("UIL2ConnectionFactory");
      myQueue = (Queue) ctx.lookup("queue/testQueue");

      ctx.bind ("SimpleSender", myQueue);

      QueueConnection con = myQConnFactory.createQueueConnection();
      QueueSession session = con.createQueueSession(false,
                             Session.AUTO_ACKNOWLEDGE);
      TextMessage textMessage = session.createTextMessage();
      QueueSender sender = session.createSender(myQueue);
      con.start();

      for (int i=0; i<10; i++) {
        textMessage.setText("Hello World #" + i);
        sender.send(textMessage);
      }

      con.close();
      ctx.close();

    } catch(Exception e) {
      e.printStackTrace();
    }

  }
}

There are two ways to receive messages. The first one is a synchronous request of messages from a queue, using a receive() method of javax.jms.QueueReceiver. This can block Reciever until it will not receive the message, or can return management on a time-out if the message does not arrive during the specified time interval. The second one is an asynchronous reception of messages as soon as they become accessible, with javax.jms.MessageListener calling the onMessage() method, which processes the message contents.

Many steps in creating receiver are similar to those for sender.

// SyncReceiver.java
import java.util.Properties;
import javax.jms.*;
import javax.naming.*;

public class SyncReceiver {

  public static void main(String argv[]) {
    new SyncReceiver();
  }

  public SyncReceiver() {
    try {
      QueueConnectionFactory myQConnFactory;
      Queue myQueue;

      Properties properties = new Properties();
      properties.put(Context.INITIAL_CONTEXT_FACTORY,
                     "org.jnp.interfaces.NamingContextFactory");
      properties.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
      properties.put(Context.PROVIDER_URL, "localhost");

      Context ctx = new InitialContext(properties);
      myQConnFactory = (QueueConnectionFactory)
                       ctx.lookup("UIL2ConnectionFactory");
      myQueue = (Queue) ctx.lookup("queue/testQueue");

      ctx.bind("SyncReceiver", myQueue);

      QueueConnection con = myQConnFactory.createQueueConnection();
      QueueSession session = con.createQueueSession(false,
                             Session.AUTO_ACKNOWLEDGE);
      QueueReceiver receiver = session.createReceiver(myQueue);

      con.start();

      for (int i=0; i<10; i++) {
        TextMessage textMessage = (TextMessage) receiver.receive();
        System.out.println("Got: " + textMessage.getText());
      }

      con.close();
      ctx.close();

    } catch(Exception e) {
      e.printStackTrace();
    }

  }
}

Afterword

Databases are an ideal approach for long-time data storage, but storage of the temporary data and users’ notifications on their changes is not their strength. In spite of the fact that it is considered inefficient, interrogations of databases are frequently used in practice. All these requests demand a lot of additional “hidden” work. If plenty of objects frequently address a database, it can lead to significant loading of the database server and a network. Most of the time, requests do not return any data, or, even worse, already known information comes back to processing.

Simply put, databases are not intended for frequent inquiries or events. If it is necessary for you to react as soon as possible to a change of the data or any event, a simpler and more effective way will be through the use of asynchronous messages.

Applications for technological processes (such as programs for document circulation, processing of claims, and other) in part very much approach the use of a MQ (message queue), because a model MQ is close to the technology of problematics of the model of technological processes, allowing to realize it in the manner of an “office” in which each character has its own box for incoming and outgoing mail.

A characteristic feature of such applications is usually a huge number of agents (agents can be people, operations of automatic processes, or even the physical equipment, for example printers or devices), each of which incurs the performance of a small problem and transfers its to the following agent, according to business logic. At the creation of such applications, the main task of development is the confidence of fast performance, and also confidence of absence of failures. MQ Servers, which work with databases, simplify the process of processing such technological processes in your application; doing it is more flexible, scaled, and expanded.

Also, it is very convenient to use MQ technology for applications focused on events. It concerns applications working in the area of financial or new services. In financial markets, operations should be done very quickly; users are interested in changes as soon as they occur.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories