Brief overview of JSR 343: JavaTM Message Service 2.0

Well, as many of us already know Oracle submitted the JSR for Java EE 7 which is sort of an umbrella JSR for many update in already existing specifications, new versions of some JSRs and some completely new JSRs which will be part of the grand Java EE 7 – JSR 342.

One of these JSRs is the JSR 343 which introduces a new version of JMS into the platform as an evolution of its previous version, JSR-914, and will unify the JMS usage with what added to the platform in the past 8 years.

The following represent some very simple usecases of JMS in the enterprise while complex multiphase transactional usecases are not unusual when MDBs and XA data sources are involved.

  • JMS itself is for asynchronous communication and widely used to communicate some execution instructions from one node or point to another or a set of other points. For example long running queries can be queued using a JMS queue to get processed by another point in the system while the query client is not blocked for the query result.
  • Or it can be used to communicate a common set of instructions to many interested parties which may or may not be around the communication happens, durable subscriptions and persisted topics. For example when clients need to get an ordered set of update messages to update a localcache when they get online after some times. Each client will get its own copy of messages it should receive when getting online.

JMS API provides enough functionalities to realize most of our design out of the specification and the minor features and functionalities not included in the JSR while required by some designs are covered by the vendor specific pack of enhancement and tweaks provided in the broker level and through the vendor specific API.

You may ask if the current JMS API provides all we need, why a new JSR should be put on the table, the answer mainly relies on the theme for Java EE 7 which is making Java EE more cloud friendly and sort of cloud enabled by nature rather than by product.

The details of JMS 2.0 spec goals are listed at the JSR homepage but a brief list can be seen as follow:

  • Community requested features and enhancements.
  • Make the JSR more cloud friendly based on how Java EE 7 will define “to be cloud friendly”
  • Cleanup of some ambiguity in the relation of JMS with other Java EE specs.
  • Make the API easier to use, more annotations and more generics will be involved for the least of the things or maybe reducing number of boxes and lines in the aove figure  could help many to start with the API faster.
  • Make necessary changes to benefit from the JSR-299 or Contexts and Dependency Injection to easier and more unified use of API.

In the follow up posts I will iterate over each one of these bullet points in more details.

I am member of the JMS 2.0 expert group but this post or any other post in my personal blog does not reflect the expert group opinion or the opinion of my employer on the subject unless you could not see this paragraph at the end of the post :-).

 

JMS Over HTTP using OpenMQ (Sun Java System Message Queue and HTTP tunneling)

You may have already faced situation when you need to have messaging capabilities in your application while your client application runs in an environment which you have no control over its network configuration and restrictions. Such situation lead to the fact that you can not use JMS communication over designated ports like 7676 and so.

You may simply put JMS away and follow another protocol or even plain HTTP communication to address your architecture and design requirement, but we can not easily put pure JMS API capabilities away as we may need durable subscription over a proven and already well tested and established design and architecture. Different JMS implementation providers provide different type capabilities to address such a requirement. ActiveMQ provide HTTP and HTTPS transport for JMS API and described it here.

OpenMQ provide different transport protocol and access channels to access OpenMQ functionalities from different prgramming . One of the access channles which involve HTTP is named Universal Message Service (UMS) which provide a simple REST interaction template to place messages and comsume them from any programming language and device which can interact with a network server. UMS has some limitations which is simply understandable based on the RESTful nature of UMS. For current version of OpenMQ, it only supports Message Queues as destinations so there is no publish-subscribe functionality available.

Another capability which involve HTTP is JMS over HTTP or simply JMS HTTP tunneling. OpenMQ JMS implementation supports HTTP/s as transport protocol if we configure the message broker properly. Well I said the JMS implementation support HTTP/S as a transport protocol which means we as user of the JMS API see almost no difference in the way that we use the JMS API. We can use publish-subscribe, point to point, durable subscription, transaction and whatever provided in the JMS API.

First, lets overview the OpenMQ installation and configuration then we will take a look at an example to see what changes between using JMS API and JMS API over HTTP transport. Installation process is as follow:

