JMS in WebSphere

Posted by Marcel Friedmann on 7:43 PM with No comments

WebSphere Application Server 8 / 8.5 provids a basic JMS support for most Java based messaging scenarios.
Advanced scenarios including e.g. clients written in languages different from java, require a fully featured messaging middleware system like Websphere MQ or Apache Active MQ.

This article discripes:
  • [What are topic and queues and why we should them -  todo ;-)]
  • Setup a JMS queue or topic on WebSphere 8.5.5. 
  • Publish and consume JMS queue messages Publish and consume JMS topic messages

Setup a JMS queue or topic on WebSphere 8.5.5.

Before creating the actual message endpoints (queues and topic) you need to create the basic messaging infrastracture (messaging bus). This example does not cover securing the messaging infrastructure. I will explain how to setup secure JMS connection in a separate blog post.
Expand Service Integration > Buses > New… 
Step 1: Enter a name for your messaging bus (e.g. jmsbus)
Step 1.1: > Next 
Step 2: > Finish
Now you need to associate the newly created message bus with the server process which hosts the message engine. The message engine is the component that actually handles the JMS messages.
First you need to add the servers as a bus member to the messaging bus.
Navigate to Service Integration > Buses > jmsbus > Bus members (under Topology) > Add 
Step 1: Select the server or cluster you want wo add as a bus member (e.g. server1) and click > Next.
Step 1.1: Choose if you want to use a file store or a data store (database store) to save the jms messages. If you are in a cluster environment you should use a data store. Click > Next.
Step 1.2 (file store option): Setup the file location for the jms file store. If you plan to send large jms messages (e.g. containing binary files) you also should increase the file store size. Click > Next.
Step 1.2. (data store option): Setup the database location, either by letting WebSphere generate an default database setup or by selecting an existing database. If you chose to use an existing data source this data source has to be configured seperatly. Click > Next.
Step 1.3: Hosting a message engine typically needs some memory. Step 1.3 allows you to adjust the heap size for your servers. Click > Next.
Step 2: > Finish and save the configuration!
After creating the basic messaging infrastructure we can now setup the JMS connection factory. A JMS connection factory is used to create connections to the specific JMS destinations (queues and topics).
Expand Resources > JMS > Queue Connection Factories > New (select your scope before!)
Select the “Default messaging provider” and click > OK.
Enter the Name and the JNDI name for the Queue Connection Factory. Also you need to select the newly created jmsbus under Connection. In this dialog you can also setup reliability settings for the queue connection factory like durable subscriptions and quality of service settings. However we do not need this kind of settings for this example.
Click > OK
To create an Topic Connection Factory expand Resources > JMS > Topic Connection Factories > New (select your scope before!)
Select the “Default messaging provider” and click > OK.
Enter the Name and the JNDI name for the Topic Connection Factory. Also you need to select the newly created jmsbus under Connection. In this dialog you can also setup reliability settings for the topic connection factory like durable subscriptions and quality of service settings. However we do not need this kind of settings for this example.
After creating the Queue / Topic Connection Factory we now can setup the specific queues or topics.
Expand Resources > JMS > Queues > New (select your scope before!)
Select the “Default messaging provider” and click > OK.
Enter a name and a JNDI name for the queue.
Under Connection select jmsbus as Bus name and “Create Service Integration Bus Destination” for Queue name. This leads to a new dialog.
Step 1: Enter an identifier (e.g. testQueueDest) and click > Next.
Step 2: Select the early created bus member and click > Next.
Step 3: > Finish.
Click OK.
After creating the queue we now setup an topic.
Expand Resources > JMS > Topics > New (select your scope before!)
Select the “Default messaging provider” and click > OK.
Enter a name and a JNDI name for the topic.
Under Connection select the jmsbus as Bus name and “Create Service Integration Bus Destination” for Topic space. This leads to a new dialog.
Step 1: Enter an identifier (e.g. testTopicDest) and click > Next.
Step 2: > Finish.
To allow remote connections (from clients outside of the WebSphere cell) you need to adjust some properties of the Connection Factories.
Expand Resource > JMS > Queue/Topic Connection Factory > jms-test-connection-factory
Under Provider endpoints enter the following triplet: <Server-Host-name>:<SIB-Endpoint-Port-of-Server/JVM>:BootstrapBasicMessaging
If you are using a cluster the triplet can be comma-seperated: host1:2812:BootstrapBasicMessaging,host2:2812:BootstrapBasicMessaging

Publish and consume JMS queue messages

Publishing JMS queue messages could be done remotely or locally (from inside the WebSphere Configuration Cell). If you connect locally you do not need the corbaloc stuff – just simply get the Factories and Queues with JNDI.
The following example runs on an IBM JRE. If you are running on a Oracle JRE you need some additional libraries. This libaries are located in your Websphere Installation folder (/runtimes ord /dev).

