Friday Dec 04, 2009

An Example of Porting Grizzly Comet to Servlet 3.0

Grizzly Comet is a very powerful feature in GlassFish v2 and GlassFish v3. It provides a framework for writing many interesting applications. However, the same application will not run in other servlet containers (without Grizzly). One can resolve this by porting the code to use asynchronous API in Servlet 3.0 as in the glassfish sample, asyn-request-war, code In this case, the application would be able to run in all Servlet 3.0 containers.

In this blog, I will discuss the former by using Even though, some details are specified to the chat example, the principle is general. There are two main steps:

Mark the servlet as asynchronous

One can achieve this by using one of the following:
  • specifying the asyncSupported in @WebServlet,
    for instance, @WebServlet(urlPatterns = {"/chat"}, asyncSupported = true)
  • adding <async-supported>true</async-supported> under corresponding <servlet> in web.xml

Modify the servlet code

ServletUsing Grizzly CometUsing Asynchronous API in Servlet 3.0
instance variablesString contextPath
  • Thread, notifierThread
  • Queue of AsyncContext, queueBlockingQueue of message, messageQueue

    Queue<AsyncContext> queue = new ConcurrentLinkedQueue<AsynContext>();
    BlockingQueue messageQueue = new LinkedBlockingQueue();

init method
  • register contextPath in CometEngine
  • set expiration time

    contextPath = config.getServletContext().getContextPath() + "/chat";
    CometContext context = CometEngine.getEngine().register(contextPath);
    context.setExpirationDelay(5 \* 60 \* 1000);

create and start a notifierThread to consume message from messageQueue

    Runnable notifierRunnable = new Runnable() {
    public void run() {
        cMessage = messageQueue.take();
        for (AsyncContext ac : queue) {
            try {
                PrintWriter acWriter = ac.getResponse().getWriter();
            } catch(IOException ex) {
    notifierThread = new Thread(notifierRunnable);

doGet method
  • create a CometHandler<PrintWriter>
  • attach the response writer to the CometHandler
  • register contextPath in CometEngine
  • add the CometHandlerto CometContext

    ... // code for ChatListenerHandler is omitted
    ChatListnerHandler handler = new ChatListnerHandler();
    CometContext context = CometEngine.getEngine().register(contextPath);

  • create a AsyncContext
  • set timeout
  • create an AsyncListener and add to AsyncContext
  • add the AsyncContext to queue

    final AsyncContext ac = req.startAsync();
    ac.setTimeout(10 \* 60 \* 1000);
    ac.addListener(new AsyncListener() {

doPost methodcall context.notify(message);put the message into the messageQueue
destroy method 
  • clean up the queue
  • interrupt the notifierThread


Note that asynchronous API in Servlet 3.0 are, in fact, quite easy to use. In this scenario, some coding is need for the notification thread. If you don't want to manage the thread that notify, you can take look at Atmosphere.

Tuesday Mar 10, 2009

Using Jetty Bayeux Client in GlassFish v3

In Cometd environment, one can access cometd services through simple Javascript, Java API for Bayeux Protoc, DOJO, etc.

In the Grizzly Issue 174, developer amplus has contributed a first porting of Jetty Bayeux Java Client to Grizzly. A modification of the contribution has been checkin to Grizzly. The above client code is based on Jetty 6.1.11. Subsequently, various cometd bugs has been fixed in Grizzly 1.9.8 or later.

In this blog, we will describe how to use the Jetty Bayeux client in Grizzly with GlassFish v3.

Environment Setting

In this moment, comet support is turned off by default. The comet/cometd can be turned on in GlassFish v3 by adding the following property to corresponding http-listener. In our case, it is the http-listener-1.

    <property name="cometSupport" value="true">

Note that it is recommended that one should set the above property by using asadmin rather than directly editing the domain.xml. For instance,

    asadmin set

Download the following jars and put it under $GLASSFISH_HOME/domains/domain1/lib:

  • grizzly-cometd-client-1.9.8.jar
  • cometd-bayeux-6.1.11.jar
  • jetty-6.1.11.jar
  • jetty-client-6.1.11.jar
  • jetty-util-6.1.11.jar
The first jar is from Grizzly repository. Note that you may like to get the correct Grizzly version working with your GlassFish v3. (For instance, one can find out the Grizzly version in MANIFEST.MF of web-glue.jar.) The remaining jars are from Jetty repository 6.1.11.

Finally, we have to start the server.

A Cometd client application using Jetty Bayeux client

In our example, we will create a web Bayeux Client for Cometd Chat Sample. It can be downloaded here.

One need to import Jetty's classes as follows:

    import org.mortbay.cometd.AbstractBayeux;
    import org.mortbay.cometd.client.BayeuxClient;
    import org.mortbay.jetty.client.HttpClient;
    import org.mortbay.thread.QueuedThreadPool;
    import org.mortbay.util.ajax.JSON;
    import dojox.cometd.Bayeux;
    import dojox.cometd.Client;
    import dojox.cometd.Message;
    import dojox.cometd.MessageListener;

Then one need to create a BayeuxClient in as follows:

  • Create a HttpClient.

        httpClient = new HttpClient();

  • Create a QueuedThreadPool for the HttpClient.

        QueuedThreadPool pool = new QueuedThreadPool();

  • Start the HttpClient and create a BayeuxClient.

        client = new BayeuxClient(httpClient, address, cometdUri) {
            public void deliver(Client from, Message message) {
                // do something
                super.deliver(from, message);

    where address is an InetSocketAddress and cometdUri is the cometd service uri.

  • Create a MessageListener for the BayeuxClient.

        MessageListener listener = new MessageListener() {
            public void deliver(Client fromClient, Client toClient, Message msg) {
                Object data = msg.get(AbstractBayeux.DATA_FIELD);
                if (data != null) {
                   // do something

    This listener is a no-op as we only use the client to send message in our case.

  • Start the BayeuxClient and subscribe the channel.


With the setup above, the JSON message can be published as follows:

    Object msg=new JSON.Literal("{\\"user\\":\\"" + name + "\\",\\"chat\\":\\"" + chat + "\\"}");
    client.publish(channel, msg, String.valueOf(mid.getAndIncrement()));

where msg is a JSON object associated to data.

Comparison with Java API for Bayeux Protocol

In this section, we will compare Jetty Bayeux client with the Java API for Bayeux Protocol. For convenience, I will summarize the Java API for Bayeux Protocol as follows:
  • Get the CometContext.

        CometEngine context = CometEngine.getEngine().getCometContext(channel);

  • Create the DeliverResponse.

        Map map = new HashMap();
        map.put(messageDataName, messageDataValue);
        Data data = new Data();

        DeliverResponse deliverResponse = new DeliverResponse();

    Note that in this moment, one has to setFinished(true) in addition to setLast(true).

  • Notify the deliverResponse


 Jetty Bayeux ClientJava API for Bayeux Protocol
Setupmore involvedsimple
Access Cometd Servicelocal and remotelocal
Clientin server and standlonein server
Construction of JSON messagessome explicitlyall use API

Shing Wai Chan


« July 2016