Introduction to Comet

Comet is a programming technique that allows a web server to
send updates to clients without requiring the clients to explicitly
request them.

This kind of programming technique is called server
push, which means that the server pushes data to the client.
The opposite style is client pull, which means
that the client must pull the data from the server, usually through
a user-initiated event, such as a button click.

Web applications that use the Comet technique can deliver updates
to clients in a more timely manner than those that use the client-pull
style while avoiding the latency that results from clients frequently
polling the server.

One of the many use cases for Comet is a chat room application.
When the server receives a message from one of the chat clients, it
needs to send the message to the other clients without requiring them
to ask for it. With Comet, the server can deliver messages to the
clients as they are posted rather than expecting the clients to poll
the server for new messages.

To accomplish this scenario, a Comet application establishes
a long-lived HTTP connection. This connection is suspended on the
server side, waiting for an event to happen before resuming. This kind of
connection remains open, allowing an application that uses the Comet
technique to send updates to clients when they are available rather
than expecting clients to reopen the connection to poll the server
for updates.

The Grizzly Implementation of Comet

A limitation of the Comet technique is that you must use
it with a web server that supports non-blocking connections to avoid
poor performance. Non-blocking connections are those that do not need
to allocate one thread for each request. If the web server were to
use blocking connections then it might end up holding many thousands
of threads, thereby hindering its scalability.

The GlassFish server includes the Grizzly HTTP Engine, which
enables asynchronous request processing (ARP) by avoiding blocking
connections. Grizzly's ARP implementation accomplishes this by using
the Java NIO API.

With Java NIO, Grizzly enables greater performance and scalability
by avoiding the limitations experienced by traditional web servers
that must run a thread for each request. Instead, Grizzly's ARP mechanism
makes efficient use of a thread pool system and also keeps the state
of requests so that it can keep requests alive without holding a single
thread for each of them.

Grizzly supports two different implementations of Comet:

Grizzly Comet —
Based on ARP, this includes a set of APIs that you use from a web
component to enable Comet functionality in your web application. Grizzly
Comet is specific to the Oracle GlassFish Server.

Bayeux Protocol —
Often referred to as Cometd, it consists of
the JSON-based Bayeux message protocol, a set of Dojo or Ajax libraries,
and an event handler. The Bayeux protocol uses a publish/subscribe
model for server/client communication. The Bayeux protocol is portable,
but it is container dependent if you want to invoke it from an Enterprise
Java BeansTM (EJBTM)
component. The Grizzly implementation of Cometd consists
of a servlet that you reference from your web application.

Client Technologies to Use With Comet

In addition to creating a web component that uses the Comet
APIs, you need to enable your client to accept asynchronous updates
from the web component. To accomplish this, you can use JavaScriptTM,
IFrames, or a framework, such as Dojo.

An IFrame is an HTML element that allows you to include other
content in an HTML page. As a result, the client can embed updated
content in the IFrame without having to reload the page.

The example in this tutorial employs a combination of JavaScript
and IFrames to allow the client to accept asynchronous updates. A
servlet included in the example writes out JavaScript code to one
of the IFrames. The JavaScript code contains the updated content and
invokes a function in the page that updates the appropriate elements
in the page with the new content.

The next section explains the two kinds of connections that
you can make to the server. While you can use any of the client technologies
listed in this section with either kind of connection, it is more
difficult to use JavaScript with an HTTP-streaming connection.

Types of Comet
Connections

When working with Comet, as implemented in Grizzly, you have
two different ways to handle client connections to the server:

HTTP Streaming

Long
Polling

HTTP Streaming

The HTTP Streaming technique keeps a connection open indefinitely.
It never closes, even after the server pushes data to the client.

In the case of HTTP streaming, the application sends a single
request and receives responses as they come, reusing the same connection
forever. This technique significantly reduces the network latency
because the client and the server don't need to open and close the
connection.

The client makes an initial request and then suspends the request,
meaning that it waits for a response. Whenever data is available,
the server writes it to the response.

Long Polling

The long-polling technique is a combination of server-push and
client-pull because the client needs to resume the connection after
a certain amount of time or after the server pushes an update to the
client.

The basic life cycle of an application using long-polling is:

request -> suspend --> data available --> write response -->
resume

The client makes an initial request and then suspends the request.
When an update is available, the server writes it to the response.
The connection closes, and the client optionally resumes the connection.

How to Choose the Type of Connection

If you anticipate that your web application will need to send
frequent updates to the client, you should use the HTTP-streaming
connection so that the client does not have to frequently reestablish
a connection. If you anticipate less frequent updates, you should
use the long-polling connection so that the web server does not need
to keep a connection open when no updates are occurring. One caveat
to using the HTTP-streaming connection is that if you are streaming
through a proxy, the proxy can buffer the response from the server.
So, be sure to test your application if you plan to use HTTP-streaming
behind a proxy.

Register the CometHandler implementation
with the CometContext object:

cometContext.addCometHandler(handler)

Notify one or more CometHandler implementations
when an event happens:

cometContext.notify((Object)(handler))

The Hidden Frame Example