OpenMQ project provides a Java EE web application which interact with OpenMQ broker from one side and Sun JMS implementation on the other side. Interaction of this application with the client and MQ broker is highly customizable in different aspects like Broker port number, client poll inrval, Broker address and so on.

  • Download OpenMQ from https://mq.dev.java.net/ it should be a zip which is different for each platform.
  • Install the MQ by unzipping the above file and running ./installer or installer.bat or so.
  • After the installation completed, go to install_folder/var/mq/instances/imqbroker/props and open the config.properties in a text editor like notepad or emeditor or gedit.
  • Add the following line to the end of the above file:
  •  imq.service.activelist=jms,admin,httpjms 
  • Now goto install_folder/mq/lib/ and pick the imqhttp.war file. deploy the file into your Servlet container or application server (I went with GlassFish). After you deployed the file start the application server or Servlet container
  • Now it is time to start the MQ broker: launch a terminal or cmd console and goto install_folder/mq/bin now execute ./imqbrokerd -port 7979 (it maybe like imqbrokerd.bat -port 7979 for Windows ) This command will start the MQ broker and keep it listening on port 7979 for incoming connection
  • To test the overall operations: Open a browser and tray to surf http://127.0.0.1:8080/imqhttp/tunnel or whatever URL which points to the newly deployed application . If you saw "HTTP tunneling Servlet ready." as the first line in the response page then we are ready for last step.

Now let’s see how we can publish some messages, this sample code assume that we have configured the message broker and assumes that we have the following two JAR files in the classpath. These JAR files are available in install_folder/mq/lib/ 

  1. imq.jar
  2. jms.jar

Now the Publisher code:

 public class Publisher {      public void publish(String messageContent) {         try {             String addressList = "http://127.0.0.1:8080/imqhttp/tunnel";             com.sun.messaging.TopicConnectionFactory topicConnectionFactory = new com.sun.messaging.TopicConnectionFactory();             topicConnectionFactory.setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList, addressList);             javax.jms.Topic top;             javax.jms.Connection con = topicConnectionFactory.createTopicConnection("admin", "admin");              javax.jms.Session session = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);             top = session.createTopic("DIRECT_TOPIC");             MessageProducer prod = session.createProducer(top);             Message textMessage = session.createTextMessage(messageContent);             prod.send(textMessage);          prod.close();         session.close();         con.close();                  } catch (JMSException ex) {             ex.printStackTrace();         }      }      public static void main(String args[]) {          Publisher p = new Publisher();         for (int i = 1; i < 10; i++) {             p.publish("Sample Text Message Content: " + i);         }     } } 

As you can see the only difference is the connection URL which uses http instead of mq and point to a Servlet container address instead of pointing to the Broker listening address.

