• Loading
    • Java Message Service (JMS) overview


      Introduction


      The Java Message Service (JMS) API is a Java Message Oriented Middleware(MOM) API for sending
      messages between two or more clients. JMS is a part of the Java Platform, Enterprise Editionand is
      defined by a specification developed under the Java Community process as JSR 914. It is a messaging
      standard that allows application components based on the java 2 Platform, Enterprise Edition (J2EE)
      to create, send, receive, and read messages. It allows the communication between different
      components of a distributed application to be loosely coupled, reliable and asynchronous.

      The JMS API can be downloaded from http://java.sun.com/products/jms/.

      JMS API Architecture


      A JMS application is composed of the following parts.

      A JMS provider is a messaging system that implements
      the JMS interfaces and provides administrative and control features. An
      implementation of the J2EE platform at release 1.3 includes a JMS provider.

      JMS clients are the programs or components, written in
      the JavaTM programming language, that produce and consume messages.

      Messages are the objects that communicate information
      between JMS clients.

      Administered objects are preconfigured JMS objects
      created by an administrator for the use of clients. The two kinds of administered
      objects are destinations and connection factories, which are described in Section "Administered Objects."

      Native clients are programs that use a messaging
      product's native client API instead of the JMS API. An application first created
      before the JMS API became available and subsequently modified is likely to
      include both JMS and native clients.



      Administrative tools allow us to bind destinations and connection factories into a Java
      Naming and Directory InterfaceTM (JNDI) API namespace. A JMS client can then look up
      the administered objects in the namespace and then establish a logical connection to the
      same objects through the JMS provider.

      Messaging Domains


      Before the JMS API existed, most messaging products supported either the point-to-point or the
      publish/subscribe approach to messaging. The JMS Specification provides a separate domain for each
      approach and defines compliance for each domain. A standalone JMS provider may implement one or
      both domains. A J2EE provider must implement both domains.
      In fact, most current implementations of the JMS API provide support for both the point-topoint
      and the publish/subscribe domains, and some JMS clients combine the use of both
      domains in a single application. In this way, the JMS API has extended the power and flexibility
      of messaging products.

      Point-to-Point Messaging Domain
      A point-to-point (PTP) product or application is built around the concept of message
      queues, senders, and receivers. Each message is addressed to a specific queue, and
      receiving clients extract messages from the queue(s) established to hold their messages.
      Queues retain all messages sent to them until the messages are consumed or until the
      messages expire.


      • Each message has only one consumer.
      • 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.
      • The receiver acknowledges the successful processing of a
      message.

      Publish/Subscribe Messaging Domain
      In a publish/subscribe (pub/sub) product or application, clients address messages to a
      topic. Publishers and subscribers are generally anonymous and may dynamically publish
      or subscribe to the content hierarchy. The system takes care of distributing the messages
      arriving from a topic's multiple publishers to its multiple subscribers. Topics retain
      messages only as long as it takes to distribute them to current subscribers.

      Pub/sub messaging has the following characteristics.
      • Each message may have multiple consumers.
      • Publishers and subscribers 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.



      Message Consumption


      Messaging products are inherently asynchronous in that no fundamental timing
      dependency exists between the production and the consumption of a message. However,
      the JMS Specification uses this term in a more precise sense. Messages can be consumed in
      either of two ways:

      • 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 client 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, which acts on the contents of the message.

      JMS Interfaces


      ConnectionFactory:-A javax.jms.ConnectionFactory is a factory that provides connections
      for clients in a JMS application. It's usually configured by an administrator and is given a
      name and then registered with the naming service. The QueueConnectionFactory and the
      TopicConnectionFactory interfaces extend the ConnectionFactory interface to provide a
      unique factory for Queue and Topic messaging models, respectively. When a client needs
      to get a connection to send or receive a JMS message, the first step is to locate the
      ConnectionFactory and acquire a javax.jms.Connection.

      Connection:-A javax.jms.Connection represents an open channel to the messaging service.
      This connection is then used to create a javax.jms.Session that can be used for this client.
      Connections normally are thread-safe and support multiple clients accessing the
      connection at the same time. To create a connection for a Queue, you can use either of
      these two methods on the QueueConnectionFactory class:

      QueueConnection createQueueConnection() throws JMSException;
      QueueConnection createQueueConnection(String username, String
      password) throws JMSException;

      Session:- A javax.jms.Session defines a serial order for producing and consuming
      messages. A JMS session, along with its producers and consumers, should be accessed by
      only one thread at a time. The Session interface is extended by the javax.jms.QueueSession
      and the javax.jms.TopicSession interfaces to provide different functionality depending on
      the messaging model.

      Destination:-A javax.jms.Destination represents a place where you send JMS messages to
      or receive them from. In one sense it is like an address, in that it is named. The destination
      typically lives on a server that is remote to the clients. JMS provides two types of
      destinations, javax.jms.Queue and the javax.jms.Topic. The following code fragments
      show how a destination is found using JNDI. This code fragment is assuming that an
      InitialContext has already been created.

      Queue myQueue = null;
      try { myQueue = (Queue) context.lookup("AuctionNotificationQueue");
      } catch( Exception ex ) { ex.printStackTrace();}

      MessageConsumer and MessageProducer:-The message producer and consumer are
      decoupled from one another. A producer will send messages to a destination regardless of
      whether or not a consumer is there to receive it. A message producer is provided by the
      javax.jms.MessageProducer interface, and the message consumer is provided by the
      javax.jms.MessageConsumer interface. When building a JMS application using the PTP
      message model, you create a javax.jms.QueueSender and a javax.jms.QueueReceiver. If
      you were using the Pub/Sub model, you would use the javax.jms.TopicPublisher and the
      javax.jms.TopicSubscriber interfaces

      Message:- The javax.jms.Message interface is the root interface for all JMS messages. It
      encapsulates all the information being exchanged between applications. There are five
      types of JMS messages :
      Name Description
      BytesMessage Used to send a message containing a stream of
      uninterpreted bytes.
      MapMessage Used to send a set of name-value pairs where names are
      strings and values are Java primitive types.
      ObjectMessage Used to send a message that contains a serializable Java
      object. Only serializable Java objects can be used.
      StreamMessage Used to send a stream of Java primitives. It is filled and read
      sequentially. Its methods are based largely on those found
      in java.io.DataInputStream and java.io.DataOutputStream.
      TextMessage Used to send a message containing a java.lang.String. This
      could even be an XML that has been serialized from a
      StringBuffer.

      Writing Simple JMS client Applications


      Setting Your Environment for Running Applications (Prerequisites):-
      Before we can run the applications we need to make necessary environment settings for compiling
      and running J2EE applications. Following settings need to be made for Microsoft Windows :
      %JAVA_HOME% Directory in which the JavaTM 2 SDK, Standard Edition, version 1.X, is installed
      %J2EE_HOME% Directory in which the J2EE SDK 1.x is installed, usually C:\j2sdkee1.x
      %CLASSPATH% Include the following:
      .;%J2EE_HOME%\lib\j2ee.jar;
      %J2EE_HOME%\lib\locale
      %PATH% Include %J2EE_HOME%\bin



      A Sample Point-to-Point Example:
      PTP Client Programs:
      The following are the two PTP client programs, one for sending a message to the queue and the other
      for receiving the message.

      SimpleQueueSender.java
      Code:
      import javax.jms.*;
      import javax.naming.*;
      public class SimpleQueueSender {
      /**
      * Main method.
      *
      * @param args the queue used by the example and,
      * optionally, the number of messages to send
      */
      public static void main(String[] args) {
      String queueName = null;
      Context jndiContext = null;
      QueueConnectionFactory queueConnectionFactory = null;
      QueueConnection queueConnection = null;
      QueueSession queueSession = null;
      Queue queue = null;
      QueueSender queueSender = null;
      TextMessage message = null;
      final int NUM_MSGS;
      if ( (args.length < 1) || (args.length > 2) ) {
      System.out.println("Usage: java SimpleQueueSender " +
      "<queue-name> [<number-of-messages>]");
      System.exit(1);
      }
      queueName = new String(args[0]);
      System.out.println("Queue name is " + queueName);
      if (args.length == 2){
      NUM_MSGS = (new Integer(args[1])).intValue();
      } else {
      NUM_MSGS = 1;
      }
      /*
      * Create a JNDI API InitialContext object if none exists
      * yet.
      */
      try {
      jndiContext = new InitialContext();
      } catch (NamingException e) {
      System.out.println("Could not create JNDI API " +
      "context: " + e.toString());
      System.exit(1);
      }
      /*
      * Look up connection factory and queue. If either does
      * not exist, exit.
      */
      try {
      queueConnectionFactory = (QueueConnectionFactory)
      jndiContext.lookup("QueueConnectionFactory");
      queue = (Queue) jndiContext.lookup(queueName);
      } catch (NamingException e) {
      System.out.println("JNDI API lookup failed: " +
      e.toString());
      System.exit(1);
      }
      /*
      * Create connection.
      * Create session from connection; false means session is
      * not transacted.
      * Create sender and text message.
      * Send messages, varying text slightly.
      * Send end-of-messages message.
      * Finally, close connection.
      */
      try {
      queueConnection =
      queueConnectionFactory.createQueueConnection();
      queueSession =
      queueConnection.createQueueSession(false,
      Session.AUTO_ACKNOWLEDGE);
      queueSender = queueSession.createSender(queue);
      message = queueSession.createTextMessage();
      for (int i = 0; i < NUM_MSGS; i++) {
      message.setText("This is message " + (i + 1));
      System.out.println("Sending message: " +
      message.getText());
      queueSender.send(message);
      }
      /*
      * Send a non-text control message indicating end of
      * messages.
      */
      queueSender.send(queueSession.createMessage());
      } catch (JMSException e) {
      System.out.println("Exception occurred: " +
      e.toString());
      } finally {
      if (queueConnection != null) {
      try {
      queueConnection.close();
      } catch (JMSException e) {}
      }
      }
      }
      }
      SimpleQueueReceiver.java

      Code:
      import javax.jms.*;
      import javax.naming.*;
      public class SimpleQueueReceiver {
      /**
      * Main method.
      *
      * @param args the queue used by the example
      */
      public static void main(String[] args) {
      String queueName = null;
      Context jndiContext = null;
      QueueConnectionFactory queueConnectionFactory = null;
      QueueConnection queueConnection = null;
      QueueSession queueSession = null;
      Queue queue = null;
      QueueReceiver queueReceiver = null;
      TextMessage message = null;
      /*
      * Read queue name from command line and display it.
      */
      if (args.length != 1) {
      System.out.println("Usage: java " +
      "SimpleQueueReceiver <queue-name>");
      System.exit(1);
      }
      queueName = new String(args[0]);
      System.out.println("Queue name is " + queueName);
      /*
      * Create a JNDI API InitialContext object if none exists
      * yet.
      */
      try {
      jndiContext = new InitialContext();
      } catch (NamingException e) {
      System.out.println("Could not create JNDI API " +
      "context: " + e.toString());
      System.exit(1);
      }
      /*
      * Look up connection factory and queue. If either does
      * not exist, exit.
      */
      try {
      queueConnectionFactory = (QueueConnectionFactory)
      jndiContext.lookup("QueueConnectionFactory");
      queue = (Queue) jndiContext.lookup(queueName);
      } catch (NamingException e) {
      System.out.println("JNDI API lookup failed: " +
      e.toString());
      System.exit(1);
      }
      /*
      * Create connection.
      * Create session from connection; false means session is
      * not transacted.
      * Create receiver, then start message delivery.
      * Receive all text messages from queue until
      * a non-text message is received indicating end of
      * message stream.
      * Close connection.
      */
      try {
      queueConnection =
      queueConnectionFactory.createQueueConnection();
      queueSession =
      queueConnection.createQueueSession(false,
      Session.AUTO_ACKNOWLEDGE);
      queueReceiver = queueSession.createReceiver(queue);
      queueConnection.start();
      while (true) {
      Message m = queueReceiver.receive(1);
      if (m != null) {
      if (m instanceof TextMessage) {
      message = (TextMessage) m;
      System.out.println("Reading message: " +
      message.getText());
      } else {
      break;
      }
      }
      }
      } catch (JMSException e) {
      System.out.println("Exception occurred: " +
      e.toString());
      } finally {
      if (queueConnection != null) {
      try {
      queueConnection.close();
      } catch (JMSException e) {}
      }
      }
      }
      }

      JMS Exceptions


      All JMS Exceptions inherit from the base exception JMSException.java.

      IllegalStateException : This exception is thrown when a method is invoked at an illegal
      or inappropriate time or if the provider is not in an appropriate state for the requested
      operation.
      InvalidClientIDException : This exception must be thrown when a client attempts to
      set a connection's client id to a value that is rejected by a provider.
      InvalidDestinationException : This exception must be thrown when a destination is
      either not understood by a provider or is no longer valid.
      InvalidSelectorException : This exception must be thrown when a JMS client attempts
      to give a provider a message selector with invalid syntax.
      JMSException : This is the root class of all JMS exceptions.
      ▪ JMSSecurityException : This exception must be thrown when a provider rejects a user
      name/password submitted by a client.
      MessageEOFException : This exception must be thrown when an unexpected end of
      stream has been reached when a StreamMessage or BytesMessage is being read.
      MessageFormatException : This exception must be thrown when a JMS client attempts
      to use a data type not supported by a message or attempts to read data in a message as
      the wrong type.
      MessageNotReadableException :This exception must be thrown when a JMS client
      attempts to read a write-only message.
      MessageNotWriteableException : This exception must be thrown when a JMS client
      attempts to write to a read-only message.
      ResourceAllocationException : This exception is thrown when a provider is unable to
      allocate the resources required by a method.
      TransactionInProgressException : This exception is thrown when an operation is
      invalid because a transaction is in progress.
      TransactionRolledBackException : This exception must be thrown when a call to
      Session.commit results in a rollback of the current transaction.

      Compiling the PTP Clients


      To compile the PTP example, do the following.
      1. Make sure that you have set the environment variables
      shown in the above table.
      2. At a command line prompt, compile the two source files:
      javac SimpleQueueSender.java
      javac SimpleQueueReceiver.java

      Starting the JMS Provider


      When you use the J2EE SDK 1.X, your JMS provider is the SDK. At another command
      line prompt, start the J2EE server as follows:
      j2ee -verbose
      Wait until the server displays the message "J2EE server startup complete."

      Creating the JMS Administered Objects


      In the window in which you compiled the clients, use the j2eeadmin command to create a
      queue named MyQueue. The last argument tells the command what kind of destination to
      create.

      j2eeadmin -addJmsDestination MyQueue queue

      To make sure that the queue has been created, use the following command:

      j2eeadmin -listJmsDestination

      This example uses the default QueueConnectionFactory object supplied with the J2EE
      SDK 1.X. With a different J2EE product, you might need to create a connection factory
      yourself.

      Running the PTP Clients


      Run the clients as follows.
      1. Run the SimpleQueueSender program, sending three
      messages. You need to define a value for jms.properties.
      • On a Microsoft Windows system,
      type the following command:
      java -

      Djms.properties=%J2EE_HOME%\config\jms_client.prop erties
      SimpleQueueSender MyQueue 3

      The output of the program looks like this:

      Queue name is MyQueue
      Sending message: This is message 1
      Sending message: This is message 2
      Sending message: This is message 3
      2. In the same window, run the SimpleQueueReceiver program, specifying the queue
      name. The java commands look like this:
      • Microsoft Windows systems:
      java -

      Djms.properties=%J2EE_HOME%\config\jms_client.prop erties
      SimpleQueueReceiver MyQueue
      The output of the program looks like this:

      Queue name is MyQueue
      Reading message: This is message 1
      Reading message: This is message 2
      Reading message: This is message 3

      Deleting the Queue


      You can delete the queue you created as follows:
      j2eeadmin -removeJmsDestination MyQueue

      Limitations of JMS


      • Durable subscribers are currently not supported. Trying to invoke the
      Session.createDurableSubscriber method or the Session.unsubscribe method throws a
      JMSException.
      • When consuming messages from a Queue, and a session recovery takes place, the
      JMSRedelivered header of the recovered messages is not set. This problem does not occur with
      Topic recovered messages.Message recovery takes place in the following scenarios:
      Transaction rollback.
      The Session.recover method is invoked.
      • Message Selectors are currently not supported. Creating a MessageConsumer with a selector
      does not effect the message consumption. Note: Since the JMS message is also a space entry,
      you can use the space template matching and querying features.
      • Message priority is currently not supported. Currently, all message are have the same priority:
      Message.DEFAULT_PRIORITY. When setting the priority of a message, the priority value is
      set correctly in the message, but the JMS layer does not take it in consideration.
      As a result, when messages are redelivered, even if a message with higher priority arrives, it is
      not delivered before other messages.
      • JMS sessions support only a single MessageConsumer. Trying to create a consumer for a
      session that already has a consumer throws a JMSException.
      • JMS does not support StreamMessage. Using this message type will probably cause errors, and
      therefore is not recommended. A working implementation of StreamMessage is planned for
      future releases.
      • JMS does not support message delivery threshold. A JMS provider might implement a
      message delivery threshold that prevents a message from being redelivered (due to session
      recovery) more times than that threshold number. When that number is passed, the message is
      sent to a dead letter queue. Currently, this feature is not supported.
      • In cluster environment, custom JMS destinations that are specified in the properties file are not
      bound to the RMI registry.
      • JMS does not support destination partitioning. Currently, all messages of a JMS destination are
      routed to the same partition. The partition where the messages go is resolved according to the
      index field of the message which, currently, is the destination name.



    Disclaimer: Users of techforum4u.com are responsible for ensuring that any material they post (article, blog posts, images or other mulitimedia content) does not violate or infringe upon the copyright, patent, trademark, or any personal or proprietary rights of any third party, and is posted with the permission of the owner of such rights.Anyone who violates these rules may have their access privileges removed without warning.