Author Avatar

Pradeep Mishra

0

Share post:

Before getting started with JMS programming model, I would suggest that first you go through the architecture, components and delivery model of JMS if not familiar.

JMS defines an API for accessing services from a messaging provider; that is, it is not a product itself. It is a set of interface classes that messaging provider vendors implement. Applications that use the JMS API can then communicate with the messaging provider the vendor supplies. The JMS API has become the industry standard interface for Java™ applications to create, send, receive and read messages using messaging providers that support the JMS API. The standard is associated with the Java Platform, Enterprise Edition (Java EE) platform. Java EE is a set of standards for a component-based way to develop, assemble and deploy enterprise applications. Java EE containers implement a standard runtime environment that provides quality of service items such as security, transaction support and thread pooling. The basic building blocks of a JMS application are:

Below figure shows how all these objects fit together in a JMS client application.

JMS Administered Objects

Before a JMS producer can send messages, it must first create a session and then a connection. To create a connection, the JMS client must figure out the mechanism for creating a connection and find a destination for the message. This function is enabled using administered objects. Administered objects consist of ConnectionFactory and destination objects. The JNDI is used to locate and download these administered objects.

  • Connection Factory − A ConnectionFactory object encapsulates a set of vendor-specific messaging server configuration parameters defined by the administrator during deployment. JMS clients use the ConnectionFactory object to create a connection to the JMS provider. A code snippet showing the use of JNDI and the connection factory object follows:
Context cntx = new InitialContext(env);
//in the case of Queue messaging model
QueueConnectionFactory queConnFactory = (QueueConnectionFactory)
cntx.lookup("java:comp/env/jms/QueueConnectionFactory");

//in the case of Topic messaging model
TopicConnectionFactory facConnFactory = (TopicConnectionFactory)
cntx.lookup("java:comp/env/jms/TopicConnectionFactory");
  • Destination − A destination object encapsulates vendor-proprietary destination information that message producers and consumers must use to send messages. JNDI is also used to locate and download destination objects. It’s also used to locate and download destination objects from java:comp/env/jms, which is a commonly used JMS root context for administered objects. A destination is called a queue in the P2P (point-to-point) messaging model and a topic in the pub/sub (publish/subscribe) model, as illustrated here:
// pub/sub model
Topic hotDealTopic = (Topic) cntx.lookup("java:comp/env/jms/topicCF");
//P2P model
Queue supportQue = (Queue) cntx.lookup("java:comp/env/jms/queueCF");

Administered objects are created by an administrator and made available for clients to use during execution, both support concurrent access. Administered objects encapsulate the JMS provider specific logic and hides it from the JMS client code, thus enhancing application portability. Administered objects are created and configured by an administrator using a vendor-provided deployment tool at deployment time.

Connection

Connection uses some JMS providers such as WebSphere, Active MQ, Open MQ etc. to create connection with client and defines these provider resources virtually outside the Java Virtual Machine (JVM). It creates connection between client and provider.
Connection objects encapsulate an open connection to the JMS provider. Connection objects use the user name and password authentication to open a connection to the JMS provider daemon for a queue and topic destination in the following way:

//P2P model
QueueConnection queConnection = queConnFactory.createQueueConnection(username, password);
// pub/sub model
TopicConnection topicConnection = topicConnFactory.createTopicConnection(username, password);

The connection can be closed by using below line −

connection.close();

Session

It is a light weight JMS object, used for producing and consuming messages. You can create message producers, message consumers, and messages by using sessions. It is single threaded and transactional.
You can create a session by using Connection object and Session interface as shown below −

//The AUTO_ACKNOWLEDGE field automatically gives the client's receipt messages, when they have been received successfully
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//P2P model
QueueSession queSession = queConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// pub/sub model
TopicSession topicSession = topicConnection.createTopicSession(false, AUTO_ACKNOWLEDGE);

Message Producer

