Today, 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.
In this article, learn how to implement Reverse Ajax using WebSockets. Code examples help illustrate WebSockets, FlashSockets, constraints on the server side, request-scoped services, and pausing long-lived requests. 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 the article, you will also need the latest version of Maven and the JDK (see Resources).
WebSockets, which emerged in HTML5, is a much more recent Reverse Ajax technique than Comet. WebSockets enables bi-directional, full-duplex communication channels, and many browsers (Firefox, Google Chrome, and Safari) already support it. The connection is opened through an HTTP request, called a WebSockets handshake, with some special headers. The connection is kept alive, and you can write and receive data in JavaScript as if you were using a raw TCP socket.
A WebSocket URL is started by typing ws:// or
wss:// (on SSL).
The timeline in Figure 1 shows communication using WebSockets. An HTTP handshake is sent to the server with specific headers. Then, a type of socket is made available either on the server or on the client side in JavaScript. This socket can be used to asynchronously receive data through an event handler.
Figure 1. Reverse Ajax with WebSockets
There is a WebSocket example in the downloadable source code for this article. When you run the example, you should see output similar to Listing 1. It shows how events occurred on the server side and immediately appeared on the client side as well. When the client sends some data, the server echoes it back to the client.
Listing 1. WebSocket sample in JavaScript
[client] WebSocket connection opened [server] 1 events [event] ClientID = 0 [server] 1 events [event] At Fri Jun 17 21:12:01 EDT 2011 [server] 1 events [event] From 0 : qqq [server] 1 events [event] At Fri Jun 17 21:12:05 EDT 2011 [server] 1 events [event] From 0 : vv |
Typically, in JavaScript you would use WebSockets as demonstrated in Listing 2, if your browser supports it.
Listing 2. JavaScript client code
var ws = new WebSocket('ws://127.0.0.1:8080/async');
ws.onopen = function() {
// called when connection is opened
};
ws.onerror = function(e) {
// called in case of error, when connection is broken in example
};
ws.onclose = function() {
// called when connexion is closed
};
ws.onmessage = function(msg) {
// called when the server sends a message to the client.
// msg.data contains the message.
};
// Here is how to send some data to the server
ws.send('some data');
// To close the socket:
ws.close();
|
The data that is sent and received can be of any type. WebSockets can be viewed like TCP sockets, so it's up to the client and server to know which type of data is being sent through. The example here is sending JSON strings.
When the JavaScript WebSocket object is created, you should see the WebSocket-specific headers if you look deeper in the HTTP requests in your browser's console (or Firebug) for the handshake. Listing 3 shows an example.
Listing 3. Sample HTTP request and response headers
Request URL:ws://127.0.0.1:8080/async Request Method:GET Status Code:101 WebSocket Protocol Handshake Request Headers Connection:Upgrade Host:127.0.0.1:8080 Origin:http://localhost:8080 Sec-WebSocket-Key1:1 &1~ 33188Yd]r8dp W75q Sec-WebSocket-Key2:1 7; 229 *043M 8 Upgrade:WebSocket (Key3):B4:BB:20:37:45:3F:BC:C7 Response Headers Connection:Upgrade Sec-WebSocket-Location:ws://127.0.0.1:8080/async Sec-WebSocket-Origin:http://localhost:8080 Upgrade:WebSocket (Challenge Response):AC:23:A5:7E:5D:E5:04:6A:B5:F8:CC:E7:AB:6D:1A:39 |
All of the headers are used by the WebSocket handshake to authorize and set up the long-lived connection. The WebSocket JavaScript object also contains two useful properties:
-
ws.url - Returns the URL of the WebSocket server.
-
ws.readyState - Returns a value of the current connection state:
- CONNECTING = 0
- OPEN = 1
- CLOSED = 2
On the server side, handling WebSockets is a little more complicated. There is not (yet) a Java specification to support WebSockets in a standard way. To use the WebSockets features of the web container (for example, Tomcat or Jetty), you have to tightly couple your application code to the container-specific library that enables you to access the WebSockets feature.
The example found in the websocket folder of the sample code uses the Jetty's WebSocket API since we're using a Jetty container. Listing 4 shows the WebSocket handler. (Part 3 of this series will use different back-end WebSocket APIs.)
Listing 4. WebSocket handler for a Jetty container
public final class ReverseAjaxServlet extends WebSocketServlet {
@Override
protected WebSocket doWebSocketConnect(HttpServletRequest request,
String protocol) {
return [...]
}
}
|
With Jetty, there are several ways to handle a WebSocket handshake. The
easier way is to subclass Jetty's
WebSocketServlet and implement the
doWebSocketConnect method. This method asks you
to return an instance of the Jetty's WebSocket interface. You have to
implement the interface and return a sort of endpoint representing the
WebSocket connection. Listing 5 provides a sample.
Listing 5. WebSocket implementation sample
class Endpoint implements WebSocket {
Outbound outbound;
@Override
public void onConnect(Outbound outbound) {
this.outbound = outbound;
}
@Override
public void onMessage(byte opcode, String data) {
// called when a message is received
// you usually use this method
}
@Override
public void onFragment(boolean more, byte opcode,
byte[] data, int offset, int length) {
// when a fragment is completed, onMessage is called.
// Usually leave this method empty.
}
@Override
public void onMessage(byte opcode, byte[] data,
int offset, int length) {
onMessage(opcode, new String(data, offset, length));
}
@Override
public void onDisconnect() {
outbound = null;
}
}
|
To send a message to the client, you write to the outbound, as shown in Listing 6:
Listing 6. Sending a message to the client
if (outbound != null && outbound.isOpen()) {
outbound.sendMessage('Hello World !');
}
|
To disconnect the client and close the WebSocket connection, use
outbound.disconnect();.
WebSockets is a very powerful way to implement a bi-directional communication with no latency. It is supported by Firefox, Google Chrome, Opera, and other modern browsers. According to the jWebSocket website:
- Chrome includes native WebSockets since 4.0.249.
- Safari 5.x includes native WebSockets.
- Firefox 3.7a6 and 4.0b1+ includes native WebSockets.
- Opera includes native WebSockets since 10.7.9067.
For more information about jWebSocket, see Resources.
WebSockets provides powerful, bi-directional, low-latency, and easy-to-handle errors. There isn't a lot of connection, like Comet long polling, and it doesn't have the drawbacks of Comet streaming. The API is also very easy to use directly without any additional layers, compared to Comet, which requires a good library to handle reconnection, timeout, Ajax requests, acknowledgments, and the optionally different transports (Ajax long polling and jsonp polling).
Drawbacks of WebSockets include:
- It is a new specification from HTML5, so it isn't yet supported by all browsers.
- No request scope. Since WebSockets is a TCP socket and not an HTTP
request, request-scoped services, like Hibernate's
SessionInViewFilter, cannot be used easily. Hibernate is a persistence framework that provides a filter to surround an HTTP request. When the request begins, it sets up a contest (containing transactions and JDBC connection) bound to the request thread. When the request finishes, the filter destroys this contest.
For browsers that don't support WebSockets, some libraries have the ability to fall back to FlashSockets (sockets through Flash). The libraries usually provide the same official WebSocket API, but they implement it by delegating calls to a hidden Flash component included on the website.
FlashSockets transparently provide the WebSockets feature, even on browsers that do not support HTML5 WebSockets.
FlashSockets has the following drawbacks:
- It requires installation of the Flash plug-in (usually, all browsers have it).
- It requires that the port 843 of the firewall is opened so the Flash
component can make an HTTP request to retrieve a policy file
containing domain authorization.
If the port 843 is unreachable, the library should fall back or give an error. All this processing takes time (up to 3 seconds, depending on the library), which will slow down the website.
- If the client is behind a proxy server, the connection to port 843 might be refused.
The WebSocketJS project provides a bridge. It requires at least Flash 10 and brings WebSockets support to Firefox 3, Internet Explorer 8, and Internet Explorer 9.
Compared to Comet, WebSockets brings many benefits. In day-to-day development, clients supporting WebSockets are faster and generate fewer requests (and thus consume less bandwidth). But, since not all browsers are supporting WebSockets, the best choice for a Reverse Ajax library would be one that's capable of detecting WebSockets support and falling back to Comet (long polling) if WebSockets are not supported.
Since the two techniques are necessary to get the best of all browsers and remain compatible, it is recommended that you use a client JavaScript library that provides a layer of abstraction on top of these techniques. Part 3 and Part 4 of this series will explore some libraries, and Part 5 will show their application. On the server side, things are a little more complicated, as discussed in the next section.
Reverse Ajax constraints on the server side
Now that you have an overview of the Reverse Ajax solutions available on the client side, let's look at Reverse Ajax solutions on the server. Up to now, the examples have used mainly client JavaScript code. On the server side, to accept Reverse Ajax connections, some techniques require specific features to handle long-lived connections compared to the short HTTP requests you're familiar with. For better scaling, a new threading model should be used that requires a specific API in Java to be able to pause requests. Also, for WebSockets, you have to correctly manage the scope of the services used in the application.
Threading and non-blocking I/O
Usually, a web server associates one thread, or one process, per incoming HTTP connection. This connection can be persistent (keep-alive) so that several requests go through the same connection. In this article's example, the Apache web server can be configured with the mpm_fork or mpm_worker models to change this behavior. Java web servers (application servers are included—this is the same thing) typically use one thread for each incoming connection.
Spawning a new thread leads to memory consumption and resource wasting because it's not guaranteed that the spawned thread will be used. The connection may be up, but no data from either the client or the server is sent. Whether this thread is used or not, it consumes memory and CPU resources for scheduling and contest switches. And, when configuring a server using a threading model, you usually have to configure a thread pool (set a maximum number of threads to process incoming connections). If this value is misconfigured and is too low, you'll end up with a thread starvation issue; requests will wait until a thread is available to process them. Response time will be slow when the maximum concurrent connection is reached. On the other hand, configuring a high value may lead to an out of memory exception. The spawning of too many threads would consume all the heap size of the JVM and lead to a server crash.
Java recently introduced a new I/O API called a non-blocking I/O. This API uses a selector that avoids binding a thread each time a new HTTP connection is made to the server. When data is coming, an event is received and a thread is allocated to process the request. Thus, this is called a thread-per-request model. It allows web servers, such as WebSphere and Jetty, to scale and handle a growing number of user connections with a fixed number of threads. With the same hardware configuration, web servers running in this mode scale much better than in the thread-per-connection mode.
In his blog, Philip McCarthy (author of Comet and Reverse Ajax) has an interesting benchmark about the scalability of the two threading models (see Resources for a link). In Figure 2 you'll find the same pattern: a threading model stops working with too many connections.
Figure 2. Benchmark of threading models
The thread-per-connection model (Threads in Figure 2) typically has a better response time, since all threads are up, ready, and waiting, but it stops serving when the connection number is too high. In the thread-per-request model (Continuations in Figure 2), a thread is used to serve the arrived request, and the connection is handled through an NIO selector. The response time may be a little slower, but threads are recycled and thus this solution scales better with a lot of connections.
To understand how threading works behind the scenes, imagine a LEGO™ block as the selector. Each incoming connection arrives in this LEGO block and is identified by a pin. The LEGO block/selector will have as many pins (as many keys) as connections. Then, only one thread is necessary to iterate over the pins as it waits for new events to happen. When something happens, the selector thread retrieves the keys for the events that occurred and a thread can be used to serve the incoming request.
The "Rox Java NIO Tutorial" has a good example of using NIO in Java (see Resources).
Many frameworks provide services, or filters, that handle a web request arriving into a servlet. For example, a filter will:
- Bind a JDBC connection to a request thread so only one connection is used for the whole request.
- Commit the changes at the end of the request.
Another example is the Guice Servlet extension of Google Guice (a dependency injection library). Like Spring, Guice can bind services in a request scope. An instance will be created once, at most, for each new request (see Resources for more information).
Typical usage would involve caching a user object retrieved from a repository (for example, a database) in the request by using the user id taken from the clustered HTTP session. In Google Guice, you might have code similar to Listing 7.
Listing 7. Request-scoped binding
@Provides
@RequestScoped
Member member(AuthManager authManager,
MemberRepository memberRepository) {
return memberRepository.findById(authManager.getCurrentUserId());
} |
When a member gets injected in a class, Guice will try to fetch it from the request. If not found, it will execute the repository call and place the result in the request.
Request-scoped services can be used with any Reverse Ajax solution except for WebSockets. Any other solution relies on HTTP requests, either short or long-lived, so each request goes through the servlet dispatching system and filters are executed. When completing a paused (long-lived) HTTP request, you'll see in subsequent parts of this series that there's also an option to make the request go through the filter chain again.
For WebSockets, data arrives directly on the
onMessage callback, like in a TCP socket. There
has not been any HTTP request sent for this data to arrive, so there is no
request contest from which to get and store scoped objects. Thus, using
services requiring scoped objects from an
onMessage callback will fail.
The guice-and-websocket sample in the downloadable
source code shows how to bypass the limitation and still use
request-scoped objects in an onMessage
callback. When you run the sample and click each button on the web page to
test an Ajax call (request-scoped), a WebSocket call, and a WebSocket call
with a simulated request scoped, you will get the output shown in Figure 3.
Figure 3. Output of a WebSocket handler using request-scoped services
You might encounter such issues whether you're using:
- Spring.
- Hibernate.
- Any other framework requiring request scoped or a per-request model,
such as
OpenSessionInViewFilter. - Any system using the
ThreadLocalfacility to scope variables to a request thread within a filter and access them later.
Guice has an elegant resolution, as shown in Listing 8:
Listing 8. Simulate a request-scope from the WebSocket
onMessage callback
// The reference to the request is hold when the
// doWebSocketMethod is called
HttpServletRequest request = [...]
Map<Key<?>, Object> bindings = new HashMap<Key<?>, Object>();
// I have a service which needs a request to get the session,
// so I provide the request, but you could provide any other
// binding that may be needed
bindings.put(Key.get(HttpServletRequest.class), request);
ServletScopes.scopeRequest(new Callable<Object>() {
@Override
public Object call() throws Exception {
// call your repository or any service using the scoped objects
outbound.sendMessage([...]);
return null;
}
}, bindings).call();
|
With Comet, there is another hurdle. How can a server pause a long-lived request without impacting performance, and then recover and complete it as soon as a server event comes?
Obviously, you can't simply hold the request and response, which could cause thread starvation and high memory consumption. Pausing a long-polling request, among non-blcoking I/O, requires a specific API. In Java, the Servlet 3.0 specification provides such an API (see Part 1 of this series). Listing 9 shows an example.
Listing 9. Defining an asynchronous servlet with Servlet 3.0
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:j2ee="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml
/ns/j2ee/web-app_3.0.xsd">
<servlet>
<servlet-name>events</servlet-name>
<servlet-class>ReverseAjaxServlet</servlet-class>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>events</servlet-name>
<url-pattern>/ajax</url-pattern>
</servlet-mapping>
</web-app>
|
When you've defined an asynchronous servlet, you can use the Servlet 3.0 API to suspend and resume a request, as shown in Listing 10:
Listing 10. Suspending and resuming a request
AsyncContext asyncContext = req.startAsync();
// Hold the asyncContext reference somewhere
// Then when needed, in another thread you can resume or complete
HttpServletResponse req =
(HttpServletResponse) asyncContext.getResponse();
req.getWriter().write("data");
req.setContentType([...]);
asyncContext.complete();
|
Prior to Servlet 3.0, each container had, and still has, its own mechanism. Jetty's continuations is a well-known example; many Reverse Ajax libraries in Java depend upon Jetty's continuations. This is not a show-stopper and does not require that you run your application in a Jetty container. The API is clever enough to detect the container you're running and fall back to the Servlet 3.0 API, if available, when run in another container such as Tomcat or Grizzly. This is true for Comet, but if you want to take advantage of WebSockets, you currently have no choice but to use the container-specific features.
The Servlet 3.0 specification is not yet released, but a lot of containers are already implementing the API since it is a standard way of doing Reverse Ajax.
WebSockets is a very powerful Reverse Ajax solution, despite a few drawbacks. It's not currently implemented on all browsers, and isn't easy to use on the server side in Java without the help of a Reverse Ajax library. Because you aren't using a standard request-response style, you cannot rely on the filter chain execution for scopes. Comet and WebSockets require server-side-specific features of the containers, so you need to pay attention when using a recent container or it will not scale.
Stay tuned for Part 3 of this series, which will explore the different APIs on the server side for Comet and WebSockets. Also learn about Atmosphere, a Reverse Ajax framework.
| Description | Name | Size | Download method |
|---|---|---|---|
| Article source code | reverse_ajaxpt2_source.zip | 14KB | HTTP |
Information about download methods
Learn
- "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.
- jWebSocket-supported browsers: Learn all about the browsers
supported by jWebSocket and Flash socket bridge.
- 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" (Google Maps .Net Control blog, August
2006): Get 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.
- "Cross-Origin Resource Sharing (CORS)" specification (W3C, July
2010): Learn more about this mechanism, which allows XHR to perform
cross-domain requests.
- "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
XMLHttpRequestobject 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 Web sites 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
-
WebSocketJS (WebSocket
Flash Bridge): Get this HTML5 WebSocket implementation powered by
Flash.
-
Google Guice: Get
Google Guice, a lightweight dependency injection framework for Java 5 and
above.
-
Jetty: Get Jetty, a web server
and javax.servlet container, plus support for WebSockets.
- 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
- Create your developerWorks profile today and setup a watchlist on 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.