The subscriber sample code follow a similar pattern. Here I write a sample durable subscriber so you can see that we can use durable subscribtion over HTTP. But you should note that HTTP transport uses polling and continuesly open communication channel which can introduce some overload on the server.

 class SimpleListener implements MessageListener {      public void onMessage(Message msg) {         System.out.println("On Message Called");         if (msg instanceof TextMessage) {             try {                 System.out.print(((TextMessage) msg).getText());             } catch (JMSException ex) {                 ex.printStackTrace();             }          }     } }  public class Subscriber {      /**      * @param args the command line arguments      */     public void subscribe(String clientID, String susbscritpionID) {         try {             // TODO code application logic here              String addressList = "http://127.0.0.1:8080/imqhttp/tunnel";             com.sun.messaging.TopicConnectionFactory topicConnectionFactory = new com.sun.messaging.TopicConnectionFactory();             topicConnectionFactory.setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList, addressList);             javax.jms.Topic top;             javax.jms.Connection con = topicConnectionFactory.createTopicConnection("admin", "admin");             con.setClientID(clientID);             javax.jms.Session session = con.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);             top = session.createTopic("DIRECT_TOPIC");             TopicSubscriber topicSubscriber = session.createDurableSubscriber(top, susbscritpionID);             topicSubscriber.setMessageListener(new SimpleListener());              con.start();           } catch (JMSException ex) {             ex.printStackTrace();         }     }      public static void main(String args[]) {          Subscriber sub = new Subscriber();         sub.subscribe("C19", "C1_011");     } } 

Now how you can test the entire example and monitor the MQ? it is very simple by utilizing the provided tools.

Do the following steps to test the overall durable subscription system:

  • Run a subscriber
  • Run another subscriber with a different client ID
  • Run a publisher once or twice
  • Kill the second subscriber
  • Run a publisher once
  • Run the subscriber and you can see that the subscriber will fetch all messages which arrived after it shut down-ed.

Note that we can not have two separate client with same client ID running because the broker will not be able to distinguish which client it should send the messages.

  • You can monitor the queue and the broker using: ./imqadmin which can be found in install_folder/mq/bin this software shows how many durable subscribers are around and how many messages are pending for each subscriber and so on.
  • You can monitor the Queue in real-time mode using the following command which can be executed in install_folder/mq/bin

./imqcmd -b 127.0.0.1:7979 metrics dst -t t -n DIRECT_TOPIC The command will ask for username and password, give admin/admin for it

The sample code for this entry can be found Here. The sample code is a NetBeans project with the publisher and the subscriber source code.

A complete documentation of OpenMQ is available at its documentation centre. You can see how you can change different port numbers or configure different properties of the Broker and HTTP tunneling web application communication.

 

Step by Step toward a jms sample in NetBeans and yes GlassFish. part 2 : Remote Client

In previous part you saw that how easy is to make an MDB to consume messages and a jsp/Servlet Front End to send message to a queue.
in this part i will show you how you can send message to a queue from a remote j2se client. you should know that in jms sending and reciving mesages has similar steps , some small changes require to consume message from a j2se client instead of sending messages.
to make it more clear , the main purpose of an MDB is to consume messages as they arrive , The MDB onMessage(..) is called whenever a message become available in destination that MDB is binded to it.

sure we can do what ever we want after message recieved. for example you can send the message that you recive from a queue to several topics , you can process it to do some database operation…. usually we use JMS for executing Asynchronous operations ,bringing more decoupling of a system components….

but lets come to our own steps to create a simple remote client that will sends some messages to tQueue that we made in first part of this series. then we will see that our messages are reciveing by TMDB. As you know we used a context object to locate the Queue and ConnectionFactory . the servlet code was like:

...
  Context ctx = new InitialContext();
...

By default a JNDI client assume that it is in a correctly configured environment , so when we do not pass a HatshTable to IinitialContext , the InitialContextFactory will return a context configured with that environment .In server environment we do not need to explicity pass parameters to InitialContext unless we need to initiate a context for another environment.
But, what are this parameters and how we can use them to initiate a context for none default environemtn or in places that there is no default environemt pre-configured , situation like standalone remote clients?
in a such situation we should configure the InitialContext using a HashTable that contain some parameters, There are several parameter that can be used to configure the initialContext but Two most important ones are :

  • provider url , for glassfish in iiop format it is : iiop://127.0.0.1:3700 We can use a key like Context.PROVIDER_URL to put its value into hashtable , also we may use java.naming.provider.url String to put value of this parameter into HashTable . this parameter is vendor dependent.
  • initial context factory , for glassfish it is : com.sun.appserv.naming.S1ASCtxFactory This is another important parameter that we must set before we can access a JNDI Tree , indeed it is totaly vendor dependent because each vendor has its own implementation for its JNDI access. This factory will create the context object along with the url that you put into the hashtable. we may use Context.INITIAL_CONTEXT_FACTORY or "java.naming.factory.initial" string as a key to put this value into the hashtable

As i said there are some other parameters that you can set , like security parameters for authentication and …. but those are not necessary.
I should tell that we can also make this parameter to be the jvm default parameter and allows the Initialcontext to return a context without need to pass any arguments. in this way we need to pass parameters to java command when we want to start it. for example you can use :
java -Djava.naming.provider.url="iiop://127.0.0.1:3700" -Djava.naming.factory.initial="com.sun.appserv.naming.S1ASCtxFactory" to start our application. this way you allows the Initialcontext to return a context without need to configure it by a HashTable. For our Sample we will use a hashtable to configure the InitialContext , but you can try to pass parameters to java instead and observ the execution of your application.
To create a j2se remote client we need to add some jar files to our project , NetBeans provide its own way to manage jar files that may be used in more than one project. it is Libraries….
Run NetBeans, From Tools menu select Library Manager , create a new library and name it jms . Now you can add as much jar files to this library as you need , then it will be reuseable for your other projects.
add following jar files to this library , I use glassfish_home as installation directory of glassfish.

  • glassfish_home/lib/appserv-rt.jar
  • glassfish_home/lib/javaee.jar
  • glassfish_home/lib/install/applications/jmsra/jmsra.jar
  • glassfish_home/lib/install/applications/jmsra/imqbroker.jar
  • glassfish_home/imq/lib/imq.jar
  • glassfish_home/lib/appserv-admin.jar
  • glassfish_home/imq/lib/jms.jar

Create a j2se project using , File > new project > general > java application. name the application jmsClient and allow the IDE to create a Main class for you.
You shoud add that library that you create to this project. to do this , expand the project node , right click on the libraries and select add library Now from the library list select jms .
Up to now you have done 30% of creating an stand alone remote client to interact with your jms resources like connectionFactories and destinations.
Now we need to code the main method of main class . expand the jmsClient node , expand the source packages and finally open the main class of your project.
The overall look of your code shoul be like the following :

public class JmsClient {
    Context ctx;
    public JmsClient() {
        Hashtable properties = new Hashtable(2);
        properties.put(Context.PROVIDER_URL,"iiop://127.0.0.1:3700");
        properties.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.appserv.naming.S1ASCtxFactory");
        try {
            ctx = new InitialContext(properties);
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }
   public Object lookup(String name){
        try {
            return ctx.lookup(name);
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        JmsClient client = new JmsClient();
        try{
            ConnectionFactory     connectionFactory = (ConnectionFactory)client.lookup("jms/tConnectionFactory");
            Queue     queue = (Queue)client.lookup("jms/tQueue");
            javax.jms.Connection  connection = connectionFactory.createConnection();
            javax.jms.Session        session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(queue);
            for(int i=0;i<5;i++) {
                TextMessage message = session.createTextMessage("It is a message from main class "+  ": "+ i);
                System.out.println( "It come from main class:"+ message.getText());
                messageProducer.send(message);
            }
        } catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

Now lets see what the above code means , i will not go indepth because JMS APIs are discussed too much 🙂 .
In constructor we configured a context object named ctx
we encapsulate the lookpu task in a method named lookup(…) we usually use a service locator or cached service locator to locate our objects in JNDI because JNDI lokups are time consumer
In main method:

  • we create a ConnectionFactory by looking it up in the jndi by using our context and dummy lookup(…) method.
  • we create a Queue by looking it up in the jndi by using our context and dummy lookup(…) method.
  • Then we create a connection using that ConnectionFactory
  • we obtain a Session (jms Session) using our connection
  • we made the messageproducer which is our tools to send message to that Queue ,
  • in a loop we create and sent 5 text message to the queue.

Now lets run the program and see the result , to run the application you nedd to complete the first part of this series , then you should run the application server , and if you like to have a demonestration like what i will show you , you should deploy the application that we made in first part.
i assume you have completed first part and you have the application server running , Now run the client that we made and what you will see in output window should be like :

and if you take a look at application server log file (in runtime tab , expand the servers node and rigt click on the glassfish instance , now select view server log..) what you should see in the server log should be something like :

messages that we send via standalone client will reach the queue that the MDB is listening on it , as soon as we send a message MDB will pick it up and start processing it.
you can download the standalone client project from here

Step by Step toward a jms sample in NetBeans and yes GlassFish

Java EE 5 brings many ease of use in EJB development world and certainly it is one of biggest step ahead in java EE land.
NetBeans 5.5 is another big step toward making development on top Java EE some easier. NetBeans is a very easy to learn and use because it does not bring many stuff on the screen to "Occupy all the space" instead it provide maximum useability by means of limited number of views.
GlassFish as Reference implementation of JAVA EE 5 , provide you with all service that are named in java EE spec but it is not similar to older RI version of J2EE ,just remember J2EE 1.3 RI
it is much more better in term of functionality, performance, ease of use and …
here I will tell you steps that you need to follow to build a simple MDB , a web based message producer and a remote message producer.

when you follow this entry you will be able to deal with basic aspect of JMS in Action and not only on your papers. but what do we need to have our JMS application running ?

  • A JMS implementation that is configured with our server , it can be done using embedded servers that are shipped with application servers or using remote / local MQ servers.
    GlassFish uses Sun message Queue , which is going to be available under the same license that GlassFish is provided. You can find more information about open source version at : http://mq.dev.java.net
  • You also need to setup a Queue and a connection factory in your application server.*
  • you should Create an MDB , and then implement the onMessage() method in way that you like.

*I should tell you that you can create your Queue and connection factory in many ways , yes more than two ways .

  • use GlassFish server web based administration console
  • use GlassFish command line console
  • using NetBeans 5.5 , yes NetBeans provide you some wizard thingy to make JMS / JDBC resources from withing NetBeans and then registering them to Application server.

I assume you know NetBeans and you registered GlassFish as an application server in NetBeans server manager
To create Queue and connection follow these steps :

  • Run The IDE and go to runtime tab , expand server node and start the GlassFish instance.
  • right click on GlassFish node and select view admin console
  • login to admin console ,In left side navigation panel , expand the resources and expand JMS resources
  • click on connection factories and from main frame click on new button , fill in the values as following ones
    • JNDI Name: jms/tConnectionFactory
    • Type: javax.jmsConnectionFactory **
    • Description: some description here
    • give it a name like : tConnectionFactory
    • Click OK button

    ** in JMS 1.1 we can use same factory for both publish/subscribe and point-to-point messaging

  • now we need to create a queue to be our messages destination, click on destination resources from main frame click on new and fill in the values as following ones

  • JNDI Name: jms/tQueue
  • Type: javax.JMS.Queue
  • Description: some description here
  • give it a name like : tQueue
  • Click Save button

Now we have our JMS Configuration ready to serve some MDB and remote client. Create a new enterprise application with two kind of modules , one EJB module and one web module , name it whatever you want but I named this sample jms
go to project view , right click on EJB module and select NewMessage-Driven Bean…
a window will open and ask you for some attributes of this MDB fill in the names like :

  • EJB Name : TMDB
  • package : mdbs
  • Mapped Name : jms/tQueue***

click finish and you are done , your MDB skeleton is ready and you just need to implement the onMessage(…) method.
*** This is where our MDB is assigned to , whether it is a topic in publish/subscribe scenario or a queue in point-to-point scenario.
Now change the implementation of your onMessage(…) as following , we also add one private object to our class , make sure that you include it too.

  @Resource
    private MessageDrivenContext mdc;
    public void onMessage(Message message) {

        TextMessage msg = null;
        try {
            if (message instanceof TextMessage) {
                msg = (TextMessage) message;
System.out.println("A Message received in TMDB: " +
                        msg.getText());
            } else {
               System.out.println("Message of wrong type: " +
                        message.getClass().getName());

            }
        } catch (JMSException e) {
            e.printStackTrace();
            mdc.setRollbackOnly();
        } catch (Throwable te) {
            te.printStackTrace();
        }
    }

we just made one more change in class skeleton and that is our MessageDrivenContext variable , we usually use this to call setRollbackOnly(…) when we use an MDB in a transactional scenario for this sample you simpley can ignore it.
Now lets make our web application to send some messages to that Queue and let the MDB fetch and process them.
wxpand web application node , and double click on index.jsp after it opens , change its content like the following , sure you can use component platte to drag and drop items to jsp source file 🙂

<%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>

    </head>
    <body>
<center>
<form action="sendMessage">
            <table  cellspacing="20" >

                <tbody>
                    <tr>
                        <td>Enter some message: </td>
                        <td><input type="text" name="message" value="Enter your message here" width="30" /></td>

                    </tr>
                </tbody>
            </table>

                <input type="submit" value="Send The message" name="send" />

            </center>
        </form>
    </body>
</html>


Now we need to build a servlet , which will send messages to our Queue , for this task you need to do these steps :

  1. Right click on web application node and select New > Servlet…
  2. change its Name to sendMessage give it a package name and click finish
  3. change the processRequest(..) method body as following list
 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //start the jms stuff

        try{
            Context ctx = new InitialContext();
            ConnectionFactory     connectionFactory = (ConnectionFactory)ctx.lookup("jms/tConnectionFactory");
            Queue     queue = (Queue)ctx.lookup("jms/tQueue");
            javax.jms.Connection  connection = connectionFactory.createConnection();
            javax.jms.Session        session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(queue);
            TextMessage message = session.createTextMessage();
            message.setText(request.getParameter("message"));
            System.out.println( "It come from Servlet:"+ message.getText());
            messageProducer.send(message);

//message sent , it was all

            //show what we have done in this servlet
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet sendMessage</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<center>");
            out.print("Servlet Send this message <h2>"+request.getParameter("message") + "</h2>  to this Queue : <h2>"+queue.getQueueName()+"</h2>");
            out.println("</center>");
            out.println("</body>");
            out.println("</html>");

        } catch(Exception ex){
            ex.printStackTrace();
        }

        out.close();
    }

It was all you should do to create a JMS point to point sample.
to view what you have Done , press F6 , if you did all the above as i said you will see a page like :

Now just give it a message and press the button , what you will see should looks like the following image , in case that your praise the NetBeans and GlassFish as i did 😉

and if you look at Application server log file , you will see something similar to : (to view the application server log file go to runtime view , right click on glassfish node and select view log file)

You can download the project from here but make sure that you build the connection factory and queue because project will need them .
In next part i will show you how easily you can make a remote client to deal with your jms destinations.