Java Message Service: Understanding the BasicsNishant M.C., October 2007 IntroductionJava Message Service (JMS) is a Java technology that helps applications communicate using messages. Applications exchange messages with the help of messaging systems or Message Oriented Middleware (MOM). MOM products usually provide load balancing, scalability, fault tolerance, and transactional support, which make a messaging system an enterprise-quality service. First let's look at the details of enterprise messaging systems. Then let's consider what JMS is, why it is used, and where it is used. Then we'll look at some code that demonstrates how applications can communicate with the help of JMS. Note: I assume that you are familiar with common Java Platform, Enterprise Edition technologies, such as JavaServer Pages (JSP) and Servlets. For the demonstration, I use Sun Java System Application Server 9.0, Java SDK 1.5, and an IDE. ContentsThis article covers the following topics:
Enterprise Messaging SystemsEnterprise messaging systems allow applications to convey messages to one or more other applications. By message I mean the data packet that contains the business and network routing headers, which indicate where the message should go. Enterprise messaging systems are not a new concept. They have been in existence for many years. Enterprise messaging systems act as a common endpoint where sender applications can post messages and receiver applications can receive messages, ensuring that messages are properly distributed among applications. These systems can also be described as a server system that facilitates the transfer of messages among applications. Common enterprise messaging system products available in the marketplace are IBM MQ series, Microsoft MSMQ, Sonic MQ, and Softwired iBus. With these products, applications are provided with an API for creating a message that contains a payload (application data) and the network routing headers. The same API is used to receive a message from other applications. Each vendor implements its own network protocol, routing facilities, and administration facilities, but the basic semantics of the API provided by each vendor are the same. In enterprise messaging systems, messages are delivered asynchronously from one system to another system. This means the sender application doesn't have to wait until the receiver application receives the message. The sender application is free to send a message and continue doing other work. Messages are treated as autonomous units that contain all the information needed for processing the data in the message. Once the sender application sends a message to the network, the sender application continues doing other work. The message is taken care of by the MOM (server system). The receiver application looks for messages in the server system and gets the message. This process is similar to a mail system. Figure 1 depicts a messaging system.
Figure 1: Messaging System The server system or MOM can be implemented efficiently by vendors in variety of ways. For example, the server system can use any protocol for communicating with the applications. Another difference among vendors can be the architecture. There are mainly two kinds of architectures:
What I described previously was a centralized architecture, that is, the applications depend on the server system for the exchange of messages. The server system can also be called a message router or a message broker, and it is responsible for delivering a message from one client to another client. So the sending client and the receiving client are decoupled. Clients see only the message server, not other clients. This architecture allows clients to be added and removed without impacting the system.
Figure 2: Centralized Architecture In reality, the message server is a cluster of distributed servers operating as a single unit. In a decentralized architecture, there is no message server. Tasks such as persistence, transaction, and security are taken care of by the client systems. Thus, the client systems are capable of performing the enterprise services on the messages. Message routing, that is, the sending of messages to their proper destinations, is delegated to the network router.
Figure 3: Decentralized Architecture There is another architecture, which is a hybrid architecture. As you probably guessed, this architecture is a combination of both the centralized and the decentralized architectures. Centralized server systems may communicate with decentralized message systems in this architecture. Thus when we say "message server" in a centralized architecture, the server system may be a single message server or a clustered message server system; in the decentralized model, the "message server" points to the server functionality in the client systems. JMS OverviewIn the previous section, I didn't mention JMS, because I was discussing the scenarios that existed before JMS came into existence. Now that you understand enterprise messaging systems and MOM, we can look at what JMS provides. JMS is an API for enterprise messaging that was developed by Sun Microsystems. It is just an abstraction of the APIs provided by the MOM systems for clients to communicate with the server. This scenario is similar to the scenario used in the Java DataBase Connectivity (JDBC) software for communicating with different databases or in the Java Naming and Directory Interface (JNDI) API for accessing different naming and directory services. Sun took the lead for developing the JMS API. Other vendors were also involved in the project, so the API was designed to support almost all MOM systems. In addition, the API has some features that could support future MOM systems. The JMS API was created to support the messaging system and not the Remote Procedure Call (RPC) based systems, such as those using CORBA and Enterprise JavaBeans (EJB) architecture. It was intended to make this messaging model a first-class distributed computing paradigm for Java technology, equal with the remote method call (RPC) based systems like CORBA and EJB. JMS Messaging ModelsJMS provides two models (types) of messaging:
The publish-and-subscribe or pub/sub model is intended for broadcasting one-to-many messages, and the point-to-point queuing or p2p method is intended for broadcasting one-to-one messages. Applications that play the role of sender or receiver are called messaging clients, and the MOM system or server is called the message provider. The message provider can be a single system or a cluster of systems. A JMS application is a business system composed of messaging clients and a message provider. The sender part of the application is generally called a producer, and the receiver part of the application is generally called a consumer. Publish-and-Subscribe (Pub/Sub) Messaging ModelIn the pub/sub model, the producer can send a message to many consumers. This "one-to-many" scenario is similar to broadcasting information to many users. The channel, pipe, or line through which the message is passed to different consumers is called a topic. Similar to how users subscribe to news media, consumers can subscribe to a particular topic or channel. Every consumer who subscribes to a topic will get the messages that are sent to this channel topic by the producer. The pub/sub based model is a "push" model, so consumers do not have to request or poll for messages. In this model, the producer sending a message is not dependent on the consumer receiving the message. That is, the producer just sends the message to the server and then it does other tasks. The producer doesn't need to wait until the consumer receives the message. Its job is over when it sends the message to the server. Likewise, the consumer receives the message for a particular topic when any message is posted on that topic. Once the consumer subscribes to a particular topic, its job is over. The instructions to be executed when a message arrives for a topic are called automatically.The consumer doesn't need to worry about that. The pub/sub model is asynchronous, whereas many web applications are synchronous, meaning the client usually waits for a response, for example, a page of text when a user sends a request by clicking a button in a registration form or when an event occurs. Asynchronous systems are very different from synchronous systems, and they are being used more frequently in many enterprise systems as well as in web applications, such as Asynchronous JavaScript and XML (AJAX) and Web services (fire and forget operations). Point-to-Point Queuing (P2P) Messaging ModelThe P2P model allows JMS clients to send and receive messages both synchronously and asynchronously using another channel called queues. Normally, in the P2P model, a consumer has to request a message that a producer sends to the channel queue. In other words, this is a "pull" or poll-based model rather than a push-based model such as pub/sub. However, in JMS, an option exists that allows P2P clients to use a push model that is similar to the pub/sub model. A queue may have multiple receivers, but only one receiver may consume each message at a time. P2P also allows clients to see the content of the queue before consuming its messages. Examples of JMS Usage in EnterprisesNow that you have an idea of what JMS is, the next questions are why is JMS used and where is it used? The following information is a short introduction to its use in the enterprise world. Most enterprises have legacy applications and new applications that cannot interoperate. Organizations have a strong desire to integrate these applications so the applications can cooperate and share information. The integration of such applications is generally called Enterprise Application Integration (EAI). A variety of home-grown solutions are used for EAI, but enterprise messaging systems are central to most of them. EAI messaging systems allow applications to communicate data and events with each other while remaining physically independent. Businesses can exchange data using Electronic Data Interchange (EDI), but the cost of entering data is high and data is entered using batch processes, not as real-time business events. The Internet, XML, and modern messaging systems have radically changed how businesses exchange data. Modern messaging systems are central to most businesses because they enable organizations to exchange data without requiring that organizations tightly integrate their business systems. For example, a manufacturer can set up a topic for bids on raw materials. Suppliers can subscribe to a topic by responding back to the manufacturer. Suppliers can be added or removed at will. These days, many systems are geographically dispersed, and businesses face problems related to the geographic dispersion of enterprise systems. Many systems have to communicate with the centralized systems at corporate headquarters. Sensitive data that is administered locally has to be synchronized with the main office. JMS allows a safe and secure exchange of data across geographically distributed business. Benefits of JMSThe fundamental concept of MOM is that communication between applications is intended to be asynchronous. This means there will always be one-way communication between systems. Once a message is sent, the producer can do other jobs; the producer doesn't have to wait for a response. In this type of messaging system, each system is decoupled from other systems. So the failure of one system does not affect other systems. Network failures can occur, and JMS guarantees delivery, that is, JMS guarantees a message will be received by the consumer when the consumer recovers to normal state. JMS also has a store-and-forward mechanism, which means that the underlying messaging server writes the message to a persistent system if the intended consumers are currently unavailable. The store-and-forward mechanism delivers all the messages that the consumer missed while it was unavailable. Practice Using JMSSo far, I have discussed what JMS is, why it is used, and where it is used. Now let's see how to use JMS. PrerequisitesThe first problem in implementing a sample message system is deciding the kind of message server to use and its availability. In this example, we are going to use Sun Java System Application Server 9.0, which is easy to download. This example requires that Java SDK 1.5 be installed as well, or you can download a complete package from download a complete package. Then, for creating the producer and the consumer, the required Java code file must be compiled. So it is best to download an IDE. I use Eclipse 3.2, which can be downloaded from http://www.eclipse.org/downloads/. From the installation of Sun Java System Application Server, you can obtain the JAR files that are required for the
Java program to run. In your classpath, include the JAR files Configuring the Message ServerLet's create a simple chat program because messages are closely related to the word "chat," and the chat program is about sending and receiving messages. As you might guess, the ingredients for a JMS application are a message producer application, a message server, and a consumer application. These applications are tested using the Sun Java System Message Queue server with Microsoft Windows XP as the operating system. Let's start by first configuring the message server. Note: I tested the sample program using Microsoft Windows XP. However, because the client program and the server run on the Java
platform, the sample program should run on all platforms supported by Java technology. If you run the program on the Solaris Operating System,
you can start the Sun Java System Application Server and the admin console by using If you are using Windows XP, start the Sun Java System Application Server by clicking Start->Programs->Sun Microsystems->Application Server PE 9->Start Default server. After the server starts, start the admin console by clicking Start->Programs->Sun Microsystems->Application Server PE 9->Admin console. Provide the admin user name and password. You should get a screen similar to Figure 4.
Figure 4: Sun Java System Application Server Admin Console Then expand the resource node by clicking the arrow to the left of Resources in the tree. Then expand the JMS Resources node, and then click Connection Factories. Create a new connection factory by clicking the New button on the right side of the screen. You should receive a screen similar to the one shown in Figure 5.
Figure 5: New JMS Connection Factory Type Then click Destination Resources in the tree (below Connection Factories). Create a JMS destination resource by clicking the New button on the right side of the screen.
Figure 6: New JMS Destination Resource Type Now you have successfully configured the message server by creating the connection factory and the channel (topic). Creating the ApplicationLet's move on to the application. We are going to create an application (producer functionality), which sends messages to the topic we just created. This application will also listen to the topic for messages (consumer functionality). In other words, the application will act as both the producer and the consumer. You will understand more by looking at the following code for the application:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Hashtable;
import java.util.StringTokenizer;
import javax.jms.JMSException;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.Context;
import javax.naming.InitialContext;
public class Chat implements MessageListener{
private TopicSession pubSession;
private TopicSession subSession;
private TopicPublisher topicPublisher;
private TopicConnection topicConnection;
private String connectionID;
private String userId;
public void set(TopicSession pubSession, TopicSession subSession,
TopicPublisher topicPublisher, TopicConnection topicConnection,
String connectionID,String userId) {
this.pubSession = pubSession;
this.subSession = subSession;
this.topicPublisher = topicPublisher;
this.topicConnection = topicConnection;
this.connectionID = connectionID;
this .userId=userId;
}
public Chat(String topicName,String connectionID,String
connectionPassword,String userId)throws Exception{
if(null==userId)
throw new Exception();
InitialContext initialContext=(InitialContext)getIntialContext();
TopicConnectionFactory topicConnectionFactory=
(TopicConnectionFactory)initialContext.lookup
("TopicConnectionFactory");
TopicConnection topicConnection=
topicConnectionFactory.createTopicConnection
(connectionID,connectionPassword);
TopicSession pubSession=
topicConnection.createTopicSession
(false,Session.AUTO_ACKNOWLEDGE);
TopicSession subSession=
topicConnection.createTopicSession
(false,Session.AUTO_ACKNOWLEDGE);
Topic chatTopic=(Topic)initialContext.lookup(topicName);
TopicPublisher topicPublisher=
pubSession.createPublisher(chatTopic);
TopicSubscriber topicSubscriber=
subSession.createSubscriber(chatTopic);
topicSubscriber.setMessageListener(this);
set(pubSession, subSession, topicPublisher, topicConnection,
connectionID,userId);
topicConnection.start();
}
public static Context getIntialContext()throws javax.naming.
NamingException{
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:3700");
return new javax.naming.InitialContext(env);
}
public void onMessage(javax.jms.Message message) {
try{
TextMessage textMessage=(TextMessage)message;
String text=textMessage.getText();
StringTokenizer stringTokenizer=new StringTokenizer(text,":");
if(!userId.equalsIgnoreCase(stringTokenizer.nextToken().trim()))
System.out.println(text);
}catch(JMSException exception){
exception.printStackTrace();
}
}
protected void writeMessage(String text)throws JMSException{
TextMessage textMessage=pubSession.createTextMessage();
textMessage.setText(userId+" : "+text);
topicPublisher.publish(textMessage);
}
public void close()throws JMSException{
topicConnection.close();
}
public static void main(String args[])throws Exception{
try{
Chat chat=new Chat("Topic","guest","guest","User3");
System.out.println("Welcome "+chat.userId);
BufferedReader bufferedReader=
new BufferedReader(new InputStreamReader(System.in));
while(true){
String message=bufferedReader.readLine();
if(message.equalsIgnoreCase("exit")){
chat.close();
System.exit(0);
}else
chat.writeMessage(message);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
In the The resources, such as ConnectionFactory and Topic that we configured in the message server, can be accessed by the clients with the help of the JNDI API. For those who are not familiar with the JNDI API, it provides an abstraction to several naming and directory services. Using a naming service, the objects, files, and devices can be bound to a name. So instead of using a cryptic network address, we can refer to an object using a name. The client can use the JNDI API to obtain references to the JMS objects that are in the message server. The following piece of code is used to create a context for the JNDI resources. A context is like the root of a file system, and once we get the root, we can travel to any directory and get the appropriate file. For getting files, we need the connection factory name, the protocol, the IP address, and the port, which we use to connect to the naming service in the server.
InitialContext initialContext=
(InitialContext)getIntialContext();
public static Context getIntialContext()throws javax.naming.
NamingException{
Hashtable env=new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.enterprise.naming.SerialInitContextFactory");
env.put("java.naming.provider.url", "iiop://localhost:3700");
//localhost:<RMIport>
return new javax.naming.InitialContext(env);
}
This method creates a
initialContext=(InitialContext)getIntialContext();
TopicConnectionFactory topicConnectionFactory=
(TopicConnectionFactory)initialContext.lookup
("TopicConnectionFactory");
TopicConnection topicConnection=
topicConnectionFactory.createTopicConnection
(connectionID,connectionPassword);
TopicSession pubSession=topicConnection.
createTopicSession (false,Session.AUTO_ACKNOWLEDGE);
TopicSession subSession=topicConnection.createTopicSession
(false,Session.AUTO_ACKNOWLEDGE);
Topic chatTopic=(Topic)initialContext.lookup(topicName);
TopicPublisher topicPublisher=pubSession.createPublisher
(chatTopic);
TopicSubscriber topicSubscriber=subSession.createSubscriber
(chatTopic);
We use this context to get references to the JMS objects from the server. By using the JNDI Name
Using this Then two sessions are created from the connection, one for publishing the messages to the topic and one for
receiving messages from the topic. The reason for implementing separate sessions is that threading restrictions are
imposed by JMS. The Boolean parameter in The next parameter is the String value, which indicates the session type. Here we are using
topicSubscriber.setMessageListener(this); set(pubSession, subSession, topicPublisher, topicConnection, connectionID, userId); topicConnection.start();
Focusing our attention back on the
protected void writeMessage(String text)throws JMSException{
TextMessage textMessage= pubSession.createTextMessage();
textMessage.setText(userId+" : "+text);
topicPublisher.publish(textMessage);
}
In the When the message is published to the topic, the server pushes the message to the listeners. Since our application is
also a listener, the listener method
public void onMessage(javax.jms.Message message) {
try{
TextMessage textMessage=(TextMessage)message;
String text=textMessage.getText();
StringTokenizer stringTokenizer=new StringTokenizer(text,":");
if(!userId.equalsIgnoreCase(stringTokenizer.nextToken().trim()))
System.out.println(text);
}catch(JMSException exception){
exception.printStackTrace();
}
}
We know that the message we want to publish is a text message, so we are explicitly type casting
the message to Running the ApplicationTo run our application, it will be good to supply parameters to the As discussed earlier, configure the message server (Sun Java System Application Server), and keep it in server started mode. If you are running the client application with the command line parameters, start two application instances using different user names. If you are running the application in an editor, you can run one application instance with a hard-coded user name and run another instance by changing the value of the user name. Try to post a message from one application instance and see that the message is pushed to the other application instance. If that happens, you have successfully created an enterprise messaging system!! You can change the implementation of the application from topic to queue to achieve P2P communication. The following code is for creating a connection, a session, and a receiver (instead of a subscriber in the pub/sub model) for the P2P model.
QueueConnectionFactory
queueConnectionFactory=(QueueConnectionFactory)initialContext.
lookup("QueueConnectionFactory");
QueueConnection queueConnection = queueConnectionFactory.
createQueueConnection(connectionID,connectionPassword);
QueueSession queSession= queueConnection. createQueueSession
(false,javax.jms.Session.AUTO_ACKNOWLEDGE);
Queue chatQueue=( Queue)initialContext.lookup(queueName);
QueueReceiver queueReceiver= queSession.createReceiver(chatQueue);
queueReceiver.setMessageListener(this);
queueConnection.start();
There is no difference in the code except for the Receiver object instead of the Subscriber object. To ensure you understand how to create a queue in the server, here is the code for sending information to the queue: QueueSender queueSender =queSession.createSender(chatQueue); queueSender.send(message,javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY,1800000); This is an overloaded method from ConclusionIn this article, I discussed what JMS is, why it is used, where it is used, and how it is used. My aim was to enable you to see that JMS is an important technology in the enterprise world by providing information about enterprise problems that require loosely coupled, asynchronous, enterprise-quality systems. There might be other ways to solve enterprise problems, but I hope this information helps you to make good decisions about using this technology. I assumed this information might be useful for developers who are new to this paradigm. Often, when developers look for enterprise-quality technology, they don't find low-level information that is appropriate for those who are new to the field. If you have any comments about this article, please communicate them to me. About the AuthorNishant M.C. is a software engineer currently working on the Java 2 Platform, Enterprise Edition (J2EE) platform. He has a great passion for Java technology, and analyzes various Java enterprise technologies. He holds a Bachelor of Engineering degree from Anna University, India. You can contact him at nishantmc [at] gmail.com.
Comments (latest comments first)Discuss and comment on this resource in the BigAdmin Wiki
Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) is provided under this License. |
BigAdmin SubscriptionsBigAdmin Areas
BigAdmin Sun Center
BigAdmin Topics | ||||||||||