Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 7 of 7
Comet support is one of the key features of the upcoming Servlet API 3.0. In the meantime, popular servlet engines already support Comet, using different approaches. Jetty 6 tries to keep the impact
on the existing Servlet API programming approach to a minimum. Jetty uses continuations to avoid blocking threads by writing the response data. The continuation suspends the request and frees the current servlet
request-handling thread. Jetty uses a RetryRequest runtime exception to implement the continuation.
When the suspend() method is called in Listing 16 below, Jetty throws a RetryRequest runtime exception. This RetryRequest exception is caught by the container, and the request placed into a timeout queue. If the timeout expires, the whole service
method of the servlet will be re-executed. In this sense a Jetty continuation is not a "true" continuation: a classic continuation
represents an execution state of a program at a certain point. The execution state is defined by the program's store and control
state which includes the stack trace, variables, and program counter. Resuming the execution means that the program's store
and control state will be reconstructed and the processing will continue. The Jetty approach implies that the service method
is idempotence, which means it yields the same result after the method is applied multiple times.
public class ForeverFrameJettyServlet extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// handle the time request
if (req.getRequestURI().endsWith("/time")) {
// get the jetty continuation
Continuation cc = ContinuationSupport.getContinuation(req, null);
// set the header
resp.setContentType("text/html");
// write time periodically
while (true) {
cc.suspend(1000); // suspend the response
String script = "<script>\r\n" +
" parent.printTime(\"" + new Date() + "\");\r\n" +
"</script>";
resp.getWriter().println(script);
resp.getWriter().flush();
}
}
// ...
}
}
Tomcat 6 introduces a new CometProcessor interface, which defines an event() callback method to process "Comet events" in an asynchronous way. The event() method will be called if specific events like BEGIN, ERROR, or READ occur. Implementing the CometProcessor interface means that Servlet API service methods such as doGet() will never be called.
public class ForeverFrameTomcatServlet extends HttpServlet implements CometProcessor {
private ArrayList<HttpServletResponse> connections = new ArrayList<HttpServletResponse>();
public void init() throws ServletException {
Thread timeSenderThread = new Thread(new TimeSender());
timeSenderThread.setDaemon(true);
timeSenderThread.start();
}
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest req = event.getHttpServletRequest();
HttpServletResponse resp = event.getHttpServletResponse();
// handle the time request
if (req.getRequestURI().endsWith("/time")) {
if (event.getEventType() == CometEvent.EventType.BEGIN) {
synchronized(connections) {
connections.add(resp);
}
} else if (event.getEventType() == CometEvent.EventType.ERROR) {
synchronized(connections) {
connections.remove(resp);
}
resp.getWriter().close();
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
synchronized(connections) {
connections.remove(resp);
}
resp.getWriter().close();
event.close();
}
}
// ...
}
class TimeSender implements Runnable {
public void run() {
while (true) {
synchronized (connections) {
for (HttpServletResponse response : connections) {
try {
PrintWriter bodyStream = response.getWriter();
String script = "<script>\r\n" +
" parent.printTime(\"" + new Date() + "\");\r\n" +
"</script>";
bodyStream.write(script);
bodyStream.flush();
} catch (IOException e) {
// handle the exception
}
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) { }
}
}
}
}
While beyond the scope of this article, it should also be noted that Grizzly, the NIO framework on which the Glassfish HTTP Listener is built, also handles Comet events. In contrast to Tomcat, Grizzly's Comet event handling is integrated with the servlet's service methods.
Servlet containers Tomcat and Jetty take two different approaches to asynchronous, non-blocking HTTP, but both provide adequate
support. In addition, most popular HTTP and network libraries already support asynchronous message handling, at least at an
early alpha-level implementation. The Apache Software Foundation's HttpCore library supports non-blocking HTTP for the client and server side, and is currently in beta status. The upcoming version
of the Apache HttpClient is also based on the HttpCore library. The MINA project is currently working on Asyncweb, which also supports non-blocking HTTP on the client and server side. Examples in this article were based on the HTTP module
of the xSocket network library, which is in alpha status.
See the Resources section to learn more about the technologies discussed in this article. You can also discuss them in the associated discussion forum.
Read more about Enterprise Java in JavaWorld's Enterprise Java section.
xSocket.
Archived Discussions (Read only)