Messaging is a communication technique between software components or applications. However, unlike tightly-coupled communication techniques such as TCP sockets, RMI and CORBA, where both the parties must be available during communication, messaging allows s/w components to exchange messages; they don’t have to be available at the same time. This is achieved with the introduction of a third component, called messaging agent that provides facilities such as creating, sending, receiving and reading messages. Messaging clients connect to a messaging agent and communicate indirectly. In fact, one need not know anything about the other, thus resulting the communication loosely-coupled.
Messaging is often used to coordinate programs in dissimilar systems or written in different programming languages. However, unlike electronic mail, which is a method of communication between people or between software applications and people, it is used for communication between software components or applications.
2. JMS API
The Java Message Service (JMS) is a Java API that allows s/w components to create, send, receive and read messages. Formerly developed by Sun, this Message Oriented Middleware (MOM) defines a set of interfaces and associated semantics, which allows Java programs to communicate with other messaging implementations. The mandatory part, which a programmer must know to understand basic messaging concept is very small. However, it supports enough features needed for sophisticated messaging applications.
3. JMS COMPONENTS
A JMS application typically has the following components [Figure 25.1:].
This is a message Oriented Middleware (MOM) that implements JMS specification. It provides requisite API library, a broker that provides message storage/delivery functions. It usually also provides administrative and control features. Some of the well-known providers are Sun’s Open Message Queue, Apache’s Active MQ and Qpid, JBoss’s HornetQ, IBM’s Websphere MQ, Progress Software’s SonicMQ, ZeroMQ, RabbitMQ etc. In this chapter, we shall use Sun’s Open Message Queue, which is also an integral part of J2EE.
These are Java programs that produce and consume messages.
There are preconfigured JMS objects created usually by an administrator and are maintained by the broker for client’s use. There are two kinds of administered objects: destinations and connection factories.
A destination is nothing but a message store. It is a target where producers place messages or it is a source consumers retrieve messages or both.
A connection factory object encapsulates a set of configuration properties for a connection. A JMS client uses a connection factory to create a connection to the broker.
These are objects that JMS clients exchange. In addition to text message, JMS supports messages that contain serialized Java objects and XML documents.
4. MESSAGING MODELS
JMS supports two models for exchanging messages between producers and consumers: Point-to- Point and Publish/Subscribe, which are frequently shortened to p2p (or PTP) and pub/sub respectively. The JMS specification refers to these as messaging domains.
In this model, the destination, producer and consumer of messages are called queue, sender and receiver respectively. Senders place messages in queues, and receivers get them [see Figure 25.2:].
Messages live in a queue until they are consumed or until they expire. Any number of senders can put messages to a queue and any number of receivers can consume messages from the queue [Figure 25.3: ]. However, each message is consumed by only one receiver. This means once a message is taken off the queue by some receiver, it no longer exists in the queue.
The term queue in P2P model is just symbolic; it doesn’t guarantee that messages are delivered in any particular order. Moreover, if more than one potential receiver exists for a queue, receivers are chosen randomly for delivery of messages.
A receiver can get messages by explicitly extracting them from the queue or can register itself to show its interest to get messages. In the former case, a sender and a receiver of a message need not live at the same time. A receiver can still fetch the message later whether or not it was running when the sender produced the message. However, if there is no message in the queue and a receiver tries to extract a message, it gets blocked until a message appears in the queue. This type of message consumption is known as synchronous consumption.
However, in P2P model, one receiver (and only one) may also get registered to a queue to get messages and continue the normal flow of execution. The broker can deliver messages as soon as they come in from some sender. This type of message consumption is known as asynchronous consumption. What happens if a message appears in a queue and an asynchronous receiver and other synchronous receivers are ready to get messages? Well, wait. We shall discuss more about synchronous and asynchronous consumption of messages later in this chapter.
In this model, the destination, producer and consumer of messages are called topic, publisher and subscriber respectively. Subscribers first show their interest in receiving messages on a topic.
Publishers, in turn, produce some messages for the topic. As soon as the messages are produced, they are distributed to all current subscribers who showed their willingness earlier [see Figure 25.4: ]. So, a client is supposed to get those messages that come after the subscription.
The primary difference of this model from P2P model is that a message is allowed to be consumed by multiple subscribers. Moreover, messages on a topic remain valid as long as they are being distributed to current subscribers. Messages do not retain the topic even if there is no subscriber for it.
The subscriber, after making a subscription must remain continuously active to receive messages. However, JMS provides a novel facility called durable subscription, where the client is allowed to be disconnected for some time. The JMS broker keeps messages published during the disconnection period and delivers them whenever it reconnects.
5. MESSAGE CONSUMPTION
JMS allows a message consumer to get messages in two ways: synchronously and asynchronously.
This style of message consumption happens when a consumer explicitly extracts messages from a destination using receive() method. The receive() method blocks the caller if no message is available at that time. As a result, the consumer cannot continue its normal mode of execution.
In this style of message consumption, a consumer simply sets up a listener and continues its normal work. The listener, on behalf of the consumer, listens on thereafter and gets notified by the broker when a message appears in the destination.
6. PROGRAMMING MODEL
JMS API defines a set of interfaces [Figure 25.5:] corresponding to different messaging components and provides them as a package javax.jms. The primary interfaces are summarized below:
This type of object encapsulates the configuration of a connection and is used to create connection. It has two flavors, one for each messaging models P2P and pub/sub: QueueConnectionFatory and TopicConnectionFactory.
A Connection object represents application’s active connection to a messaging broker. This is used to create Session objects. Like ConnectionFactory, it also has two forms for the two models:
QueueSession and TopicSession.
This is a context used to create destinations, producers, consumers, messages etc. It also has two flavors: QueueSession and TopicSession.
This is the message store where producers place messages and consumers get messages from. A Destination object may be created from Session or by JNDI lookup. In P2P and pub/sub models, destinations are called queues and topics respectively and are represented by Queue and Topic objects respectively.
A MessageProducer object is created from Session specifying a Destination and is used to send messages to the specified destination. It has two forms for two messaging models: QueueSender and TopicPublisher.
A MessageConsumer object is created from Session specifying a Destination and is used to receive messages from the specified destination. It has two forms for two messaging models:
QueueReceiver and TopicSubscriber.
The interface is the root interface of all JMS messages. It defines the message header and the acknowledgement method to be used for all messages. A message usually consists of a header that contains fields used for message routing and identification, application specific property values and a payload that contains the application data being sent. Five types of messages are specified in JMS API [Table 25.1: ]:
Contains a stream of Java primitive values.
Contains a set of name-value pairs.
Contains a java.lang.String object. This message type can be used to transport plain-text messages, and XML messages.
Contains a Serializable Java object.
Contains a stream of un-interpreted bytes for encoding a body to match an existing message format.
There are various JMS providers. However, for simplicity, we shall use a full-blown provider such as J2EE server. Instead, we shall use formerly Sun’s Open Message Queue, which is lightweight, easy to use and an integral part of J2EE. So, the next section discusses how to get and install Open MQ.
7. INSTALLING OPEN MQ
The first step to create a JMS application is to get Open Message Queue. Download the latest release of Open Message Queue from https://mq.java.net/downioads.htmi. We downloaded the zip archive for windows openmq4_5_2-binary-WINNT.zip. Unzip the binary (.jar) bundle in a directory, say D:\openmq4_5_2. Hereafter, we shall refer to this directory as <mq_top>. Edit the file
<MQ_TOP>/etc/mq/imqenv.conf to set imq_default_javahome to your JDK home directory. We did this using the following:
Open Message Queue is now ready to function. Go to <MQ_TOP>/mq/bin and use the following command to start the broker:
If everything goes fine, the output displayed should be similar to that shown below:
Open Message Queue 4.5.2 Oracle
Version: 4.5.2 (Build 2-d)
Compile: Thu 12/08/2011
To check the broker startup, use imqcmd utility as follows:
imqcmd query bkr –u admin
Supply the default password of admin, when prompted to do so. A sample output is shown below:
Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.