Thursday, February 19, 2009

JMS ( Java Message Service)

1. Introduction
The different software applications can communicate with each other using messaging paradigm–exchanging the data in message format where the data contained in a message can be anything Object ,Tex ...etc depending on the business scenario – this paradigm when used in business Systems, are generically referred to as enterprise messaging systems, or Message-Oriented Middleware (MOM).

MOM unlike RPC and object-orientation it is an asynchronous form of communication, i.e. the sender does not block waiting for the recipient to participate in the exchange. If the message service offers persistence and reliability then the receiver need not be up and running when the message is sent.
MOM vendors provide transmitting the messages across a network, ensuring messages distribution, fault tolerance, load balancing, scalability and reliability to exchange large quantities of message. Most of MOM vendors may implement their own networking protocols, routing, and administration facilities but the basic semantics of the developer API provided by different MOMs are the same. This similarity in APIs makes the Java Message Service possible. (MOM == JMS provider) 2. JMS API
JMS (Java message service) is a Java API that allows applications to create, send, receive, and read messages, it is designed to be easily and widely used with many different MOM vendors.

JMS API enables communication that is not only loosely coupled but also asynchronous and reliable.
1- Loosely coupled :A component sends a message to a destination, and the recipient can retrieve the message from the destination. However, the sender and the receiver do not have to be available at the same time in order to communicate. In fact, the sender does not need to know anything about the receiver; nor does the receiver need to know anything about the sender. The sender and the receiver need to know only which message format and which destination to use.
2- Asynchronous: A JMS provider can deliver messages to a client as they arrive; a client does not have to request messages in order to receive them.
3- Reliable: The JMS API can ensure that a message is delivered once and only once. Lower levels of reliability are available for applications that can afford to miss messages or to receive duplicate messages.

2.1 JMS messaging models
JMS supports two models: point-to-point (PTP) and publish/subscribe (pub-and-sub).

2.1.1 Point to Point [queue] Messaging model:
- It is intended for one-to-one delivery of messages through a virtual channel called [Queue]
- It is a pull- or polling-based model, where messages are requested by consumer from the queue instead of being pushed to the client automatically.
- The message is read just once by a consumer although There may be more than one potential consumer to queue, however once a message has been read by one consumer it cannot be read by any of the remaining consumers.
- A sender and a receiver of a message have no timing dependencies. The receiver can fetch the message whether or not it was running when the client sent the message.
- In PTP it is preferred that the Sender program should be established before the consumer (very important note).
- In PTP After the message is read it is deleted from the queue.

2.1.2 Publisher and Subscriber [Topic] Messaging model:
- It is intended for a one-to-many broadcast of messages through a virtual channel called [Topic]
- It is a push-based/broadcast model, where messages are automatically broadcast to consumers instead of being pulled.
- In pub-and-sub the receiver should be register to the topic before the sender’ sending to the message – because: the JSM provider should get which consumers are waiting the sent message to the topic.
- Publishers and subscribers of a message have a timing dependency. A client that subscribes to a topic can consume only messages published after the client has created a registration to the topic.
- In pub-and-sub the message remains in the topic until all consumers have read the message.
JMS queues and topics are the JMS Destinations and are bound in the JNDI environment and made available to J2EE applications.
2.2 Messaging Consumption Approaches
A queue or topic consumption can be either synchronous or asynchronous.
Synchronously:
A subscriber or a receiver explicitly fetches the message from the destination by calling the receive method. The receive method can block until a message arrives or can time out if a message does not arrive within a specified time limit.
Asynchronously:
A Subscriber or a receiver can register a message listener with a consumer. A message listener is similar to an event listener. Whenever a message arrives at the destination, the JMS provider delivers the message by calling the listener’s onMessage method without hanging.

3. JMS Provider
There are several JMS Providers like Oracle JMS Provider (
Oracle Application Server JMS and Oracle JMS),WebSphere MQ, SonicMQ, and SwiftMQ …etc ; You can choose JMS provider depending on their integration and quality-of-service (QOS) requirements.

Before creating JMS clients, it is required to configure the JMS Ports, the connection factories and destinations (Queue/Topic) for the accessed JMS Provider and this configuration steps will be different from JMS provider to other.
Imp Note: in our article we are covering Oracle Application Server JMS.
3.1.1 Configuring OracleAS JMS Ports
Use the
Oracle Enterprise Manager 10g to configure the port range for OracleAS JMS. The default range is between 3201 and 3300.
From the OC4J Home page, select the Administration page, then the Instance Properties column, then Server Properties. Scroll to the Multiple VM Configuration section.
3.1.2 Configuring Destination Objects in JMS Provider environment
OracleAS JMS Destination –queue or Topic- objects are configured in the
jms.xml file. OracleAS JMS is already installed with OC4J, so the only configuration necessary is for the queues, topics, and their connection factories that your applications use.

From the OC4J Home page, select the Administration page, then the Enterprise Messaging Service column, then JMS Destinations and JMS Connection Factories.
Note: The jsm.xml could be configured manually in J2EEHome/OC4JHOME/Config.



4. JMS API Programming Model
After setting the JMS provider environment, it is the time to build JMS Clients (producer or consumer client).
The basic building blocks of a JMS application consist of
1- Access JMS provider
2- Create administered Connection: connection factories and destinations
3- Create Connection
4- Create Session
5- Create Producer and consumer
6- Create Message
7- Send and receive Messages

