Tutorials‎ > ‎

Simple JMS ToDo Application


In this tutorial, we will build a todo application using Java Messaging Service. This todo application has two users involved. The first user will asign a task to be done to a team, and the second user is a member of team who can view their task.

Java messaging Service or JMS is a method of communication between java application component that is loosly coupled. It means applications which communicate with each other don't need to know the existence of each other. What they need to know is the message format, and the destination name. With this loosly coupled communication, we can have better scalability and maintainability.

JMS has two messaging model,which are Point-To-Point (P2P) model and Publish/Subcribe (Pub/Sub) model. In P2P, each message can only be consumed by one receiver. In Pub/Sub one message can be published to one topic, and the subscriber who make a subscription to that topic can see the new incoming message. In other word Pub/Sub model suppport one message to be consumed by many receivers. Our tutorial example will use a Pub/Sub model messaging.

Technology used in this tutorial:

Setting up Administered Object

First we must create the administered objects. These are objects that will describe the model of connection and messaging destination type. These administered object is configured administratively, rather than programmatically, which are:

  • Connection factory – an object used to create a connection to JMS

  • JMS Destination – a target destination that client specify to send/recieve the message

Below are the steps to create the administered objects.

  1. Start the glassfish server

    1. Open up command prompt

    2. Change current directory to bin folder in glassfish directory. (or add the glassfish bin folder to your environment path)

    3. Type: asadmin start-domain

  2. Create a Topic (JMS Destination)

    1. Open http://localhost:4848 in your browser

    2. Click “JmsResource” > “Destination Resource” that is located in the Common Task (Left panel)

    3. Click “New” Button

    4. Filled up the form:
      JNDI Name: jms/TodoTopic
      Physical Destination Name: TodoTopic

  3. Edit default connection factory:

    1. Open http://localhost:4848

    2. Click “JmsResource” > “Connection Factories”

    3. Click the existing connection factory: “jms/__defaultConnectionFactory”

    4. In additional properties, Click “Add Property” button

    5. Specify the following field:
      Name : Client Id
      Value : myId

    6. Click “Save” button

In the second step, we create a new destination type, Topic which is a Pub/Sub messaging model in JMS. We specify the JNDI or Java Naming Directory Interface which is the logical directory where we place the destination resource. And the physical destination name which is the physical name of the resource.

In the third step, we add a client Id property for a connection factory. This is a requirement setting to enable a Pub/Sub communication. The value can be anything.


Code the web

  1. Create a new java web application project

    1. File > New Project

    2. Choose Java Enterprise on the left panel.

    3. Check Web application

    4. Choose Glassfish4 as the application Server
      If you haven’t add glassfish as your application server

      1. Download glassfish4 then extract it.

      2. Click “New” button In the previous pop up dialog

      3. Choose Glassfish Server

      4. Specify the glassfish folder where you extract

      5. Click Ok

    5. Click Next

    6. Rename the project to TodoWeb

    7. Click Finish

  2. Setup project library

    1. Hold Ctrl + Alt + Shift + S to open project setting

    2. In the module setting, click tab dependency

    3. Click Plus icon > “JARs or directories” to add new dependency

    4. Choose javax.jms-api.jar that is located at [your glassfish directory]/glassfish/modules folder

  3. Create a new servlet.

    1. Right Click on src folder > New > Servlet

    2. Fill the following fiield:
      Name: TodoServlet
      Package: servlet
      Class: TodoServlet

    3. Click Ok

  4. Create a new jsp file as the view

    1. Right click on WEB-INF folder inside web folder

    2. New > JSP/JSPX

    3. Name it todo.jsp

  5. Write the following code in TodoServlet.java

package servlet;

import javax.annotation.Resource;
import
javax.jms.ConnectionFactory;
import
javax.jms.JMSContext;
import
javax.jms.TextMessage;
import
javax.jms.Topic;
import
javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.io.IOException;

@WebServlet(name = "TodoServlet", urlPatterns = "/")

public class TodoServlet extends HttpServlet {

    @Resource(lookup = "jms/__defaultConnectionFactory")
    private
ConnectionFactory connectionFactory;

    @Resource(lookup = "jms/TodoTopic")
    private
Topic topic;

        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
String title
= request.getParameter("title");
        
String description = request.getParameter("description");

            try(JMSContext context = connectionFactory.createContext();) {
            TextMessage msg
= context.createTextMessage(title + "|" + description);
            context
.createProducer().send(topic, msg);
        }

    }

     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.getRequestDispatcher("/WEB-INF/todo.jsp").forward(request, response);
    }

}

