Java Message Service is an API that supports the formal communication called messaging between computers on a network. JMS provides a common interface for standard message protocols and message services in support of the Java programs.
JMS provides the facility to create, send and read messages. The JMS API reduces the concepts that a programmer must learn to use the messaging services/products and also provides the features that support the messaging applications.
JMS helps in building the communication between two or more applications in a loosely coupled manner. It means that the applications which have to communicate are not connected directly they are connected through a common destination.
1. Why We Need JMS?
When one application wants to send a message to another application in such a way that both applications do not know anything about each other; and even they may NOT be deployed on the same server.
For example, one application A is running in India and another application B is running in the USA, and A is interested in sending some updates/messages to B – whenever something unique happens on A. There may be N number of such applications that are interested in such updates to B.
In this scenario, Java provides one of the solutions in form of JMS – and solves the exact same problem discussed above.
JMS is also useful when we are writing any event-based application like a chat server where it needs a publish event mechanism to send messages between the server and the clients.
Note that JMS is different from RMI so there is no need for the destination object to be available online while sending a message. The publisher publishes the message and forgets it, whenever the receiver comes online, it will fetch the message. It’s a very powerful solution for very common problems in today’s world.
2. Benefits of JMS
JMS is asynchronous by default. So to receive a message, the client is not required to initiate the communication. The message will arrive automatically to the client as they become available.
JMS provides the facility of assurance that the message will be delivered once and only once. We know that duplicate messages create problems. JMS helps you avoid such problems.
3. JMS Messaging Domains
Even before the JMS API existed, most messaging products supported either the point-to-point or the publish/subscribe approach to messaging. The JMS also provides a separate domain for each of both approaches and defines the compliance for each domain.
Any JMS provider can implement both or one domain, it’s his own choice. The JMS provides the common interfaces which enable us to use the JMS API in such a way that it is not specific to either domain.
Let’s see both types of messaging domains in more detail to understand how JMS works.
3.1. Point-to-Point Messaging
In the point-to-point messaging domain the application is built on the basis of message queues, senders and receivers.
Each and every message is addressed to a particular queue. Queues retain all messages sent to them until the messages are consumed or expired.
There are some characteristics of PTP messaging:
- There is only one client for each message.
- There is no timing dependency for sender and receiver of a message.
- The receiver can fetch message whether it is running or not when the sender sends the message.
- The receiver sends the acknowledgement after receiving the message.
3.2. Publish/Subscribe Messaging
Publishers and subscribers are generally anonymous and can dynamically publish or subscribe to the topic. The Topic is responsible to hold and deliver messages. The topic retains messages as long as it takes to distribute to the present clients.
Some of the characteristics are:
- There can be multiple subscribers for a message.
- The publisher and subscribe have a timing dependency. A client that subscribes to a topic can consume only messages published after the client has created a subscription, and the subscriber must continue to be active in order for it to consume messages.
Read More: HornetQ Basic Example
4. Receiving a Message
In JMS, the message consumption can be done in two ways:
In synchronous message consumption, the subscriber/receiver requests the message from the destination by calling the
receive() method will block till the message arrives or time out if the message does not arrive within a given time. Just like normal java method calls with some return value.
In asynchronous message consumption, a subscriber can register (or subscribe) as a message listener with the consumer.
The message listener is the same as the event listener, whenever the message arrives at the destination the JMS provider will deliver the message by calling the listener’s
onMessage() method which will act on the content of the message.
5. JMS Participating Objects
JMS application has some basic building blocks, which are:
- Administered objects – Connection Factories and Destination
- Message Producers
- Message Consumers
- Message Listeners
5.1. JMS Administered Objects
JMS application provides two types of administered objects:
- Connection Factories
These two administered objects are created by the JMS system administrator in JMS Provider by using the Application Server the admin console. Both objects are stored in the Application server JNDI Directory or JNDI Registry.
5.2. Connection Factories
The client uses an object which is a connection factory used to create a connection to a provider. It creates a connection between JMS Provider and JMS Client.
When JMS Client such as sender or receiver search out for this object in JNDI Registry, then the JMS Client receives one connection object which is nothing just a physical connection between JMS Provider and JMS Client. Using this connection, the client can have communication with the destination object to send or receive messages into Queue or Topic.
Let us have an example to understand it to send the message:
QueueConnectionFactory queueConnFactory = (QueueConnectionFactory) initialCtx.lookup ("primaryQCF"); Queue purchaseQueue = (Queue) initialCtx.lookup ("Purchase_Queue"); Queue returnQueue = (Queue) initialCtx.lookup ("Return_Queue");
The client uses an object known as a destination which is used to specify the target of messages it produces and the source of message who consumes it.
The JMS application uses two types of destinations:
The code examples to create a queue or a topic:
Create queue session
QueueSession ses = con.createQueueSession (false, Session.AUTO_ACKNOWLEDGE); //get the Queue object Queue t = (Queue) ctx.lookup ("myQueue"); //create QueueReceiver QueueReceiver receiver = ses.createReceiver(t);
Create topic session
TopicSession ses = con.createTopicSession (false, Session.AUTO_ACKNOWLEDGE); // get the Topic object Topic t = (Topic) ctx.lookup ("myTopic"); //create TopicSubscriber TopicSubscriber receiver = ses.createSubscriber(t);
5.4. JMS Connection
The connection encapsulates the virtual connection with a JMS Provider. The connection implements the Connection interface, when it will have a ConnectionFactory object then we can use this to create a connection.
Connection connection = connectionFactory.createConnection();
5.5. JMS Session
The session is a single-threaded context that is used for producing and consuming messages.
The sessions are used to create the following:
- Message Producers
- Message Consumers
The session implements the Session interface and after creating a Connection object we use this to create a Session.
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
5.6. Message Producer
A message producer is an object which is created by a session and is used for sending messages to the destination. This implements the
We use Session to create a
MessageProducer for the destination, queue or topic object.
MessageProducer producer = session.createProducer(dest); MessageProducer producer = session.createProducer(queue); MessageProducer producer = session.createProducer(topic);
5.7. Message Consumer
A message consumer is an object which is created by a session and is used to receive messages sent at a destination. It will implement the
We use a session to create a MessageConsumer for a destination, queue or topic object.
MessageConsumer consumer = session.createConsumer(dest); MessageConsumer consumer = session.createConsumer(queue); MessageConsumer consumer = session.createConsumer(topic);
5.8. Message Listener
A message listener is an object which acts as an asynchronous event handler for messages. The message listener implements the MessageListener interface which contains the one method
onMessage() method, we define the actions to be performed when the message arrives. By using
setMessageListener() we define the message listener with a specific
Listener myListener = new Listener(); consumer.setMessageListener(myListener);
The JMS Messages are used by the JMS Clients to have communication between systems. The JMS messages have a simple format but are highly flexible, which allows creating messages matching different formats.
The JMS message is divided into three parts:
The JMS message header contains the number of predefined fields which contain those values which are used by the clients and providers to identify and send messages. The predefined headers are:
In message properties we can create and set properties for messages. The message properties are custom name value pairs which are set or read by applications. The message properties are useful for supporting filtering messages. The JMS API provides some predefined property that a provider can support. The message property is optional.
In message bodies the JMS API defines five message body formats which are also called as message types which allow us to send and receive data in many different forms and also provides compatibility with the existing messaging formats. It basically consists of the actual message sent from JMS sender to receiver.
The different message types are:
Text: Represented by javax.jms.TextMessage. It is used to represent a block of text.
Object: Represented by javax.jms.ObjectMessage. It is used to represent a java object.
Bytes: Represented by javax.jms.BytesMessage. It is used to represent the binary data.
Stream: Represented by javax.jms.StreamMessage. It is used to represent a list of java primitive values.
Map: Represented by javax.jms.MapMessage. It is used to represent a set of keyword or value pairs
That’s all for the JMS Introduction Tutorial and it’s related terminologies. In the next set of posts. we will see some examples of JMS.
Happy Learning !!