4.1 Accessing JMS provider
Context ctx = new InitialContext(); ( if lookup in the current vendor)
Or
Hashtable env = new Hashtable();
String initialContextFactory="com.evermind.server.rmi.RMIInitialContextFactory";
String securityPrincipal="userName";
String credentials="userPassword";
env.put( Context.INITIAL_CONTEXT_FACTORY,initialContextFactory );
env.put( Context.SECURITY_PRINCIPAL, securityPrincipal );
env.put( Context.SECURITY_CREDENTIALS, credentials);
ctx = new InitialContext(env);

4.2 Creating administered Connection: connection factories and destinations
4.2.1 Connection Factory:
A connection factory is the object a client uses to create a connection with a provider, Each connection factory is an instance of either the QueueConnectionFactory or the TopicConnectionFactory interface.a pair of connection factories come preconfigured with the J2EE SDK and are accessible as soon as you start the service.
QueueConnectionFactory queueConnectionFactory =
(QueueConnectionFactory) ctx.lookup("jms/QueueConnectionFactory");


TopicConnectionFactory topicConnectionFactory =
(TopicConnectionFactory) ctx.lookup("jms/TopicConnectionFactory");

4.2.2 Destination:
A destination is the object a client uses to specify the target of messages it produces and the source of messages it consumes.
Queue myQueue = (Queue) ctx.lookup("jms/MyQueue");
Topic myTopic = (Topic) ctx.lookup("jms/MyTopic");



4.3 Create Connection
A connection encapsulates a virtual connection with a JMS provider. A connection could represent an open TCP/IP socket between a client and a provider service daemon. You use a connection to create one or more sessions.
QueueConnection queueConnection =
queueConnectionFactory.createQueueConnection();


TopicConnection topicConnection =
topicConnectionFactory.createTopicConnection();

Note:
When an application completes, you need to close any connections that you have created. Failure to close a connection can cause resources not to be released by the JMS provider. queueConnection.close(); topicConnection.close();


4.4 Create Session
A session is a single-threaded context for producing and consuming messages, A session provides a transactional context with which to group a set of sends and receives into an atomic unit of work.
QueueSession queueSession =
queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

TopicSession topicSession =
topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);


The first argument means that the session is not transacted; the second means that the session automatically acknowledges messages when they have been received successfully.


4.5 Create Message Producer and consumer
A message producer and consumer are objects which created by a session and are used for sending and receiving messages to a destination.
Producer:
QueueSender queueSender = queueSession.createSender(myQueue);
TopicPublisher topicPublisher = topicSession.createPublisher(myTopic);

Consumer:
QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);
TopicSubscriber topicSubscriber = topicSession.createSubscriber(myTopic);




4.6 Create Message
The JMS API defines five message types [ TextMesssage, MapMessage, BytesMessage, StreamMessage, ObjectMessage, Message] , which allow you to send and to receive data in many different forms and provide compatibility with existing messaging formats and provides some predefined property names that a provider may support. The use of either predefined properties or user-defined properties is optional.
TextMessage message = queueSession.createTextMessage();
message.setText(msg_text); // msg_text is a String



4.7 Sending and receiving Messages
Sending:
QueueSender
and TopicPublisher can be used to send the messages.
queueSender.send(message);
topicPublisher.publish(message);


Receiving:
QueueReceiver and a TopicSubscriber can be used to receive the messages at any time after calling start method.
queueConnection.start();
--> To consume a message synchronously you can use receive method as following:
Message m = queueReceiver.receive();
or
Message m = queueReceiver.receive(1000); // time out after a second

if (m instanceof TextMessage) {
TextMessage message = (TextMessage) m;
System.out.println("Reading message: " + message.getText());
} else {
// Handle error
}

--> To consume a message asynchronously you will use message listener where it is an object that acts as an asynchronous event handler for messages. This object implements the MessageListener interface, which contains one method, onMessage. In the onMessage method, you define the actions to be taken when a message arrives.

The message listener will be registered with a specific QueueReceiver or TopicSubscriber by using the setMessageListener method. For example, if you define a class named QueueListener that implements the MessageListener interface, you can register the message listener as follows:

QueueListener queueListener = new queueListener();
queueReceiver.setMessageListener(queueListener);


Important notes:
1- The setmessageListener method will throw Exception if it is running in Web or EJB Container; it should be used under Client container. So to handle the asynchronous consumption in J2EE 1.3 platform you will need to use Message Driven Bean which is a special kind of message listener.
2- If you call start before you register the message listener, you are likely to miss messages.



References:
Java Message Service O'Reilly [Richard Monson-Haefel ,David A. Chappell]
EJB 3 Developer Guide [ Michael Sikora ]
http://java.sun.com/javaee/5/docs/tutorial/doc/bncdq.html
http://download.oracle.com/docs/cd/B14099_19/web.1012/b14012/jms.htm
http://mediasrv.ns.ac.yu/extra/java2/tutorials/jms_tutorial/index.html

5 comments:

Lino Vijay Fonseca said...

Hello Sarah,
I just read your article on JMS Message Service and found it exteremely informative. Thanks for sharing this information with us.
As an addition to this article, it would be helpful if you could add the common issues faced by developers when working with JMS queues such as Lookup failure or AuthorizationExceptions and suggest steps which they can use to resolve the problem.
Once again thanks for the post.
Regards

Anonymous said...
This comment has been removed by a blog administrator.
Unknown said...

Hello Sarah,

thanks so much for this post, it was so fantastic for me while searching some thing and found the solution in your post.
hope that you are fine and every thing is ok.

Anonymous said...

Genial fill someone in on and this post helped me alot in my college assignement. Thanks you for your information.

Paulo Merson said...

The push and pull models are orthogonal to the queue or topic selection. One can use JMS MessageReceiver.receive() following the pull model with either queue or topic. Same for MessageReceiver.setMessageListener(MessageListener) to use the push model.