Using Atmosphere's JQuery Plugin to Build Applications Supporting Both Websocket and Comet
Join the DZone community and get the full member experience.
Join For FreeUntil all Browsers and WebServers properly support the Websocket protocol, it will be difficult to write portable applications. Not anymore, using the new JQuery Atmosphere Plugin which is able to auto-detect which transport (Websocket or Comet) to use based on what the Browser and Web Server support.
Since the Websocket protocol is relatively new, not all web servers and browser support it which means writing a websocket application that will always lock your users with a limited set of browsers and web server. For example, as of today, only Jetty 8, Resin 4 and GlassFish 3.1 support Websocket on the server side, and Chrome 4 and Safari 5 on client side. Eventually they may all support the protocol, but it will take a couple of years before it happens. Not to say that Internet Explorer will probably implement a subset of it, or a broken version just to continue what they started with IE 6. On the server side, as I discussed here, it will take years before the Java Community Process (JCP) comes up with a specification for all Java web servers. The good news is that we already have a solution for the server side named Atmosphere, which allows the creation of portable Async/Real Time applications supporting both Websocket and/or Comet at the same time.
Does portable library exists on the client side, e.g being able to write application that can use Websocket when available, and fallback/downgrade to use Comet technique (http streaming or long polling)? As far as I can tell, there is no such open source library available today supporting both Websocket and Comet (feel free to point me to them). Not anymore, with the new Atmosphere JQuery Plugin.
Introducing the Atmosphere JQuery Plug In
The Atmosphere JQuery Plugin easily allows you to write asynchronous and real time applications without the need to wait for Websocket adoption. The Atmosphere JQuery Plug In can be used with any webserver that supports Websocket and Comet. The Atmosphere Framework is not mandatory on the server side, but you will miss something if you don't use it as I will demonstrate in this post. That means you can use it with node.js or any existing Comet framework like Grizzly Comet, Jetty Continuation and Servlet 3,0 Async.
Using it with a server side application built on top of Atmosphere allows the plug in to detect what the Web Server supports and optimally select Websocket or any Comet technique. As an example, you can set the default transport to Websocket, deploy in Jetty 8 and use Chrome to run your application. In that case, the Websocket protocol will be used. Now if you try with Firefox, the Plugin will downgrade to Comet without any changes required on either client or server side. You can also deploy your application in Tomcat 7, which doesn't support Websocket and still the application will work without any change. The great news is as soon as Tomcat starts supporting Websocket, your application will still work without requiring any code changes, and will upgrade automatically and use the Websocket protocol.
Writing a PubSub application that supports both Websocket and Comet.
To demonstrate how the Atmosphere JQuery Plug In works, let's write a simple PubSub application that can support WebSocket and Comet (long-polling and http streaming). If you can't wait, you can browse the entire code here. On the client side, let's create a very simple HTML page which allow us to:
- Select the topic we want to subscribe to.
- Select the transport to use: Auto-Detect, Websocket, Long-Polling or Http Streaming. Auto-Detect means the Atmosphere JQuery Plug In will try to pick the best one for us.
- Publish message to the topic we have subscribed to.
The goal here is to write a simple PubSub that you can deploy anywhere, use with any browsers without having to care about the transport used. Something like:
First, the user needs to enter a topic. Next is to pick the transport to use to communicate to the Web Server. By default, let's use Websocket and fallback to http-streaming in case the browser or the server isn't supporting Websocket.
$.atmosphere.subscribe(
document.location.toString() + 'pubsub/' + getElementByIdValue('topic'),
callback : null
$.atmosphere.request = {transport: getElementByIdValue('transport')});
The subscribe function takes three parameters:
- The location of the server application, including the topic value. More details about the server side in the next section.
- A function callback which will get invoked when the server is receiving topic's messages.
- A Request object that can be used to configure the Plug In.
The Request object is where you can configure the Plug In. The object default values are:
connected: false,
timeout: 60000,
method: 'GET',
headers: {},
contentType : "text/html;charset=ISO-8859-1",
cache: true,
async: true,
ifModified: false,
callback: null,
dataType: ' ',
url : url,
data : ' ',
suspend : true,
maxRequest : 60,
logLevel : 'info',
requestCount : 0,
fallbackTransport : 'long-polling',
transport : 'websocket'
This is where you can configure the HTTP request similar to JQuery.ajax() function, with extra configuration like transport, fallbackTransport and callback. With the above configuration, the Plug In will first try to use Websocket and if the client of server (or both) isn't supporting Websocket, will use the fallbackTransport as the second choice. Next is to define a callback which will be invoked when the server sent us update about our subscribed topic:
function callback(response)
{
var data = response.responseBody
if (data.length > 0) {
$('ul').prepend($('<li></li>').text(" Message Received: " + data + " using transport: " + response.transport));
}
}
The important piece here is the response object, which is defined as:
status: 200,
responseBody : ' ',
headers : [],
state : "messageReceived",
transport : "websocket",
push : [],
error: null
The responseBody contains what the server has just sent us. You can also retrieve some headers depending on which transport is used, if there is an error, etc. The push function is a key piece here as it allow you to publish message to the Web Server message. The Plug In will either re-use the current transport to push messages to the Web Server, or open a new one if the current transport doesn't support it. All of this done magically by the Plug In. For our sample, the push function is defined as:
response.push(document.location.toString() + 'pubsub/' + getElementByIdValue('topic'),
null,
$.atmosphere.request = {data: 'message=' + getElementByIdValue('phrase') })
This function will be invoked every time you click on the "Push Message" button.
Make it fun
As a try, you can deploy the application on Jetty 8, use Chrome and Firefox to see how it works (download here). You can switch transport on the fly be selecting the transport using the drop down menu. If you use Chrome, all transport will works where Firefox fake Websocket (using the default fallbackTransport value). Do the same on Tomcat and now Chrome will still works event if you set the transport to Websocket.
Humm...what about the server side?
Without going into the details of how to write an Atmosphere application (download the white paper or search this blog), the server side for this sample JUST consists of:
@Path("/pubsub/{topic}")
@Produces("text/html;charset=ISO-8859-1")
public class JQueryPubSub {
private @PathParam("topic") Broadcaster topic;
@GET
public SuspendResponse<String> subscribe() {
return new SuspendResponse.SuspendResponseBuilder<String>()
.broadcaster(topic)
.outputComments(true)
.addListener(new EventsLogger())
.build();
}
@POST
@Broadcast
public Broadcastable publish(@FormParam("message") String message) {
return new Broadcastable(message, "", topic);
}
}
The mapping is simple:
- Invoking $.atmosphere.subscribe will invoke the subscribe() method on the server side. This method will tells Atmosphere to suspend the connection and create a topic (Broadcaster). The Broadcast is like a queue. As soon as you offer a message to it the message will be sent to all the subscriber of that queue. In our case it means all browser connected to that topic.
- Invoking response.push will invoke the publish() method on the server side. The value will be broadcasted to all subscribed connections, independently of the transport used.
Simple, is it :-) Did you noted that there is no mention of Comet or Websocket on the server side? With the Atmosphere Framework, you write an application without having to care about it.
For any questions or to download Atmosphere JQuery Plug In, go to our main site and use our Nabble forum (no subscription needed), or follow the team or myself and tweet your questions there! You can also checkout the code on Github. Or download our latest presentation to get an overview of what the framework is.
Originally published on jfarcand.wordpress.com
Opinions expressed by DZone contributors are their own.
Comments