Home > GlassFish, Grizzly > Writing a Comet web application using GlassFish

Writing a Comet web application using GlassFish

This blog describes how to write Comet enabled web application using GlassFish’s Comet Engine.

A couple of months ago, I’ve blogged about the technical details of the GlassFish‘s Comet support. Since then, I’ve got a lot of feedbacks on the blog and also privately. Surprisingly, a lot of peoples have started using the API and an asked for a blog describing a basic example. So here it comes … a basic Chat Servlet :-)

werixc.jpg

First, to enable Comet Support in GlassFish, add the following in ${glassfish.home}/domains/domain1/config/domain.xml


        <http-listener acceptor-threads="1" address="0.0.0.0" 
           blocking-enabled="false" default-virtual-server="server"
           enabled="true" family="inet" id="http-listener-1" port="8080"
           security-enabled="false" server-name="" xpowered-by="true">
                <property name="cometSupport" value="true"/>
        </http-listener>

Next, add in you web.xml:


        <load-on-startup>0</load-on-startup>

OK now the interesting parts. The first things to decide when writing a Comet enabled web app is the component that will get polled. For this example, I will use a Servlet. First, the Servlet needs to register to the CometEngine:


   48     public void init(ServletConfig config) throws ServletException {
   49         super.init(config);
   50         contextPath = config.getServletContext().getContextPath() + "/chat";
   51         CometEngine cometEngine = CometEngine.getEngine();
   52         CometContext context = cometEngine.register(contextPath);
   53         context.setExpirationDelay(60 * 1000);
   54     }

The important part to define first is the context path that will be considered for Comet processing (or polling). All requests that takes the form of http://:/context/chat will be considered for polling. The context.setExpirationDelay() will determine how long a request will be polled. For this example, I’ve set the expiration delay to 60 seconds. After 60 seconds, the polled connection will be closed.

Next, you need to define a Comet request Handler which will get invoked every time the CometContext is updated. For the Chat, the handler will be created after the user has entered its user name (by issuing http://…/login.jsp)


   71                 if ("login".equals(action)) {
   72                     String username = request.getParameter("username");
   73                     request.getSession(true).setAttribute("username", username);
   74
   75                     if (firstServlet != -1){
   76                          cometContext.notify("User " + username
   77                           + " from " + request.getRemoteAddr()
   78                           + " is joinning the chat.",CometEvent.NOTIFY,
   79                                  firstServlet);
   80                     }
   81
   82                     response.sendRedirect("chat.jsp");
   83                     return;
   84                 } else if ("post".equals(action)){
   85                     String username = (String) request.getSession(true)
   86                         .getAttribute("username");
   87                     String message = request.getParameter("message");
   88                     cometContext.notify("[ " + username + " ]  "
   89                             + message + "<br/>");
   90                     response.sendRedirect("post.jsp");
   91                     return;
   92                 } else if ("openchat".equals(action)) {
   93                     response.setContentType("text/html");
   94                     CometRequestHandler handler = new CometRequestHandler();
   95                     handler.clientIP = request.getRemoteAddr();
   96                     handler.attach(response.getWriter());
   97                     cometContext.addCometHandler(handler);
   98                     String username = (String) request.getSession(true)
   99                         .getAttribute("username");
  100                     response.getWriter().println("<h2>Welcome "
  101                             + username + " </h2>");
  102                     return;

After the user has logged in, the browser will be redirected to the chat.jsp page, which will sent the action=”openchat”. The CometHandler (the class that will update the chat message box) implementation looks like:


  134         public void onEvent(CometEvent event) throws IOException{
  135             try{
  136
  137                 if (firstServlet != -1 && this.hashCode() != firstServlet){
  138                      event.getCometContext().notify("User " + clientIP
  139                       + " is getting a new message.",CometEvent.NOTIFY,
  140                              firstServlet);
  141                 }
  142                 if ( event.getType() != CometEvent.READ ){
  143                     printWriter.println(event.attachment());
  144                     printWriter.flush();
  145                 }
  146             } catch (Throwable t){
  147                t.printStackTrace();
  148             }
  149         }
  150
  151
  152         public void onInitialize(CometEvent event) throws IOException{
                      ....
  156         }

Every time the user will post a new message, the CometHandler.onEvent(…) will be invoked and the Chat message pushed back to the browser.

On the client side, the chat.jsp page looks like


     26 <frameset>
     27   <iframe name="chat" src ="/comet/chat?action=openchat" width="100%" scrolling="auto"></iframe>
     28   <iframe name="post" src="post.jsp" width="100%" scrolling="no"/>
     29 </frameset>

You can download the application (which include the src) here.

Note that the application described here is really to give an example. I would never recommend the use of static variables like I did in the example.

werixc96.jpg

Before I forgot, one interesting feature I’ve recently added (was requested on first blog on Grizzly’s Comet) is the ability to update a single CometHandler (or a single polled request). When calling cometContext.addCometHandler(..), the returned value can be later re-used to push datas only to that cometHandler by doing:


     cometContext.notify(String message, int type, String cometListenerID);

See the API for more info. For the Chat example, I’ve added a pop up window where a chat moderator receives all the chat messages, who is connected and from where:


    138   event.getCometContext().notify("User " + clientIP
    139      + " is getting a new message.",CometEvent.NOTIFY,
    140        firstServlet);

That’s it. Very simple, is it? No needs to spawn a thread anywhere on the Servlet side, no special Servlet operations, etc.

Once I’ve a chance, I will try to use AJAX and improve the client. Any help is appreciated on that side :-) As usual, thanks for all the feedbacks sent by emails!

_uacct = “UA-3111670-1″;
urchinTracker();

technorati:

About these ads
Categories: GlassFish, Grizzly
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 50 other followers

%d bloggers like this: