Oracle GlassFish Server 3.0.1 Application Development Guide

Developing the Web Component

This section shows you how to create a Comet-enabled web component by giving you instructions for creating the servlet in the Hidden Frame example.

Developing the web component involves performing the following steps:

  1. Create a web component to support Comet requests.

  2. Register the component with the Comet engine.

  3. Define a Comet handler that sends updates to the client.

  4. Add the Comet handler to the Comet context.

  5. Notify the Comet handler of an event using the Comet context.

ProcedureTo Create a Web Component to Support Comet

  1. Create an empty servlet class, like the following:

    import javax.servlet.*;
    
    public class HiddenCometServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    private String contextPath = null;
    	@Override
    	public void init(ServletConfig config) throws ServletException {}
    
    	@Override
    	protected void doGet(HttpServletRequest req, 
    	HttpServletResponse res) 
    	throws ServletException, IOException {}
    
    	@Override
    	protected void doPost(HttpServletRequest req, 
    	HttpServletResponse res)
    	throws ServletException, IOException {);
    }
  2. Import the following Comet packages into the servlet class:

    import com.sun.grizzly.comet.CometContext;
    import com.sun.grizzly.comet.CometEngine;
    import com.sun.grizzly.comet.CometEvent;
    import com.sun.grizzly.comet.CometHandler;
  3. Import these additional classes that you need for incrementing a counter and writing output to the clients:

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.concurrent.atomic.AtomicInteger;
  4. Add a private variable for the counter:

    private final AtomicInteger counter = new AtomicInteger();

ProcedureTo Register the Servlet With the Comet Engine

  1. In the servlet's init method, add the following code to get the component's context path:

    ServletContext context = config.getServletContext();
    contextPath = context.getContextPath() + "/hidden_comet";
  2. Get an instance of the Comet engine by adding this line after the lines from Step 1:

     CometEngine engine = CometEngine.getEngine();
  3. Register the component with the Comet engine by adding the following lines after those from Step 2:

    CometContext cometContext = engine.register(contextPath);
    cometContext.setExpirationDelay(30 * 1000);

ProcedureTo Define a Comet Handler to Send Updates to the Client

  1. Create a private class that implements CometHandler and add it to the servlet class:

    private class CounterHandler 
    	implements CometHandler<HttpServletResponse> {
    	private HttpServletResponse response;
    }
  2. Add the following methods to the class:

    public void onInitialize(CometEvent event) 
    	throws IOException {}
    
    	public void onInterrupt(CometEvent event) 
    		throws IOException {
    		removeThisFromContext();
    	}
    	
    	public void onTerminate(CometEvent event) 
    		throws IOException {
    		removeThisFromContext();
    	}
    
    	public void attach(HttpServletResponse attachment) {
                this.response = attachment;
    	}
    
    	private void removeThisFromContext() throws IOException {
    		response.getWriter().close();
    		CometContext context = 
    			CometEngine.getEngine().getCometContext(contextPath);
    		context.removeCometHandler(this);
    	}

    You need to provide implementations of these methods when implementing CometHandler. The onInterrupt and onTerminate methods execute when certain changes occur in the status of the underlying TCP communication. The onInterrupt method executes when communication is resumed. The onTerminate method executes when communication is closed. Both methods call removeThisFromContext, which removes the CometHandler object from the CometContext object.

ProcedureTo Add the Comet Handler to the Comet Context

  1. Get an instance of the Comet handler and attach the response to it by adding the following lines to the doGet method:

    CounterHandler handler = new CounterHandler();
    handler.attach(res);
  2. Get the Comet context by adding the following lines to doGet:

    CometEngine engine = CometEngine.getEngine();
    CometContext context = engine.getCometContext(contextPath);
  3. Add the Comet handler to the Comet context by adding this line to doGet:

    context.addCometHandler(handler);

ProcedureTo Notify the Comet Handler of an Event

  1. Add an onEvent method to the CometHandler implementation class to define what happens when an event occurs:

    public void onEvent(CometEvent event) 
    	throws IOException {
    	if (CometEvent.NOTIFY == event.getType()) {
    		int count = counter.get();
    		PrintWriter writer = response.getWriter();
    		writer.write("<script type='text/javascript'>" + 
    			"parent.counter.updateCount('" + count + "')" +
    			"</script>\n");
    		writer.flush();
    		event.getCometContext().resumeCometHandler(this);
    	}
    }

    This method first checks if the event type is NOTIFY, which means that the web component is notifying the CometHandler object that a client has incremented the count. If the event type is NOTIFY, the onEvent method gets the updated count, and writes out JavaScript to the client. The JavaScript includes a call to the updateCount() function, which will update the count on the clients' pages.

    The last line resumes the Comet request and removes it from the list of active CometHandler objects. By this line, you can tell that this application uses the long-polling technique. If you were to delete this line, the application would use the HTTP-Streaming technique.

    • For HTTP-Streaming:

      Add the same code as for long-polling, except do not include the following line:

      event.getCometContext().resumeCometHandler(this);

    You don't include this line because you do not want to resume the request. Instead, you want the connection to remain open.

  2. Increment the counter and forward the response by adding the following lines to the doPost method:

    counter.incrementAndGet();
    CometEngine engine = CometEngine.getEngine();
    CometContext<?> context = 
    	engine.getCometContext(contextPath);
    context.notify(null);
    req.getRequestDispatcher("count.html").forward(req, res);

    When a user clicks the button, the doPost method is called. The doPost method increments the counter. It then obtains the current CometContext object and calls its notify method. By calling context.notify, the doPost method triggers the onEvent method you created in the previous step. After onEvent executes, doPost forwards the response to the clients.