The message producer (MessageProducer) object is created by a session object and is used by producer clients to send messages to a destination. It’s a super interface for both the TopicPublisher and QueueSender objects. With P2P, use the send() method of the QueueSender interface to send messages to a destination and use the publish() method of the TopicPublisher interface for the pub/sub model. For example, let’s assume we want to connect to a queue destination called “TheCodersStopQueue” and a topic destination called “TheCodersStopTopic” that was preconfigured by the administrator. First, look up the destinations and then create the sender and publisher objects as follows:

Queue theCodersStopQueue 
= (Queue) jndi.lookup("java:comp/env/jms/TheCodersStopQueue");
Topic theCodersStopTopic 
= (Topic) jndi.lookup("java:comp/emv/jms/TheCodersStopTopic");
QueueSender queSender = queSession.createSender(theCodersStopQueue);
queSender.send(queueMsg);
TopicPublisher topicPublisher = topicSession.createPublisher(theCodersStopTopic);
topicPublisher.publish(topicMsg);

Message Consumer

The message consumer (MessageConsumer) object is also created by a session object and is used by consumer clients to receive messages from a destination. A MessageConsumer is a super interface to both the QueueReceiver and TopicSubscriber interfaces. There are several variations for creating a message consumer client. A message consumer client can be created with a message selector, which enables developers to selectively filter messages the client will receive based on the selector SQL syntax. Developers also can select between synchronous and asynchronous communication modes when creating the consumer client. When selecting synchronous mode, the pull method is being selected and the receive() method is used to get messages. If the synchronous or push mode is preferred, the MessageListener interface is implemented and the JMS provider uses the onMessage() method to deliver messages. The start() method in QueueConnection and TopicConnection objects must be invoked before messages can arrive as illustrated here:

QueueReceiver queReceiver = queSession.createQueueReceiver("TheCodersStopQueue");
queConection.start();
Message msg = queReceiver.receive();

Or, asynchronous mode requires more work. First, developers must define a QueueListener class that implements the MessageListener interface and then registers the queue listener as follows:

QueueListener queListener = new QueueListener(); 
queReceiver.setMessageListener(queListener);

JMS Messages

The ultimate purpose of a JMS application is to produce and consume messages that can then be used by other software applications. JMS messages have a basic format that is simple but highly flexible, allowing you to create messages that match formats used by non-JMS applications on heterogeneous platforms.
A JMS message can have three parts: a header, properties, and a body. Only the header is required.
Below table summarizes these objects, which are the building blocks for JMS applications (for both the P2P and pub/sub messaging models). Notice the symmetry of the object names and semantics.

Table 1 – JMS API and Message Types

ObjectPoint-To-Point MessagesPublish/Subscribe MessagesComment
DestinationQueue, TemporaryQueueTopic, TemporaryTopicAdministered object
ConnectionFactoryQueueConnection FactoryTopicConnection FactoryAdministered object
ConnectionQueueConnectionTopicConnection 
SessionQueueSessionTopicSession 
MessageProducerQueueSenderTopicPublisher 
MessageConsumerQueueReceiverTopicSubscriber 
MessageTextMessage, MapMessage, ByteMessage, StreamMessage, ObjectMessageTextMessage, MapMessage, ByteMessage, StreamMessage, ObjectMessageMessage types are common to both models

JMS Exception Handling

The root class for exceptions thrown by JMS API methods is JMSException. Catching JMSException provides a generic way of handling all exceptions related to the JMS API.
The JMSException class includes the following subclasses, described in the API documentation:

  • IllegalStateException
  • InvalidClientIDException
  • InvalidDestinationException
  • InvalidSelectorException
  • JMSSecurityException
  • MessageEOFException
  • MessageFormatException
  • MessageNotReadableException
  • MessageNotWriteableException
  • ResourceAllocationException
  • TransactionInProgressException
  • TransactionRolledBackException

I hope you have enjoyed this post and it helped you to understand JMS programming model. Please like and share and feel free to comment if you have any suggestions or feedback.

Getting Started with Java Message Service (JMS)
Accessing Data with JPA

Leave a Reply