Today's users expect fast, dynamic applications accessible from the web. This series shows you how to develop event-driven web applications using Reverse Ajax techniques. Part 1 introduced Reverse Ajax, polling, streaming, Comet, and long polling. You learned how Comet using HTTP long polling is the best way to reliably implement Reverse Ajax, since all browsers now provide support. Part 2 showed how to implement Reverse Ajax using WebSockets. Code examples helped illustrate WebSockets, FlashSockets, constraints on the server side, request-scoped services, and pausing long-lived requests.
In this article, delve into details about using Comet and WebSockets in your web application for different web containers and APIs (Servlet 3.0 and Jetty Continuations). Learn to transparently use Comet and WebSockets by using abstraction libraries, such as Socket.IO. Socket.IO uses feature detection to decide if the connection will be established with WebSocket, AJAX long polling, Flash, and so on.
You can download the source code used in this article.
Ideally, to get the most out of this article, you should know JavaScript and Java. The example created in this article was built using Google Guice, a dependency injection framework written in Java. To follow along with this article, you should be familiar with the concepts of a dependency injection framework, such as Guice, Spring, or Pico.
To run the sample in this article, you will also need the latest version of Maven and the JDK (see Resources).
Server solutions for Comet and WebSocket
You learned in Part 1 that Comet (long-polling or streaming) requires that the server is able to pause a request and resume or complete it after a potentially long delay. Part 2 described how servers need to use the non-blocking I/O features to handle a lot of connections and that they only use threads to serve requests (thread-per-request model). You also learned that the usage of WebSocket is server-dependent and that not all servers support WebSockets.
This section shows you how to use Comet and WebSockets, if applicable, on the Jetty, Tomcat, and Grizzly web servers. The source code provided with this article contains a sample chat web application for Jetty and Tomcat. This section also discusses the supported APIs for the following application servers: Jboss, Glassfish, and WebSphere.
Jetty is a web server supporting the Java Servlet specification 3.0, WebSockets, and many other integration specifications. Jetty is:
- Powerful and flexible
- Easily embedded
- Supports virtual hosts, session clustering, and a lot of features that can be easily configured through Java code or XML
- Used for the Google App Engine's hosting service
The core Jetty project is hosted by the Eclipse Foundation.
Since Version 6, Jetty includes an asynchronous API called Jetty Continuations, which allows a request to be paused and resumed later. Table 1 shows the map of the supporting specification and API for the major Jetty version families.
Table 1. Jetty versions and support
| Supports | Jetty 6 | Jetty 7 | Jetty 8 |
|---|---|---|---|
| Non-blocking I/O | X | X | X |
| Servlet 2.5 | X | X | X |
| Servlet 3.0 | X | X | |
| Jetty Continuations (Comet) | X | X | X |
| WebSockets | X | X |
To implement Reverse Ajax with Comet, you can use Jetty's Continuation API, as shown in Listing 1:
Listing 1. Jetty Continuation API for Comet
// Pausing a request from a servlet's method (get, post, ...):
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Continuation continuation = ContinuationSupport.getContinuation(req);
// optionally set a timeout to avoid suspending requests for too long
continuation.setTimeout(0);
// suspend the request
continuation.suspend();
// then hold a reference for future usage from another thread
continuations.offer(continuation);
}
// Then, from another thread which wants to send an event to the client:
while (!continuations.isEmpty()) {
Continuation continuation = continuations.poll();
HttpServletResponse response =
(HttpServletResponse) continuation.getServletResponse();
// write to the response
continuation.complete();
}
|
The complete web application is in the source code that comes with this article. The Jetty Continuations are bundled in a JAR archive. You have to put this JAR file in your web application's WEB-INF/lib folder to be able to use Jetty's Comet features. The Jetty Continuations will work on Jetty 6, 7, and 8.
Beginning with Jetty 7, you also have access to the WebSockets feature. Place Jetty's WebSocket JAR file in your web application's WEB-INF/lib folder to gain access to Jetty's WebSocket API, as shown in Listing 2:
Listing 2. Jetty's WebSocket API
// Implement the doWebSocketConnect and returns an implementation of
// WebSocket:
public final class ReverseAjaxServlet extends WebSocketServlet {
@Override
protected WebSocket doWebSocketConnect(HttpServletRequest request,
String protocol) {
return [...]
}
}
// Sample implementation of WebSocket:
class Endpoint implements WebSocket {
Outbound outbound;
public void onConnect(Outbound outbound) {
this.outbound = outbound;
}
public void onMessage(byte opcode, String data) {
outbound.sendMessage("Echo: " + data);
if("close".equals(data))
outbound.disconnect();
}
public void onFragment(boolean more, byte opcode,
byte[] data, int offset, int length) {
}
public void onMessage(byte opcode, byte[] data,
int offset, int length) {
onMessage(opcode, new String(data, offset, length));
}
public void onDisconnect() {
outbound = null;
}
}
|
In the downloadable source code, there is a chat sample in the jetty-websocket folder that demonstrates how to use Jetty's WebSocket API.
Tomcat is probably the most widely known web server. It has been used for many years and was integrated as a web container into early versions of the Jboss application server. Tomcat was also used as the reference implementation for the servlet specification. It was discontinued in servlet API 2.5 when people began to look at alternatives based on non-blocking I/O (such as Jetty). Table 2 shows the supported specifications and API for the two latest Tomcat version families.
Table 2. Tomcat support
| Supports | Tomcat 6 | Tomcat 7 |
|---|---|---|
| Non-blocking I/O | X | X |
| Servlet 2.5 | X | X |
| Servlet 3.0 | X | |
| Advanced I/O (Comet) | X | X |
| WebSockets |
As shown in Table 2, Tomcat does not support WebSockets; it has an equivalent of Jetty's Continuations called Advanced I/O to support Comet. Advanced I/O is much more of a low-level wrapper around NIO than a good API to facilitate Comet usage. It is poorly documented, and there are few examples of applications using this API. Listing 3 shows a servlet example used to suspend and resume requests in a chat web application. You can find the complete web application in the source code with this article.
Listing 3. Tomcat API for Comet
public final class ChatServlet extends HttpServlet
implements CometProcessor {
private final BlockingQueue<CometEvent> events =
new LinkedBlockingQueue<CometEvent>();
public void event(CometEvent evt)
throws IOException, ServletException {
HttpServletRequest request = evt.getHttpServletRequest();
String user =
(String) request.getSession().getAttribute("user");
switch (evt.getEventType()) {
case BEGIN: {
if ("GET".equals(request.getMethod())) {
evt.setTimeout(Integer.MAX_VALUE);
events.offer(evt);
} else {
String message = request.getParameter("message");
if ("/disconnect".equals(message)) {
broadcast(user + " disconnected");
request.getSession().removeAttribute("user");
events.remove(evt);
} else if (message != null) {
broadcast("[" + user + "]" + message);
}
evt.close();
}
}
}
}
void broadcast(String message) throws IOException {
Queue<CometEvent> q = new LinkedList<CometEvent>();
events.drainTo(q);
while (!q.isEmpty()) {
CometEvent event = q.poll();
HttpServletResponse resp = event.getHttpServletResponse();
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/html");
resp.getWriter().write(message);
event.close();
}
}
}
|
In Tomcat, an asynchronous servlet must implement a
CometProcessor. For asynchronous servlets,
Tomcat does not call the standard HTTP methods
(doGet, doPost, and
so on). Instead, an event is sent to the
event(CometdEvent) method. When a request first
arrives, the example checks to see if it is a
GET in order to suspend it;
evt.close() is not called. If it is a
POST, it means the user sent a message, so it
is broadcast to the other CometEvent, and
evt.close() is called to complete the post
request. On the client side, broadcasting will make all long polling
requests to complete the sent message, and another long polling request is
immediately sent to receive the next events.
Grizzly is not a web container, but more of an NIO framework that helps developers build scalable applications. It was developed as part of the Glassfish project, but it can also be used on a standalone or embedded basis. Grizzly provides components to act as an HTTP/HTTPS server and components for Bayeux Protocol, Servlet, HttpService OSGi, and Comet, among others. Grizzly supports WebSockets and is used in Glassfish to provide Comet and WebSocket support.
Glassfish, Oracle's Application Server, is the reference implementation of the J2EE 6 specifications. Glassfish is a complete suite, like WebSphere and Jboss, using Grizzly for NIO, WebSocket, and Comet support. Its modular architecture, based on OSGI, makes it really flexible for changing components. Table 3 shows Glassfish support for Comet and WebSockets.
Table 3. Glassfish support
| Supports | Glassfish 2 | Glassfish 3 |
|---|---|---|
| Non-blocking I/O | X | X |
| Servlet 2.5 | X | X |
| Servlet 3.0 | X | |
| Comet | X | X |
| WebSockets | X |
Grizzly usage is not trivial, as it's intended to be used embedded or directly from Java code. It is widely used as a framework to support Comet and WebSockets that can be embedded in a larger application, such as Glassfish, which provides web deployment capabilities and the Servlet specification API.
See Resources for links to examples of WebSockets and Comet in Grizzly or Glassfish. Because Glassfish uses Grizzly, the examples should work on both. The WebSocket API is very similar to the one in Jetty, but the Comet API is more complex.
Jboss is an application server built on top of Tomcat. It has supported Comet and NIO since Version 5. Jboss 7 is still in development, but is included in Table 4 below.
Table 4. Jboss support
| Supports | Jboss 5 | Jboss 6 | Jboss 7 |
|---|---|---|---|
| Non-blocking I/O | X | X | X |
| Servlet 2.5 | X | X | X |
| Servlet 3.0 | X | X | |
| Comet | X | X | X |
| WebSockets |
WebSphere is an IBM application server. Support of the Servlet 3 API (containing the standardized asynchronous API for Comet) was added in Version 8 of WebSphere (see Resources to read the announcement).
Table 5. WebSphere support
| Supports | WebSphere 8 |
|---|---|
| Non-blocking I/O | X |
| Servlet 2.5 | X |
| Servlet 3.0 | X |
| Comet | X |
| WebSockets |
What about having common APIs?
Each server brings its own native API for Comet and WebSocket. As you might guess, writing a portable web application can be difficult. The Servlet 3.0 Specification includes additional methods to suspend and resume a request later, allowing all web containers supporting the Servlet 3.0 Specification to support the Comet long-polling requests.
The Jetty team provides a library called Jetty Continuation, which is independent from the Jetty container. The Jetty Continuation library is clever enough to detect the container or specification available. If running on a Jetty server, the native Jetty API will be used. If running on a container supporting the Servlet 3.0 Specification, this common API will be used. Otherwise, a non-scalable implementation is used.
Regarding WebSockets, there is no standard yet in Java, and thus you need to use the container vendor API within your web application if you want to use WebSockets.
Table 6 summarizes the technologies supported by the various servers.
Table 6. Technologies supported by servers
| Container | Comet | WebSocket |
|---|---|---|
| Jetty 6 | Jetty Continuations | N/A |
| Jetty 7 | Servlet 3.0 Jetty Continuations | Native Jetty API |
| Jetty 8 | Servlet 3.0 Jetty Continuations | Native Jetty API |
| Tomcat 6 | Advanced I/O | N/A |
| Tomcat 7 | Servlet 3.0 Advanced I/O Jetty Continuations | N/A |
| Glassfish 2 | Native Grizzly API | N/A |
| Glassfish 3 | Servlet 3.0 Native Grizzly API Jetty Continuations | Native Grizzly API |
| Jboss 5 | Native Jboss API | N/A |
| Jboss 6 | Servlet 3.0 Native Jboss API Jetty Continuations | N/A |
| Jboss 7 | Servlet 3.0 Native Jboss API Jetty Continuations | N/A |
| WebSphere 8 | Servlet 3.0 Jetty Continuations | N/A |
There is no obvious solution for WebSockets except to use the container API. As for Comet, each container supporting the Servlet 3.0 Specification supports Comet. The advantage of Jetty Continuations here is to provide Comet support on all of these containers. Thus, some Reverse Ajax libraries (which is discussed in the next section and in the next article in this series) are using Jetty Continuations for their server-side API.
The Jetty Continuation API is shown in the Jetty sample in this article. The Servlet 3.0 Specification was described and used in the two Comet examples in Part 1 of this series.
Considering all of the major APIs (Servlet 3.0 and Jetty Continuations), plus all of the native support on the server side, and two major ways of doing Reverse Ajax on the client side (Comet and WebSocket), writing your own JavaScript and Java code to wire them could be difficult. You must also factor in timeouts, connection failures, acknowledgement, ordering, buffering, and so on.
The rest of this article shows you Socket.IO in action. Part 4 in this series will explore Atmosphere and CometD. These three libraries are all open source, and they all support Comet and WebSocket on many servers.
Socket.IO is a JavaScript client library that provides a single API, similar to WebSocket, to connect to a remote server to asynchronously send and receive messages. By providing a common API, Socket.IO supports several transports: WebSocket, Flash Sockets, long polling, streaming, forever Iframes, and JSONP polling. Socket.IO detects browser capabilities and tries to choose the best transport available. The Socket.IO library is compatible with nearly all browsers (including old ones, such as IE 5.5) as well as mobile browsers. It also has features such as heartbeats, timeout, disconnection, and error handling.
The Socket.IO website (see Resources) describes in detail how the library works and which browser and Reverse Ajax technique are used. Basically, Socket.IO uses a communication protocol that enables the client library to communicate with an endpoint on the server side, which can understand the Socket.IO protocol. Socket.IO was first developed for Node JS, a JavaScript engine used to build faster servers. Many projects brought support for other languages, including Java.
Listing 4 shows an example of using the Socket.IO JavaScript library on the client side. The Socket.IO website has documentation and examples.
Listing 4. Socket.IO client library usage
var socket = new io.Socket(document.domain, {
resource: 'chat'
});
socket.on('connect', function() {
// Socket.IO is connected
});
socket.on('disconnect', function(disconnectReason, errorMessage) {
// Socket.IO disconnected
});
socket.on('message', function(mtype, data, error) {
// The server sent an event
});
// Now that the handlers are defined, establish the connection:
socket.connect();
|
To use the Socket.IO JavaScript library, you will need the corresponding Java part called Socket.IO Java (see Resources). This project was initially started by the Apache Wave team to bring support for Reverse Ajax to Wave before WebSockets was available. Socket.IO Java was forked and maintained by Ovea (a company specializing in event-driven web development) and then abandoned. Developing the back end to support the Socket.IO client library is complex due to the multiple transports. Part 4 of this series will show how supporting a lot of transports in a client library is not necessary to achieve better scalability and browser support, since long-polling and WebSockets are sufficient. When WebSockets were not available, Socket.IO was indeed a good choice.
Socket.IO Java uses the Jetty Continuation API to suspend and resume requests. It uses the native Jetty WebSockets API for WebSockets support. You can determine which server will work correctly with a web application using Socket.IO Java.
Listing 5, below, shows an example of how to use Socket.IO on
the server. You have to define a servlet extending
SocketIOServlet and implement a method
returning a sort of endpoint representation. The API is very similar to
the WebSockets API. The advantage is that this API is used on the server
side, independent of the chosen transport on the client side. Socket.IO
translates all transport types to the same API on the server side.
Listing 5. Socket.IO Java library used for the chat sample - servlet
public final class ChatServlet extends SocketIOServlet {
private final BlockingQueue<Endpoint> endpoints =
new LinkedBlockingQueue<Endpoint>();
@Override
protected SocketIOInbound doSocketIOConnect
(HttpServletRequest request) {
String user =
(String) request.getSession().getAttribute("user");
return user == null ? null : new Endpoint(this, user, request);
}
void broadcast(String data) {
for (Endpoint endpoint : endpoints) {
endpoint.send(data);
}
}
void add(Endpoint endpoint) {
endpoints.offer(endpoint);
}
void remove(Endpoint endpoint) {
endpoints.remove(endpoint);
}
}
|
Listing 6 shows how to return the endpoint.
Listing 6. Socket.IO Java library usage for the chat sample - endpoint
class Endpoint implements SocketIOInbound {
[...]
private SocketIOOutbound outbound;
[...]
@Override
public void onConnect(SocketIOOutbound outbound) {
this.outbound = outbound;
servlet.add(this);
servlet.broadcast(user + " connected");
}
@Override
public void onDisconnect(DisconnectReason reason,
String errorMessage) {
outbound = null;
request.getSession().removeAttribute("user");
servlet.remove(this);
servlet.broadcast(user + " disconnected");
}
@Override
public void onMessage(int messageType, String message) {
if ("/disconnect".equals(message)) {
outbound.close();
} else {
servlet.broadcast("[" + user + "] " + message);
}
}
void send(String data) {
try {
if (outbound != null
&& outbound.getConnectionState() == ConnectionState.CONNECTED) {
outbound.sendMessage(data);
}
} catch (IOException e) {
outbound.close();
}
}
}
|
The complete example of Socket.IO is included in the source code in the socketio folder.
All web containers support Comet, and nearly all support WebSockets. Even if the specifications lead to several different native implementations, you can still develop a web application using Comet with the common APIs (Servlet 3.0 or Jetty Continuations). And, even better, you can harness the power of Comet and WebSockets transparently by using libraries such as Socket.IO. Two more libraries, Atmosphere and CometD, will be covered in the next article in this series. All three libraries provide multi-browser support, a fantastic user experience, and the benefits of error handling, an easier API, timeout, and reconnections.
| Description | Name | Size | Download method |
|---|---|---|---|
| Article source code | reverse_ajaxpt3_source.zip | 21KB | HTTP |
Information about download methods
Learn
- Read the previous parts in this series:
-
JSR 315: Java Servlet 3.0
Specification is an update to the 2.5 specification.
- Read the IBM WebSphere Application Server V8.0 release announcement.
- "Google AppEngine uses Jetty!" describes Google's customization of
Jetty.
- Read more about Jetty
Continuations and features.
- See a Glassfish
WebSockets Sample using Grizzly.
- WebSphere Application Server: Learn more about the flagship
product within IBM's WebSphere brand.
-
WebSphere 8 (with Comet support) enables intelligent management
of application environments and helps deliver rich user experiences
faster.
-
Socket.IO aims to make realtime apps
possible in every browser and mobile device, blurring the differences
between the different transport mechanisms.
- "Start using HTML5 WebSockets today" (Nettuts+): Review how to run
a WebSocket server in PHP, and see how to build a client to send and
receive messages to it over the WebSocket protocol.
- "The WebSocket API"
(W3C, July 2011): This specification defines an API that enables Web pages
to use the WebSocket protocol for two-way communication with a remote
host.
- Read more about Asynchronous processing support in Servlet 3.0.
- Philip McCarthy's weblog has more on Comet & Java:
Threaded Vs Nonblocking I/O.
-
The Rox Java NIO
Tutorial collects the author's experiences using the Java NIO
libraries and the dozens of hints, tips, suggestions and caveats that
litter the Internet.
- On Wikipedia, read about:
-
Exploring Reverse AJAX: Provides an introduction to some
Reverse-Ajax techniques.
- "Cross-domain communications with JSONP, Part 1: Combine JSONP and
jQuery to quickly build powerful mashups" (developerWorks,
February 2009): See how you can combine an obscure cross-domain call
technique (JSONP) and a flexible JavaScript library (jQuery) to build
powerful mashups surprisingly quickly.
- "Build Ajax applications with Ext JS" (developerWorks, July 2008):
Get an overview of the object-oriented JavaScript design concepts behind
Ext JS, and shows how to use the Ext JS framework for rich Internet
application UI elements.
- "Compare JavaScript frameworks" (developerWorks, February 2010):
Get an overview of the frameworks that greatly enhance JavaScript
development.
- "Mastering Ajax, Part 2: Make asynchronous requests with JavaScript
and Ajax" (developerWorks, January 2006): Learn how to use Ajax
and the XMLHttpRequest object to create a request/response model that
never leaves users waiting for a server to respond.
- "Create Ajax applications for the mobile web" (developerWorks,
March 2010): Understand how to build cross-browser smartphone Web
applications using Ajax.
- "Where
and when to use Ajax in your applications" (developerWorks,
February 2008): See how you can use Ajax to improve your websites while
avoiding bad user experiences.
- "Improve the performance of web 2.0 applications" (developerWorks,
December 2009): Explore different browser-side cache mechanisms.
- "Introducing
JSON" (JSON.org): Get an introduction to JSON syntax.
-
developerWorks Web
development zone: Find articles covering various Web-based
solutions.
-
developerWorks podcasts: Listen to interesting interviews and
discussions for software developers.
-
developerWorks technical events and webcasts: Stay current with
developerWorks technical events and webcasts.
Get products and technologies
-
Jetty: Get Jetty, a web server
and javax.servlet container, plus support for WebSockets.
- Apache Tomcat
Advanced I/O documentation: Get valuable links, a User Guide,
Reference, and Apache Tomcat Development instructions.
-
Grizzly NIO Framework: To help you
take advantage of the Java NIO API.
-
Grizzly Comet
Sample: See the changes you'll need to make to existing
applications before building a new one from scratch.
-
Glassfish Application Server: Get the main GlassFish Server Open
Source Edition.
-
Socket.IO Java:
Get the original project and the most updated Ovea's fork.
- Apache Maven: Get Maven, a software
project management and comprehension tool.
-
Java Development Kit, Version 6: Get the Java Platform, Standard
Edition (Java SE), which lets you develop and deploy Java applications on
desktops and servers, as well as in today's demanding embedded
environments.
- Try
out IBM software for free. Download a trial version, log into an
online trial, work with a product in a sandbox environment, or access it
through the cloud. Choose from over 100 IBM product trials.
Discuss
- Participate in the discussion forum.
- Create your developerWorks profile today and setup a watchlist on Reverse Ajax. Get connected and stay
connected with developerWorks community.
- Find other developerWorks members interested in web development.
- Share what you know: Join one of our developerWorks groups focused on web
topics.
- Roland Barcia talks about Web 2.0 and middleware in his blog.
- Follow developerWorks' members' shared bookmarks on web topics.
- Get answers quickly: Visit the Web 2.0 Apps forum.
- Get answers quickly: Visit the Ajax forum.

Mathieu Carbou, a Java web architect and consultant at Ovea, provides services and development solutions. He is a committer and leader of several open source projects, a speaker, and a leader of Montreal's Java User Group. Mathieu has a strong background in code design and best practices, and is a specialist of event-driven web development from the client side to the back end. He focuses on providing event-driven and messaging solutions in highly scalable web applications. Check out his blog.




