JMS: Java Messaging Service |
1. Indroduction and definitions
JMS stands for Java Message Service. Messaging is a method of communication
between software components or applications. It is a peer-to-peer
system, that is, both the origin and the destination of a communication have equal
capabilties in contrast with client/server system. Messaging clients, once connected
to the messaging agent can send and receive messages to and from each other.
The messaging agent provides the facilities to create, send, receive, and read messages.
2. JMS architecture
3. Messaging domainsIn JMS, J2EE provider implements PTP and Publish/Subscribe domains.3.1. PTP Mechanism
3.2. Publish/Subscribe
4. JMS API Programming Model
4.1. Connection FactoriesA connection factory is the object that a client uses to create a connection with a provider.J2EE SDK comes with a pair of preconfigured connection factories which are QueueConnectionFactory and TopicConnectionFactory interfaces. It is possible to create new connection factories by using the following command-lines:
C:\> j2eeadmin -addJmsFactory jndi_name queue C:\> j2eeadmin -addJmsFactory jndi_name topic We perform first a JNDI API lookup of the connection factory, and set an InitialContext object to use to look up the QueueConnectionFactory and the TopicConnectionFactory; as:
Context ctx = new InitialContext(); //For queue: QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory"); //For Topic: TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory"); Calling the InitialContext method with no parameters: InitialContext(); will use the file named jndi.properties, that indicates the JNDI API implementation and the namespace to use. 4.2. DestinationsA destination is the object a client uses to specify the target of messages it produces and the source of messages it receives. In the PTP messaging domain, destinations are called queues; we use the following J2EE SDK command to create them:
j2eeadmin -addJmsDestination queue_name queue
C:\> j2eeadmin -addJmsDestination topic_name topic
A JMS application may use multiple queues and/or topics. In addition to looking up a connection factory, we look up a destination. If we have created a topic named "TheTopic", we perform a JNDI API lookup of TheTopic and assign it to a Topic object:
Topic TheTopic = (Topic) ctx.lookup("TheTopic");
Queue TheQueue = (Queue) ctx.lookup("TheQueue");
4.3. ConnectionsA connection with a JMS provider is a virtual. It could represent an open TCP/IP socket between a client and a provider service daemon. Once a connection is created, we can then create one or more sessions.Like connection factories, connections have two forms that implement the QueueConnection or the TopicConnection interface. We use QueueConnectionFactory or a TopicConnectionFactory object to create a connection: //For Queue:
QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
queueConnection.close(); topicConnection.close(); Before to use an application , we have to call the connection's start method. To stop message delivery temporarily without closing the connection, we call the stop method. 4.4. SessionsA session is a single-threaded context to produce and receive messages. Like connections, Sessions have two forms, implementing the QueueSession or the TopicSession interface. Once TopicConnection object, or QueueConnection object is created , we use it to successively create a TopicSession, or a QueueSession:
TopicSession topicSession =
topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
QueueSession queueSession = queueConnection.createQueueSession(true, 0); 4.4. Message ProducersA message producer is an object created by a session and is used for sending messages to a destination. The PTP form of a message producer implements the QueueSender interface. The pub/sub form implements the TopicPublisher interface.If we use a QueueSession to create a sender for the queue "TheQueue", and TopicSession to create a publisher for the topic "TheTopic"; the related codes are:
QueueSender queueSender = queueSession.createSender(TheQueue); TopicPublisher topicPublisher = topicSession.createPublisher(TheTopic); We can create an unidentified producer by specifying null as the argument to createSender or createPublisher. Once the message producer is created, we can use it to send messages first created .
queueSender.send(message);
topicPublisher.publish(message); For a created unidentified producer, use the overloaded send or publish method that specifies the destination as the first parameter. 4.5. Message ConsumersA message consumer is an object created by a session, and used to receive messages sent to a destination. It allows a JMS client to register interest in a destination with a JMS provider, which manages the delivery of messages from a destination to the registered consumers. The destination is either queue or topic. The PTP form of message consumer implements the QueueReceiver interface. The pub/sub form implements the TopicSubscriber interface. If we use a QueueSession to create a receiver for the queue "TheQueue", and a TopicSession to create a subscriber for the topic "TheTopic"; the related codes are://For Queue:
QueueReceiver queueReceiver = queueSession.createReceiver(TheQueue);
TopicSubscriber topicSubscriber = topicSession.createSubscriber(TheTopic);
We use the TopicSession.createDurableSubscriber method to create a durable topic subscriber. Once we have created a message consumer, it becomes active, and we can use it to receive messages. We can use the close method for a QueueReceiver or a TopicSubscriber to make the message consumer inactive. With a QueueReceiver or a TopicSubscriber, we use the receive method to consume a message synchronously. This method can be used at any time after the start method is called:
queueConnection.start();
Message m = queueReceiver.receive();
topicConnection.start();
Message m = topicSubscriber.receive(1500);
To consume a message asynchronously, we use a message listener. 4.6. Message ListenersA message listener is an object that acts as an asynchronous event handler for messages. This object implements the MessageListener interface, which contains one method, onMessage, in which we define the actions to be taken when a message arrives.We register the message listener with QueueReceiver or TopicSubscriber by using the setMessageListener method. If we define a class named TheTopicListener that implements the MessageListener interface, we can register the message listener as follows:
TheTopicListener topicListener = new TheTopicListener();
topicSubscriber.setMessageListener(topicListener);
After the message listener is registred first, we call then start method on the QueueConnection or the TopicConnection to begin a message delivery. Once message delivery begins, the message consumer automatically calls the message listener's onMessage method whenever a message is delivered. The onMessage method takes one argument of type Message, which the method can cast to any of the other message types. A message listener is used to any destination type (queue or topic). The same listener can obtain messages from either a queue or a topic, depending on the used object QueueReceiver or a TopicSubscriber. A message listener needs a message type and format, and destination type to reply to a message and create a producer for the destination type. 4.7. Message SelectorsOur applications need to filter the messages it receives. JMS API message selector is used for this purpose. Filtering messages is done by the JMS provider.A message selector is a String that contains an expression that we do not desire. The syntax of the expression is based on a subset of the SQL92 conditional expression syntax. The createReceiver, createSubscriber, and createDurableSubscriber methods have forms to specify a message selector as an argument when we create a message consumer. The message consumer then receives only messages filtred with respect to their headers and properties, not to message body. 5. ExamplesHere two examples. One for Queue domain, the second for Topic domain.For this, we need a java compiler, jms and corba related classes. The Java compiler J2SE v 1.4.2_04 and the j2sdkee1.3.1 server have the necessary to run these two examples. We can dowload J2SE v 1.4.2_04 compiler at v 1.4.2_04, and the server j2sdkee1.3.1 at j2sdkee1.3.1, Unzip the related file; then go to: Start - Setting - control panel - Advanced - Environment Variables and set the variables and their values. Place the following values AT FIRST
JAVA_HOME : c:\j2sdk1.4.2_04 J2EE_HOME : c:\j2sdkee1.3.1 PATH : C:\j2sdk1.4.2_04\bin;C:\j2sdkee1.3.1\bin CLASSPATH : .;C:\j2sdkee1.3.1\lib\j2ee.jar;C:\j2sdkee1.3.1\lib\locale 5.1.PTP Queue domain5.1.1. The steps of the programs5.1.1.1. Sending programsThe sending program will have the following steps: 1. JNDI API lookup of the QueueConnectionFactory and queue, 2. Creating a connection and a session, 3. Creating a QueueSender, 4. Creating a TextMessage, 5. Sending messages to the queue, 6. Sending a control message to set the end of the message stream, 7. Closing the connection (then the session and QueueSender). The related progam is: TheQueueSender.java, 5.1.1.2. Receiving programs The receiving program will have the following steps: 1. JNDI API lookup of the QueueConnectionFactory and queue, 2. Creating a connection and a session, 3. Creating a QueueReceiver, 4. Starting the connection, the message delivery will then begin, 5. Receiving the messages sent to the queue until the end-of-message-stream control message is received, 6. Closing the connection (then the session and QueueReceiver). The related progam is: TheQueueReceiver.java, 5.1.2. Compiling the programs5.1.1.1. Sending programs1. Compile:
C:\>javac TheQueueSender.java C:\>javac TheQueueReceiver.java At another new command line prompt, start the J2EE server as follows:
C:\>j2ee -verbose
3. Create the JMS Administered Objects: In the first window in which the programs are compiled, use the j2eeadmin command to create a queue named TheQueue:
C:\>j2eeadmin -addJmsDestination TheQueue queue
4. Check wether the queue has been created. Use the following command:
C:\>j2eeadmin -listJmsDestination
5. Run TheQueueSender program; send twho messages. You need to define a value for jms.properties.
C:\>java -Djms.properties=%J2EE_HOME%\config\jms_client.properties TheQueueSender TheQueue 2
6. The output of the program looks like this:
Your queue name is TheQueue Java(TM) Message Service 1.0.2 Reference Implementation (build b14) Sending message: This is the 1 message Sending message: This is the 2 message 5.1.1.2. Receiving programs 7. In the same window, run the TheQueueReceiver program:
C:\>java -Djms.properties=%J2EE_HOME%\config\jms_client.properties TheQueueReceiver TheQueue
8. The output of the program looks like this:
The queue name is TheQueue Java(TM) Message Service 1.0.2 Reference Implementation (build b14) Reading the message: This is the 1 message Reading the message: This is the 2 message In a different terminal window, run TheQueueSender program. When the messages have been sent, (In the case TheQueueReceiver is runned first, it will display the queue and wait until TheQueueSender program start. It receives then the messages and exits). 9. To Delete the Queue, perform:
C:\>j2eeadmin -removeJmsDestination TheQueue
10. To stop the server, perform:
C:\>j2ee -stop
5.2.Pub/Sub Topic domainHere, we will use the publishing and subscribing programs related to pub/sub domain. We will use also the message listener that consumes messages asynchronously.5.2.1. The steps of the programs5.2.1.1. Publishing Clients programsHere are the steps: 1. JNDI API lookup of the TopicConnectionFactory and topic 2. Creating a connection and a session 3. Creating a TopicPublisher 4. Creating a TextMessage 5. Publishing messages to the topic 6. Closes the connection (then the session and TopicPublisher) The related progam is: TheTopicPublisher.java, 5.2.1.2. Subscribing Clients programs Here are the steps: 1. Performs a JNDI API lookup of the TopicConnectionFactory and topic, 2. Creates a connection and a session, 3. Creates a TopicSubscriber, 4. Creates an instance of the TextListener class and registers it as the message listener for the TopicSubscriber, 5. Starts the connection, causing message delivery to begin, 6. Listens for the messages published to the topic, stopping when the user enters the character q or Q, 7. Closes the connection, which automatically closes the session and TopicSubscriber, The related progam is: TheTopicSubscriber.java, 5.2.1.3. The message listener 1. When a message arrives at destination, the onMessage method is called automatically, 2. The onMessage method converts the incoming message to a TextMessage and displays its content. The related progam is: TextListener.java, 5.2.2. Compiling the Pub/Sub Clients programs5.2.2.1. Sending programs1. Compile:
C:\> javac TheTopicPublisher.java C:\> javac TheTopicSubscriber.java C:\>javac TextListener.java 2. Starting the JMS Provider by starting the J2EE server (if it it is not already running) in a new another terminal window:
C:\>j2ee -verbose
3. Creating the JMS Administered Objects Create a topic named TheTopic in the first window of command-line. (the last argument tells the command what kind of destination to create).
C:\>j2eeadmin -addJmsDestination TheTopic topic
4. Check if the ceated destination is here:
C:\>j2eeadmin -listJmsDestination
5. Running the Pub/Sub Clients programs:
C:\>java -Djms.properties=%J2EE_HOME%\config\jms_client.properties TheTopicSubscriber TheTopic
6. The program displays the following lines and hangs:
The name of the topic is TheTopic Java(TM) Message Service 1.0.2 Reference Implementation (build b14) To end the program, enter Q or q, then <return> 7. In another terminal window, run the TheTopicPublisher program:
C:\>java -Djms.properties=%J2EE_HOME%\config\jms_client.properties TheTopicPublisher TheTopic 4
8. The output of the program, in this second new windows, looks like this:
The name of Topic is TheTopic Java(TM) Message Service 1.0.2 Reference Implementation (build b14) Publishing message: This is the 1 message Publishing message: This is the 2 message Publishing message: This is the 3 message Publishing message: This is the 4 message In the first window, the program displays the following:
The name of the topic is TheTopic Java(TM) Message Service 1.0.2 Reference Implementation (build b14) To end the program, enter Q or q, then <return> Reading the message: This is the 1 message Reading the message: This is the 2 message Reading the message: This is the 3 message Reading the message: This is the 4 message 9. Deleting the Topic:
C:\>j2eeadmin -removeJmsDestination TheTopic
10. Stopping the Server:
C:\>j2ee -stop
|