//Imports
        import java.text.DateFormat;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        import java.util.Properties;
        import javax.jms.JMSException;
        import javax.jms.Message;
        import javax.jms.Queue;
        import javax.jms.QueueBrowser;
        import javax.jms.QueueConnection;
        import javax.jms.QueueConnectionFactory;
        import javax.jms.QueueReceiver;
        import javax.jms.QueueSender;
        import javax.jms.QueueSession;
        import javax.jms.Session;
        import javax.jms.TextMessage;
        import javax.naming.Context;
        import javax.naming.InitialContext;
        import javax.naming.NamingException;
        
        //Class initialization
        Context ctx = null;
     QueueConnection connection = null;
  Queue inQueue = null;
  QueueSession session = null;
  boolean transacted = false;

  // Initialize properties for corba connection
  Properties p = new Properties();
  
  p.put(Context.INITIAL_CONTEXT_FACTORY,
    "com.ibm.websphere.naming.WsnInitialContextFactory");
  //PROVIDER_URL: corbaloc:iiop::
  p.put(Context.PROVIDER_URL, "corbaloc:iiop:127.0.0.1:2812");   
  p.put("com.ibm.CORBA.ORBInit", "com.ibm.ws.sib.client.ORB");
  
  System.out.println("put env - finished");

  try {
   ctx = new InitialContext(p);
   if (null != ctx)
    System.out.println("Got naming context");
                
   //Get the Queue Connection Factory
   QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) ctx
     .lookup("jms/testQCF");
   
            //Get the actual queue
   inQueue = (Queue) ctx.lookup("jms/testQueue");
   
            //Start the Connection
      connection = queueConnectionFactory.createQueueConnection();
   connection.start();
   
            //Create a transacted session
   session = connection.createQueueSession(transacted,
     Session.AUTO_ACKNOWLEDGE);
                    
            //Create a queue browser
   QueueBrowser qb = session.createBrowser(inQueue);
   
   //Send a JMS Queue Message
   QueueSender queueSender = session.createSender(inQueue);
            
            //Dummy message
   DateFormat dateFormat = new SimpleDateFormat(
     "yyyy/MM/dd HH:mm:ss");
   Date date = new Date();

   TextMessage outMessage = session
     .createTextMessage("My First JMS Message "
       + dateFormat.format(date));
                            
            //Send dummy message
   queueSender.send(outMessage);
   
            //Generate a receiver for the queue
   QueueReceiver queueReceiver = session.createReceiver(inQueue);
   Message inMessage = queueReceiver.receive(2000); //2000 = timeout
            
            //Print out received message
   if (inMessage instanceof TextMessage) {
    String replyString = ((TextMessage) inMessage).getText();
    System.out
      .println("Message received from queue is a TextMessage: "
        + replyString);
   }

  } catch (NamingException e) { 
   e.printStackTrace();
  } catch (JMSException e) {
   e.printStackTrace();


Publish and consume JMS topic messages

Publishing JMS topic messages (events) programmatically could be done remote or local (from inside the WebSphere Configuration Cell). If you connecting locally you do not need the corbaloc stuff – just simply get the Factories and Topics with JNDI.

//Imports
        import java.text.DateFormat;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        import java.util.Properties;

        import javax.jms.JMSException;
        import javax.jms.Message;
        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;
        import javax.naming.NamingException;
        
        //Class initialization
        
        Context ctx = null;
     TopicConnection connection = null;
  Topic inTopic = null;
  TopicSession subscriptionSession = null;
  TopicSession publishSession = null;
  boolean transacted = false;

        //Corba connection settings
  Properties p = new Properties();
     p.put(Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory");
  p.put(Context.PROVIDER_URL, "corbaloc:iiop:127.0.0.1:2812");
  p.put("com.ibm.CORBA.ORBInit", "com.ibm.ws.sib.client.ORB");

  try {
   ctx = new InitialContext(p);

   if (null != ctx)
    System.out.println("Got naming context");
   
            //Get the connection factory
   TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) ctx
     .lookup("jms/testTCF");
   
            //Get the actual topic
   inTopic = (Topic) ctx.lookup("jms/testTopic");
   //Create and start a Connection
   connection = topicConnectionFactory.createTopicConnection();
   connection.start(); 
   
   //Subscribe to a Topic
   subscriptionSession = connection.createTopicSession(transacted,
     Session.AUTO_ACKNOWLEDGE);
   TopicSubscriber topicSubscriber = subscriptionSession.createSubscriber(inTopic);
   
            topicSubscriber.setMessageListener(new TopicTestListener());
   System.out.println("message listener is set");
   
   //Publish a test message to topic
   publishSession = connection.createTopicSession(transacted,
     Session.AUTO_ACKNOWLEDGE);
   TopicPublisher publisher = publishSession.createPublisher(inTopic);
            //Send dummy message   
   DateFormat dateFormat = new SimpleDateFormat(
     "yyyy/MM/dd HH:mm:ss");
   Date date = new Date();

   TextMessage outMessage = publishSession.createTextMessage("My First JMS Message "
       + dateFormat.format(date));
   publisher.publish(outMessage);
      

  } catch (NamingException e) {
   e.printStackTrace();
  } catch (JMSException e) {
   e.printStackTrace();
  }

 }
 
 public static class TopicTestListener implements MessageListener {
  public void onMessage(Message msg) {
   //onMessage = topic message received
   try {
    String msgText;
    if (msg instanceof TextMessage) {
     msgText = ((TextMessage) msg).getText();
    } else { // If it is not a TextMessage...
     msgText = msg.toString();
    }
                //print out message
    System.out.println("Message Received: " + msgText);

   } catch (JMSException jmse) {
    jmse.printStackTrace();
   }