@WebServlet is an annotation that will indicate that this class has been mapped to a servlet named “TodoServlet”. It also state that this class will be accessed when it hit “/” url from it's application web context.

@Resource is an annotation that will tell the application server container to inject a resource given it's resource JNDI name. In this case we inject the connection factory and topic that we have created before.

DoPost method is a method that will be accessed whenever there is a HTTP POST method acccessing the “/” url. The code is pretty straight forward, first it retrieve the request body parameter – titile and description. Then connection factory create a JMSContext using ConnectionFactory.createContext method. JMS context is an object that will managed a connection and it's session to JMS. The session in jms context is used to create a message, producer and consumer of JMS message.

To create a simple text message, we can use JMSContext.createTextMessage method. This message consist of title and description of a new todo task, that is seperatedby '|' symbol. So later, when consumers retrieve a new message, they must split the message by '|' delimiter symbol.

The last thing is we ceate a producer using JMSContext.createProducer method, then using the procuder we send a message to a topic destination.

DoGet method is a metod that will be accessed whenever there is a HTTP GET method accessing the “/” url. This method will forward the user request to “/WEB-INF/todo.jsp” file.

        6. Write the following code in todo.jsp

This html is used to passed the user input into the servlet that we have made before.

<form action="" method="post">
    <h1>Input New Todo</h1>     <table cellspacing="10px">         <tr>             <td>Title</td>             <td>:</td>             <td><input name="title"/></td>         </tr>         <tr>
            <td>Description</td>             <td>:</td>             <td><textarea name="description" id="" cols="30" rows="10"></textarea></td>         </tr>     <tr>      <td colspan="2"></td>    <td><button>+ Add New Task</button></td>    </tr> </table>
</form>

Code the console application

To create a simple console application, follow these steps:

  1. Creata a new Java Project

        a. File > New Project > Next > Next
        b. Named the project “TodoConsole”
        c. Click Finish

  1. Create a new main class

        a. Right click on src folder > New > Class
        b. Named it “main”

  1. Write the following code

import javax.jms.*;
import javax.naming.Context;
import
javax.naming.InitialContext;
import
javax.naming.NamingException;
import
java.util.Properties;
public class Application {
    
private static MessageListener listener = new MessageListener() {
        @Override
        
public void onMessage(Message message) {
            String[] arr
;
            try
{
                arr = ((TextMessage)message).getText().split("\\|");
                String title = arr[
0];
                String description = arr[1];                 System.out.println("New Message\n" +                                    "===========\n" +
                                   "Title: "
+ title + "\n"+
                                  "Description:"
+ description);
            
} catch (JMSException e) {
                e.printStackTrace()
;
            
}

        }

    }


    private static
Context prepareContext() throws NamingException {

        
Properties properties =
new Properties();

        properties.setProperty(Context.
INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");

        properties.setProperty(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
        properties.setProperty(Context.PROVIDER_URL, "iiop://localhost:3700");

        return new InitialContext(properties);

    }

    public static void main(String[] args) throws NamingException {

        
Context jndiContext =
prepareContext();

        ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/__defaultConnectionFactory");

        Topic topic = (Topic) jndiContext.lookup("jms/TodoTopic");
              try (JMSContext context = connectionFactory.createContext()) {
            
context.setClientID("myId");
            
context.stop();
            
context.createDurableConsumer(topic, "Todo").setMessageListener(listener);
            context.start();

            System.in.read();
        } catch (Exception e) {             e.printStackTrace();   }     }
}
;

A listener is an object of MessageListener that will listen to every new message that come to a topic, that we specified later. This MessageListener interface has one method contract that is onMessage which receive a Message object as it's argument. Message is a base class that will be inherited to be TextMessage, a class that it's message body is string. We will use this instance to get the message by typecast it to TextMessage then use getText method. Because we have a message in format like [title]#[message body], we will split the message by '#' character then will display the message.

Next, prepareContext method, a method that will connect to jndi resource given the server host. After we already setting up the connection to glassfish server, now we find the jdni resource, using Context.lookup method. There will be two resource that we need, connectionFactory and topic (jms destination). Using the connectionFactory we will create a jms context, an object to create a jms connection and it's session. Then we create a durable consumer given a jms destination and it's topic name. After we have create the consumer, we set it's message listener to listener object that we have created before. After that we want to hold the proses, so our program doesn't terminated immediately. Using System.in.read() will read one input character and hold the process until we input enter character.

I know this simple tutorial takes a lot of configuration, and may be this simple tutorial can be implemented with another way. But if you think about this concept a second, you can start making your application to communicate each another, and make an automation of it. I hope you learn something from this tutorial.