The term comet was created by Alex Russell (dojo). There are several different implementations out there. Jetty, Tomcat and Glassfish (for instance) offer support for comet. The Dojo Toolkit provides the client side bits of it. I decided to play with comet, using Jetty and Dojo. I did download the latest, greatest Jetty (6.1.7). This distribution already contains the cometd APIs and a demo project (in $JETTY_HOME/contrib/cometd). The demo is easy to launch, just call
mvn jetty:run
and the nice maven2 plugin does the rest. The demo contains a simple chat and an echo example. I wasn’t interested in chatting
or echo. Doing some google searches, I found this (outdated) comet demo blog. It does what I was looking for. Pushing data from the server to the client.
I created a very simple client HTML page:
<html>
<head>
<script type="text/javascript" src="pathToDojo.js"></script>
<script type="text/javascript">
dojo.require("dojox.cometd");
dojo.require("dojox.cometd.timestamp");
//a callback function
function callback(msg)
{
alert(msg.data.payload);
}
//cometd servlet is registered at /cometd
dojox.cometd.init("/cometd");
//subscribe to message channel; add the callback
dojox.cometd.subscribe("/ping",callback);
</script>
</head>
<body>
A trivial comet client page
</body>
</html>
What does this do? Not much. But enough:
- registering the required JS files
- defining a callback function
- initialize the cometd, pointing to Jetty’s ContinuationCometdServlet URL
- subscribing to a channel and register the callback function
The callback (callback()) is called, when ever the client receives a message, from the server.
On the server, I created a (simple) ServletFilter, to actually send a message to the “/ping” channel. Here is the doFilter() method:
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chaing)
throws IOException, ServletException
{
Bayeux bayeux = (Bayeux) filterConfig.getServletContext()
.getAttribute(Bayeux.DOJOX_COMETD_BAYEUX);
Channel channel = bayeux.getChannel("/ping", true);
Client client = bayeux.newClient("client",null);
Map<String,Object> message = new HashMap<String,Object>();
message.put("payload", new java.util.Date());
channel.publish(client ,message, "messageId");
}
When ever the filter is called, It creates a message and publishes on the “/ping” channel.I tested the demo the following way:
- opened the HTML file via IE (was served via jetty)
- opened the HTML file via FF (was served via jetty)
- opened the Filter URL from my iPod
What happened was this:
- doFilter() was executed and the message was published on the channel.
- both clients were notified and the callback was executed, which simple shows the “payload” in an JS alert().
This is a simple, but interesting demo.
Now I tried to queue multiple message after some seconds to the clients. I modified my server side code to have a simple loop:
...
for(int i = 0; i < 10; i++)
{
message.put("payload", new java.util.Date());
channel.publish(client ,message, "messageId");
try
{
Thread.sleep(5000);
} catch (InterruptedException e)
{ ... }
}
...
Sure, that isn’t the best way to push multiple message to the client, but it worked. By doing some more research, I noticed that Apache’s ActiveMQ has ajax support. That would be a nice extended way to integrate a real messaging system to the comet way of doing things.
Please note, that I used the ServletFilter only to emulate a “message driven” architecture.
In a real application, usually your client get’s updated by an event, and not (only) b/c a Servlet(Filter) was executed.
I am sure, that using comet technology you can create pretty cool web 2.0 / mashup applications.