This rest of this tutorial uses the Hidden Frame example to
explain how to develop Comet-enabled web applications. You can download
the example from grizzly.dev.java.net at Hidden example download. From there, you can download
a prebuilt WAR file as well as a JAR file containing the servlet code.

The Hidden Frame example is so called because it uses hidden
IFrames. The example allows multiple clients to increment a counter
on the server. When a client increments the counter, the server broadcasts
the new count to the clients using the Comet technique.

The client side of the example uses hidden IFrames with embedded
JavaScript tags to connect to the server and to asynchronously post
content to and accept updates from the server.

The server side of the example consists of a single servlet
that listens for updates from clients, updates the counter, and writes
JavaScript code to the client that allows it to update the counter
on its page.

The browser loads three frames: The first one accesses
the servlet using an HTTP GET; the second one loads the count.html page, which displays the current count; and the third
one loads the button.html page, which is used
to send the POST request.

After clicking the button on the button.html page,
the page submits a POST request to the servlet.

The doPost method calls the onEvent method of the Comet handler and redirects the
incremented count along with some JavaScript to the count.html page
on the client.

The updateCount() JavaScript function
on the count.html page updates the counter on
the page.

Because this example uses long-polling, the JavaScript
code on count.html calls doGet again
to resume the connection after the servlet pushes the update.

Creating a Comet-Enabled Application

This section uses the Hidden Frame example application to demonstrate
how to develop a Comet application. The main tasks for creating a
simple Comet-enabled application are the following:

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.

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.

To Add the Comet Handler
to the Comet Context

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

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.

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

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.

Creating the Client Pages

Developing the HTML pages for the client involves performing
these steps:

Create a welcome HTML page, called index.html,
that contains: one hidden frame for connecting to the servlet through
an HTTP GET; one IFrame that embeds the count.html page,
which contains the updated content; and one IFrame that embeds the button.html page, which is used for posting updates using
HTTP POST.

Create the count.html page that
contains an HTML element that displays the current count and the JavaScript
for updating the HTML element with the new count.

Create the button.html page that
contains a button for the users to submit updates.

To Create a HTML Welcome Page
That Contains IFrames for Receiving and Sending Updates

The first frame, which is hidden, points to the servlet by referencing
its context path. The second frame displays the content from count.html, which displays the current count. The second frame displays
the content from button.html, which contains
the submit button for incrementing the counter.

To Create a HTML Page That
Updates and Displays the Content

Create an HTML page called count.html and
add the following content to it:

The JavaScript takes the updated count it receives from the
servlet and updates the count element in the page. The last line in
the updateCount() function invokes the servlet's doGet method again to reestablish the connection.

For HTTP-Streaming:

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

parent.hidden.location.href = “hidden_comet”

This line invokes the doGet method
of CometServlet again, which would reestablish
the connection. In the case of HTTP-Streaming, you want the connection
to remain open. Therefore, you don't include this line of code.

To Create the HTML Page
That Allows Submitting Updates

Create an HTML page called button.html and
add the following content to it:

This deployment descriptor contains a servlet declaration and
mapping for HiddenCometServlet. The load-on-startup attribute must be set to 0 so that the Comet-enabled servlet
will not load until the client makes a request to it.

Deploying and Running a Comet-Enabled Application

Before running a Comet-enabled application in the GlassFish Server,
you need to enable Comet in the server. Then you can deploy the application
just as you would any other web application.

When running the application, you need to connect to it from
at least two different browsers to experience the effect of the servlet
updating all clients in response to one client posting an update to
the server.

Enabling Comet in the GlassFish Server

Before running a Comet-enabled application, you need to enable
Comet in the HTTP listener for your application by setting a special
attribute in the associated protocol configuration. The following example shows the asadmin set command that adds this attribute:

asadmin set server-config.network-config.protocols.protocol.http-1.http.comet-support-enabled="true"

To Run the Example

Open two web browsers, preferably two different brands
of web browser.

Enter the following URL in both browsers:

http://localhost:8080/grizzly-comet-hidden/index.html

When the first page loads in both browsers, click the
button in one of the browsers and watch the count change in the other
browser window.

Bayeux Protocol

The Bayeux protocol, often referred to as Cometd,
greatly simplifies the use of Comet. No server-side coding is needed
for servers such as GlassFish Server that support the Bayeux protocol.
Just enable Comet and the Bayeux protocol, then write and deploy the
client as described in the following tasks:

Enabling Comet

Before running a Comet-enabled application, you need to enable
Comet in the HTTP listener for your application by setting a special
attribute in the associated protocol configuration. The following example shows the asadmin set command that adds this attribute:

asadmin set server-config.network-config.protocols.protocol.http-1.http.comet-support-enabled="true"

Substitute the name of the protocol for http-1.

To Configure the web.xml File

To enable the Bayeux protocol on the GlassFish Server, you must
reference the CometdServlet in your web application's web.xml file. In addition, if your web application includes
a servlet, set the load-on-startup value for your
servlet to 0 (zero) so that it will not load until
the client makes a request to it.

For information about pushing data from an external component
such as an EJB module, see the example at http://blogs.sun.com/swchan/entry/java_api_for_cometd.
Using this Grizzly Java API for Cometd makes
your web application non-portable. Running your application on a server
that doesn't support Grizzly Comet will not work.