星期四 四月 03, 2008
Recently, there is a great interest in Comet technology. One can find many interesting articles in Comet Daily. Comet allows server and client to keep a live connection for communication. This provides a mechanism for server to update clients, instead of having classical polling. In this blog, I am going to share my experience about using Comet with hidden frame and long polling in GlassFish v3 Technology Preview 2 builds. I try to make example as simple as possible to illustrate the basic interactions there. If you want to learn more about Comet, then I recommend Jean-Francois' blogs.
Set up GlassFish v3
Download GlassFish v3 Technology Preview 2, unzip the file and start the server with jvm option v3.grizzlySupport=true to enable comet.
java -Dv3.grizzlySupport=true -jar glassfish-10.0-SNAPSHOT.jar
We need the above jvm-option in today's build. This will not be needed when comet is enabled by default.
Comet Servlet Code
The comet servlet code is adapted from grizzly sample comet-counter, which uses Ajax client. The details of our serlvet is as follows:
- In
init(ServletConfig), one registers a context path to CometEngine,ServletContext context = config.getServletContext();
contextPath = context.getContextPath() + "/hidden_comet";
CometEngine engine = CometEngine.getEngine();
CometContext cometContext = engine.register(contextPath);
cometContext.setExpirationDelay(30 * 1000);where "/hidden_comet" is url-pattern of the comet servlet in
web.xml. For testing purpose, one keeps the connection for 30 sec. - In
doGet(HttpServletRequest, HttpServletResponse), one looks up the CometContext and adds our CometHandler.CounterHandler handler = new CounterHandler();
handler.attach(res);
CometEngine engine = CometEngine.getEngine();
CometContext context = engine.getCometContext(contextPath);
context.addCometHandler(handler); - In
doPost(HttpServletRequest, HttpServletResponse), one increments the counter and then invokes theCometContext.notify, which will trigger theCometHandler.onEventabove.counter.incrementAndGet();
CometEngine engine = CometEngine.getEngine();
CometContext<?> context = engine.getCometContext(contextPath);
notify(null);In addition, it forwards to
count.htmlpage for displaying the count.req.getRequestDispatcher("count.html").forward(req, res); - Next, one need to have a class implementing
CometHandlerinterface. Among methods inCometHandler, the most interesting one isonEvent(CometEvent).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);
}
}In our case, it writes a Javascript back to client side. This will invoke the Javascript function
updateCountincount.html. TheonEventalso invokesresumeCometHandler. This is necessary as the polling connection will be dropped once it is used. - To compile the above Java code, one needs to include javax.javaee*.jar and grizzly-comet*.jar in classpath.
Client Code
On client side, I will illustrate the technique of hidden frame.
Basically, the main page will have at least two frames. One of them does the long polling and is hidden from user.
In our case, the index.html consists two frames as follows:
<iframe name="hidden" src="hidden_comet" frameborder="0" height="0" width="100%"><iframe>
<iframe name="counter" src="count.html" frameborder="0" height="100%" width="100%"><iframe>
The first frame, which is hidden, is pointed to our Comet Servlet above through GET method.
The second frame is to display the counter and submit button
for incrementing the counter.
The Javascript in count.html is very simple as follows:
<script type='text/javascript'>
function updateCount(c) {
document.getElementById('count').innerHTML = c;
parent.hidden.location.href = "hidden_comet";
};
</script>
How does it work?
One can download the sources and war file from here, and deploy the war file. Using two browsers to access http://localhost:8080/grizzly-comet-hidden/index.html and click on "Click" button on each browser separately. Then one sees that counts in both browsers will be updated whenever one clicks on one of them. The mechanism is outlined as follows:
- When the user accesses
index.html, a browser will load two frames:- The "hidden" frame accesses our Comet Servlet through
GETmethod. This allows the client to start long polling with server. - The "counter" frame loads a static
count.html.
- The "hidden" frame accesses our Comet Servlet through
- When the user clicks on the button in
count.html, it submits aPOSTrequest to our Comet Servlet. This triggers the CometHandleronEventmethod and redirects back tocount.htmlto display the count. TheonEventtriggers theupdateCount()JavaScript in "counter" frame, which will- update the count and
- invoke the Comet Servlet
doGetfor long polling in "hidden" frame,











Hi Shing-Wai,
Great post!
You said tha...
Hi Jennifier,
This example has no Ajax in client...
If one download the latest gf v3 build, then one s...
jh