Archive
Atmosphere .9 .9 .9 .9 released: Tomcat/GlassFish WebSocket, Netty Framework, Hazelcast, Fluid API, JQuery Optimization
The Atmosphere Framework version 0.9 has been released and contains a lot of new cool features and bugs fixes (around 101!!). This blog will describes the main new features! But first, let’s make it clear: the Atmosphere Framework has been designed to transparently support Comet and WebSocket with both client and server components. That means you don’t have to care if a server supports WebSocket or Comet, if a Browser supports WebSocket or not. You write your application and Atmosphere will pick the best transport for you, TRANSPARENTLY! As an example, all applications written with Atmosphere deployed on Jetty can now be deployed AS-IT-IS in Tomcat and automatically use the new Tomcat’s WebSocket API. Yes, you read it correctly: WITHOUT any changes!
Performance and Massive Scalability?
Atmosphere is live for 3 months of WSJ.com and Smartmoney.com and serves millions of requests using WebSocket, Long-Polling and JSONP => Atmosphere is production ready! And there is much more live Web Site using Atmosphere…I just can list them here.
Adoption
Atmosphere is available in mostly all available framework, either as a plugin or extension. If your framework isn’t supporting Atmosphere, complains to them and tell them it is really simple to add support!
jQuery.atmosphere.js new API
The Atmosphere Javascript client has been rewritten in order to allow a better integration with the WebSocket API and auto detection of the best transport to use depending of server capacity. For example, atmosphere.js always try to use WebSocket as the initial transport and will transparently negotiate with the server to see which transport to use. If the server isn’t supporting WebSocket, atmosphere.js will transparently use HTTP (long-polling, streaming or JSONP). On both client and server side, your application doesn’t need to implement anything in order to work. API wise, function support has been added to make it really easy to write Javascript client. New functions available are onOpen, onReconnect, onClose, onError. As an example, a chat client supporting WebSocket and Comet will only consist of:
var socket = $.atmosphere; var request = { url: document.location.toString() + 'chat', contentType : "application/json", logLevel : 'debug', transport : 'websocket' , fallbackTransport: 'long-polling'}; request.onOpen = function(response) { ... }; request.onReconnect = function (request, response) { ... }; request.onMessage = function (response) { var message = response.responseBody; ... }; request.onError = function(response) { ... }; var subSocket = socket.subscribe(request);
A lot of improvements has been made to hide Browser specific implementation: the famous Internet Explorer works transparently and supported version are 6/7/8/9 and always pick the best transport.
Native Tomcat WebSocket
Starting with Tomat 7.0.27, Atmosphere will detect the new Tomcat WebSocket API and use it by default. That means atmosphere.js will negotiate the WebSocket protocol and use it. That also means as soon as you deploy your application from previous Tomcat version to 7.0.27, WebSocket will transparently used. As an example, the chat client described above will transparently communicates using WebSocket to its associated Server component
@Path("/")
@Produces("application/json")
public class ResourceChat {
@Suspend
@GET
public String suspend() {
return "";
}
@Broadcast(writeEntity = false)
@POST
public Response broadcast(Message message) {
return new Response(message.author, message.message);
}
}
Now you can compare the number of line the Atmosphere Chat (support all transports) requires versus the Tomcat Chat (which, btw, only support WebSocket). Much more simpler with Atmosphere!
Netty Framework Support
YES, you read it correctly. Atmosphere has been refactored and can now be run on top of non Servlet Container! NettoSphere is the runtime that allow any existing Atmosphere application to run transparently on top of the Netty Framework. NettoSphere also support WebSocket and any existing applications will work without any change. As simple as
Nettosphere server = new Nettosphere.Builder().config(
new Config.Builder()
.host("127.0.0.1")
.port(8080)
.staticResourcePath("/Users/jfarcand/")
.resource(MyResource.class)
.build())
.build();
server.start();
GlassFish 3.1.2 WebSocket Support
The latest GlassFish release ships with an updated WebSocket implementation and Atmosphere makes use of it. As with Tomcat, Netty and Jetty, Atmosphere applications can be deployed without any modifications.
JAX-RS 2.0 Async API Support
The work in progress JAX-RS 2.0 specification introduces a new async API (which strangely looks like Atmosphere’s own API
). The current incarnation of the API is really limited and I really hope the Spec EG will reconsider their decision. But whatever decision is made, Atmosphere supports the new annotation and the ExecutionContext class. The chat application would looks like
// You can use that object to suspend as well.
@Context ExecutionContext ctx;
@Suspend() // Not the Atmosphere's Suspend
@GET
public String suspend() {
// ctx.suspend
return "";
}
@POST
@Broadcast(writeEntity = false)
public Response broadcast(Message message) {
return new Response(message.author, message.message);
}
You can compare with the current JAX-RS samples Chat, that only support long-polling (much more complex). The JAX-RS Async API lack of listener is a major issue IMO. As an example, Atmosphere’s Suspend annotation suppors event listeners which can be used to track the current state of the connection. As an example, with the current incantation of JAX-RS Async API, an application cannot be notified when a client drop the connection and hence the application’s resources can never be cleaned. That can easily produces out of memory error. Another problem is with the JAX-RS Async API it is quite complex to implement http-streaming because some browsers required some padding data before the response (WebKit and IE). In conclusion: since Atmosphere runs transparently in all WebServer, there are no good reasons to move to JAX RS 2 Async API (which will only runs on top of Servlet 3.0 WebServer). Instead use the API with Atmosphere and get portability, WebSocket and transport negotiation.
Native WebSocket Application
Atmosphere supports native WebSocket development, e.g application that only support WebSocket. A simple pubsub WebSocket will looks like
public class WebSocketPubSub extends WebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(WebSocketPubSub.class); @Override public void onTextMessage(WebSocket webSocket, String message) { AtmosphereResource r = webSocket.resource(); Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo()); if (message != null && message.indexOf("message") != -1) { b.broadcast(message.substring("message=".length())); } } @Override public void onOpen(WebSocket webSocket) { // Accept the handshake by suspending the response. AtmosphereResource r = webSocket.resource(); Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo()); r.setBroadcaster(b); r.addEventListener(new WebSocketEventListenerAdapter()); r.suspend(-1); }
. The client would consists of
var request = { url : document.location.toString() }; request.onMessage = function (response) { if (response.status == 200) { var data = response.responseBody; if (data.length > 0) { // print the message } } } subSocket = socket.subscribe(request);
You can also use the WebSocket API directly, but atmosphere.js does a lot more (reconnection, proper API use, etc.)
Hazelcast support
Atmosphere can now be clustered/clouded using Hazelcast. As simple as:
@Path("/pubsub/{topic}")
@Produces("text/html;charset=ISO-8859-1")
public class JQueryPubSub {
private @PathParam("topic") HazelcastBroadcaster topic;
@GET
public SuspendResponse subscribe() {
return new SuspendResponse.SuspendResponseBuilder()
.broadcaster(topic)
.outputComments(true)
.addListener(new EventsLogger())
.build();
}
@POST
@Broadcast
public Broadcastable publish(@FormParam("message") String message) {
return new Broadcastable(message, "", topic);
}
}
The broadcast operations will be distributed to all Hazelcast server available. You can masively scale your WebSocket application by just using the Hazelcast plugin! Don’t like Hazelcast? You can do the same using Redis/JMS/XMPP or JGroup broadcaster as well.
Miscellaneous
Tons of new features and improvements (101 issues fixed). Amongst them
- Improved Fluid API: The API of AtmosphereResource, Broadcaster and AtmosphereEvent has been improved to make DSL more easier.
- JGroup Support Improved
- Sprint Integration Improved and Sample added
- Build-in message size tracking
- No web.xml configuration
- OSGI improvements
1.0.0: Coming SOON, SwaggerSocket around the corner!
Atmosphere is fully powered by Wordnik and we are working hard to make the 1.0.0 release happens soon (End of May 2012). At Wordnik we are using Atmosphere a lot and soon we will release our REST over WebSocket protocol (called SwaggerSocket, which integrate with Swagger). New features will includes an Atmosphere Java Client that will mimic the Javascript functionality, Terracotta supports, etc (see a detailed list here).
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Google Group forum, follow the team or myself and tweet your questions there! .
NettoSphere: A WebSocket and HTTP server based on the Atmosphere and Netty Framework
Introducing NettoSphere, A Java WebSocket and HTTP server based on the Atmosphere and Netty Framework. NettoSphere easily allow the creation of WebSocket and/or Comet applications. This blog will quickly demonstrate how simple and fast it take to build WebSocket application.

If you don’t know what is Atmosphere, take a quick look at this blog.
NettoSphere supports all Atmosphere API, which means you can write REST style application via Jersey or pure AtmosphereHandler. You start the server by doing:
val server : NettoSphereServer = new NettyAtmosphereServer.Builder.config( new Config.Builder() .host("127.0.0.1") .port(8080) .resource(classOf[MyWebSocketEchoProtocol]) .build) .build.start
As an example, you can write bi-directional WebSocket application by adding the following WebSocketProtocol:
class MyWebSocketEchoProtocol extends WebSocketProtocol with Serializable { override def onOpen(webSocket: WebSocket) { logger.info("Client's connected {}", webSocket.resource.getRemoteAddr ) } override def onMessage(webSocket: WebSocket, message: String) { webSocket.write(message) } }
Now client wise, any WebSocket library will works (like the jQuery.atmosphere.js, wCS or AHC), or using bare metal WebSocket API
function showMessage(text) { document.getElementById('message').innerHTML = text; } var ws = new WebSocket('ws://' + document.location.host + '/echo'); ws.onopen = function() { showMessage('Connected!'); }; ws.onclose = function() { showMessage('Closed'); }; ws.onmessage = function(msg) { showMessage(msg.data); };
That’s it. That doesn’t have to be complicated!! For more information, go to the NettoSphere main page or ping me on Twitter!
Writing Client/Server WebSocket Application using Scala
Today I will explains how to quickly write a WebSocket application in Scala. I will show how easy it is to write both client and server side. For the client I will use the wCS library, and for the server I will use the Atmosphere’s WebSocket Framework. If you expect something complex, don’t read this blog!
OK let’s write a really simple application which echo messages received to all connected clients. Messages can be initiated by the client or by the server itself. In order to achieve that, we will use the Atmosphere Framework. If you aren’t familiar with Atmosphere, take a look at this introduction. What we need to define is a Scala class that will be invoked by the framework when a WebSocket message is received. With Atmosphere, it as simple as:
import javax.ws.rs.{POST, Path}
import org.atmosphere.annotation.Broadcast
@Path("/")
class Echo {
/**
* Broadcast/Publish the WebSocket messages to all connection WebSocket clients.
*/
@POST
@Broadcast
def echo(echo : String) : String = {
echo
}
}
The echo method will be invoked with a String arguments who represent a WebSocket message. The message will be distributed using an Atmosphere Broadcaster, which can be seen as a bi-directional channel of communication between clients and server. Looking for more code? Well, with Atmosphere you don’t need more on the server side as the framework take care of the WebSocket’s handshake and all the protocol details you don’t want to spend time on it.
Now on the client side, let’s use the wCS library (Asynchronous I/O WebSocket Client for Scala). First, let’s open a connection to the server
val w = new WebSocket
w.open("ws://127.0.0.1/")
Once the WebSocket connection is established, we can now send message (as String or Bytes).
w.send("foo")
To receive WebSocket messages, all we need to do is to pass a Listener that will be invoked when the server echo messages
w.listener(new TextListener() {
override def onMessage(s : String) {
// Do something with the message
}
})
We can switch at any moment between String and Bytes, and associate as many Listener as we can. Note that the library is fully asynchronous and never the send operation is “non blocking”. We can fluidly write the code above by just doing:
val w = new WebSocket
w.listener(new TextListener() {
override def onOpen(){
// do something
}
override def onMessage(message: String) {
// do something
}
override def onClose() {
// do something
}
}).open("ws://127.0.0.1").send("foo")
That’s all. You just wrote your first WebSocket client/server application using Scala! For more information, ping me on Twitter!
Writing WebSocket Clients using AsyncHttpClient
The AsyncHttpClient version newly released 1.7.0 now supports WebSocket. Both Netty and Grizzly provider supports the latest version of the specification.
Like HTTP support with AHC, WebSoket is quite simple. Starting with AHC 1.7, a new interface called UpgradeHandler is available to the client so any kind of protocol can be used. You can event replace the actual WebSocket implementation with your in case you don’t like mine
public interface UpgradeHandler<T> {
/**
* If the HTTP Upgrade succeed (response's status code equals 101),
* the {@link AsyncHttpProvider} will invoke that
* method
*
* @param t an Upgradable entity
*/
void onSuccess(T t);
/**
* If the upgrade fail.
* @param t a {@link Throwable}
*/
void onFailure(Throwable t);
For WebSocket, I wrote a simple one called WebSocketUpgradeHandler which extends the usual AsyncHandler (always required with AHC) and UpgradeHandler. The interesting part is the WebSocketUpgradeHandler.Builder, which allow you to add listeners and WebSocket properties:
/**
* Add a {@link WebSocketListener} that
* will be added to the {@link WebSocket}
*
* @param listener a {@link WebSocketListener}
* @return this
*/
public Builder addWebSocketListener(WebSocketListener listener) {
l.add(listener);
return this;
}
/**
* Remove a {@link WebSocketListener}
*
* @param listener a {@link WebSocketListener}
* @return this
*/
public Builder removeWebSocketListener(WebSocketListener listener) {
l.remove(listener);
return this;
}
/**
* Set the WebSocket protocol.
*
* @param protocol the WebSocket protocol.
* @return this
*/
public Builder setProtocol(String protocol) {
this.protocol = protocol;
return this;
}
/**
* Set the max size of the WebSocket byte message that will be sent.
*
* @param maxByteSize max size of the WebSocket byte message
* @return this
*/
public Builder setMaxByteSize(long maxByteSize) {
this.maxByteSize = maxByteSize;
return this;
}
/**
* Set the max size of the WebSocket text message that will be sent.
*
* @param maxTextSize max size of the WebSocket byte message
* @return this
*/
public Builder setMaxTextSize(long maxTextSize) {
this.maxTextSize = maxTextSize;
return this;
}
/**
* Build a {@link WebSocketUpgradeHandler}
* @return a {@link WebSocketUpgradeHandler}
*/
public WebSocketUpgradeHandler build() {
return new WebSocketUpgradeHandler(this);
}
You can add several type of listeners like WebSocketTextListener, WebSocketByteListener, etc. To create a WebSocket, you just need to do:
AsyncHttpClient c = new AsyncHttpClient();
// or new AsyncHttpClient(new GrizzlyAsyncHttpprovider(config))
WebSocket websocket = c.prepareGet("ws://something:port)
.execute(
new WebSocketUpgradeHandler.Builder().addWebSocketListener(
new WebSocketByteListener() {
@Override
public void onOpen(WebSocket websocket) {
}
@Override
public void onClose(WebSocket websocket) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onMessage(byte[] message) {
}
@Override
public void onFragment(byte[] fragment, boolean last) {
}
}).build()).get();
The AHC Future returned is a WebSocket, and it is returned as soon as the handshake is successful. The WebSocket API is also simple:
public interface WebSocket {
/**
* Sen a byte message.
* @param message a byte message
* @return this
*/
WebSocket sendMessage(byte[] message);
/**
* Send a text message
* @param message a text message
* @return this.
*/
WebSocket sendTextMessage(String message);
/**
* Add a {@link WebSocketListener}
* @param l a {@link WebSocketListener}
* @return this
*/
WebSocket addMessageListener(WebSocketListener l);
/**
* Close the WebSocket.
*/
void close();
}
Conclusion, writing WebSocket is super simple!!! Here is a fully asynchronous echo client
WebSocket websocket = c.prepareGet("ws://localhost:80")
.execute(
new WebSocketUpgradeHandler.Builder()
.addWebSocketListener(new WebSocketTextListener() {
@Override
public void onMessage(String message) {
System.out.println(message);
}
@Override
public void onFragment(String fragment, boolean last) {
}
@Override
public void onOpen(WebSocket websocket) {
websocket
.sendTextMessage("ECHO")
.sendTextMessage("ECHO");
}
@Override
public void onClose(WebSocket websocket) {
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
}).build()).get();
For any questions you can use our Google Group, irc.freenode.net #asynchttpclient or use Twitter to reach me! You can checkout the code on Github as well!
Atmosphere 0.8: Jersey on Steroid, WebSocket Sub Protocol, Native WebSocket, JQuery Plugin CORS, REST over HTTP
The Atmosphere Framework 0.8 version has been released. This is our biggest release ever! This blog will describe the new feature covered by this fantastic release.
Jersey on Steroid with WebSocket
The Jersey Framework can now be fully run on top of a WebSocket connection seamlessly. A single WebSocket connection can now be used to invoke Jersey. That’s open the door to request pipeline and asynchronous processing of REST call transparently. This will be discussed soon in more details, but this feature is implemented via the new WebSocketProtocol API.
Browser WebSocket Support
Atmosphere fully support Opera, Firefox (MozWebSocket), Chrome, Safari and IE 10 Preview WebSocket transparently when used with the Atmosphere JQuery Plug In. Safari on iOS is also supported.
Native WebSocket Support
It is now possible to write native WebSocket application. A simple PubSub application can consist only of:
public AtmosphereRequest onMessage(WebSocket webSocket, String message) {
AtmosphereResource r = (AtmosphereResource) webSocket.resource();
Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo());
b.broadcast(message);
//Do not dispatch to another Container
return null;
}
public void onOpen(WebSocket webSocket) {
// Accept the handshake by suspending the response.
AtmosphereResource r = (AtmosphereResource) webSocket.resource();
Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo());
r.setBroadcaster(b);
r.addEventListener(new WebSocketEventListenerAdapter());
// Keep Alive the WebSocket Connection Forever
r.suspend(-1);
}
public void onClose(WebSocket webSocket) {
webSocket.resource().resume();
}
public void onError(WebSocket webSocket,
WebSocketProcessor.WebSocketException t) {
logger.error(t.getMessage() + " Status {} Message {}",
t.response().getStatus(),
t.response().getStatusMessage());
}
WebSocket Sub Protocol Implementation Support
Writing WebSocket sub protocol on top of a WebSocket connection is now extremely simple, thanks to the WebSocketProtocol API
public interface WebSocketProtocol extends AsyncProtocol{
/**
* Allow an implementation to query the
* AtmosphereConfig of init-param, etc.
*/
void configure(AtmosphereServlet.AtmosphereConfig config);
/**
* Parse the WebSocket message, and delegate the processing
* to the {@link org.atmosphere.cpr.AtmosphereServlet#cometSupport} or
* to any existing technology. Invoking
* {@link org.atmosphere.cpr.AtmosphereServlet#cometSupport} will
* delegate the request processing
* to the {@link org.atmosphere.cpr.AtmosphereHandler} implementation.
* Returning null means this implementation will
* handle itself the processing/dispatching of the WebSocket's request;
* /
AtmosphereRequest onMessage(WebSocket webSocket, String data);
AtmosphereRequest onMessage(WebSocket webSocket, byte[] data, int offset, int length);
/**
* Invoked when a WebSocket is opened
* @param webSocket {@link WebSocket}
*/
void onOpen(WebSocket webSocket);
/**
* Invoked when a WebSocket is closed
* @param webSocket {@link WebSocket}
*/
void onClose(WebSocket webSocket);
/**
* Invoked when an error occurs.
* @param webSocket {@link WebSocket}
* @param t a WebSocketProcessor.WebSocketException
*/
void onError(WebSocket webSocket, WebSocketProcessor.WebSocketException t);
By default, Atmosphere uses the SimpleHttpProtocol to dispatch WebSocket message to Servlet based container. As an example, Atmosphere dispatch WebSockets messages to Jersey by wrapping the message inside an HttpServletRequest and an asynchronous I/O HttpServletResponse. By default message are considered as POST when dispatched to Jersey, but all HTTP property are configurable (content-type, headers, cookies, etc.). Another example is the EchoProtocol, which just echo message to all connected WebSocket.
Improved Cross-Origin Resource Sharing (CORS) Support
The Atmosphere JQuery Plug In has an improved support for CORS, specially with IE 8/9. You can either turn it on globally or per request. As simple as:
jQuery.atmosphere.subscribe(
this.url,
this.atmosphereCallback,
jQuery.atmosphere.request = {
method : 'POST',
data : json,
transport: "websocket" ,
fallbackMethod: "POST",
enableXDR : 'true',
attachHeadersAsQueryString: true });
Trackability Support and Multi Tab
Trackability of remote AtmosphereResource was available in previous version only with Jersey. With 0.8, Trackability is now available to all modules and natively implemented in the JQuery Atmosphere Plug In. When the Plug In execute a request, a unique ID is assigned to the request. The server will read that unique id and will try to look up an AtmosphereResource linked to that ID. That allow application to remotely manipulate AtmosphereResource without the need to keep track, inside the application itself, a list of AtmosphereResource. That allow an application to suspend more than one AtmosphereResource per connection, opening the possibility to implement Browser multi-tab support by assigning a unique ID per tab, represented by different AtmosphereResource on the server side.
Atmosphere also support Trackable injection like:
@Path("/subscribe")
@POST def subscribeAndPublish(
@HeaderParam(X_ATMOSPHERE_TRACKING_ID) trackedResource:
TrackableResource[AtmosphereResource[_, _]],
@HeaderParam(X_ATMOSPHERE_TRACKING_ID) trackingID: String,
@HeaderParam(X_ATMOSPHERE_TRANSPORT) transport: String, message: String)
: SuspendResponse[TrackableResource[AtmosphereResource[_, _]]] =
{
....
}
Headers as Query String
Some environment are just allowing the GET operation. An example if the WebSocket Handshake operation, which by default execute a GET without allowing the client to configure any headers. IE CORS also only support this model. The good news is Atmosphere can encode the headers as a QueryString and decode it on the server side as header, allowing application to pass information during the handshake operation. As simple as:
jQuery.atmosphere.subscribe(
this.url,
this.atmosphereCallback,
jQuery.atmosphere.request = {
method : 'POST',
data : json,
transport: "websocket" ,
fallbackMethod: "POST",
attachHeadersAsQueryString: true
});
There is much more new features, take a look at the changes log for more info.
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Google Group forum, follow the team or myself and tweet your questions there! .
Hitchiker Guide to the Atmosphere Framework using WebSocket, Long-Polling and Http Streaming
The Atmosphere Framework easily allow the writing of web application that support, transparently, SSE (Server Side Events), JSONP, WebSocket, Long-Polling and Http Streaming. The Atmosphere Framework also hide the complexity of the current asynchronous API, which differ from Server to Server and make your application portable among them. More important, it is much more easy to write an Atmosphere application than using the Servlet 3.0 API.

There are several APIs available in Atmosphere to write an asynchronous application: AtmosphereHandler, Meteor or using Jersey‘s Atmosphere extension. In this blog I will take the famous JQuery PubSub sample to demonstrate those APIs. Note that I will not discuss the JQuery Atmosphere Plugin as it is the same for all APIs. Important, all code snippet below support WebSocket, SSE, JSONP, Long-Polling and Streaming by default. Only the last section only support WebSocket.
The JQuery PubSub Application is quite simple. You enter a topic to subscribe, you select a transport to use (WebSocket, JSONP, SSE, Streaming or Long-Polling) or let the plug in decide for you, and then you are ready to publish message. You can use Redis on the server side to cluster your application among servers. The subscribe operation is done using a GET, the publish using a POST (in the form of message=”something”). If the WebSocket transport is used, the message is wrapped as a POST and delivered as a normal HTTP request. Note that this feature is configurable in Atmosphere
PubSub using AtmosphereHandler
The AtmosphereHandler is a low level API that can be used to write an asynchronous application. An application just have to implement that interface. This API is usually used by other framework in order to integrate with Atmosphere (GWT, Jersey, Vaading, etc.) but it can also be used if you want to write Servlet style code. So, with an AtmosphereHandler, the PubSub implementation will take the form of:
public class AtmosphereHandlerPubSub
extends AbstractReflectorAtmosphereHandler {
@Override
public void onRequest
(AtmosphereResource r)
throws IOException {
HttpServletRequest req = r.getRequest();
HttpServletResponse res = r.getResponse();
String method = req.getMethod();
// Suspend the response.
if ("GET".equalsIgnoreCase(method)) {
String trackingId = trackingId(req);
// Log all events on the console, including WebSocket events.
r.addEventListener(new WebSocketEventListenerAdapter());
res.setContentType("text/html;charset=ISO-8859-1");
Broadcaster b = lookupBroadcaster(req.getPathInfo());
r.setBroadcaster(b);
if (req.getHeader(X_ATMOSPHERE_TRANSPORT)
.equalsIgnoreCase(LONG_POLLING_TRANSPORT)) {
req.setAttribute(RESUME_ON_BROADCAST, Boolean.TRUE);
r.suspend(-1, false);
} else {
r.suspend(-1);
}
} else if ("POST".equalsIgnoreCase(method)) {
Broadcaster b = lookupBroadcaster(req.getPathInfo());
String message = req.getReader().readLine();
if (message != null && message.indexOf("message") != -1) {
b.broadcast(message.substring("message=".length()));
}
}
}
@Override
public void destroy() {
}
Broadcaster lookupBroadcaster(String pathInfo) {
String[] decodedPath = pathInfo.split("/");
Broadcaster b = BroadcasterFactory.getDefault()
.lookup(decodedPath[decodedPath.length - 1], true);
return b;
}
}
When a GET is received, we lookup a Broadcaster and then suspend the response based on the path info (REST style). Here we need a make sure we aren’t sending padding data (required for WebKit browser) when long polling is used. That’s the only required conditional evaluation needed in terms of transport. With the POST we just look up the Broadcaster (which represent a pubsub topic) and broadcast the request’s body. That;s it.
PubSub using Meteor
The Meteor is another low level API that can be used with existing Servlet application. As an example, the ADF framework use Meteor in order to integrate Atmosphere support.
public class MeteorPubSub extends HttpServlet { @Override public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { // Create a Meteor Meteor m = Meteor.build(req); // Log all events on the console, including WebSocket events. m.addListener(new WebSocketEventListenerAdapter()); res.setContentType("text/html;charset=ISO-8859-1"); Broadcaster b = lookupBroadcaster(req.getPathInfo()); m.setBroadcaster(b); if (req.getHeader(X_ATMOSPHERE_TRANSPORT) .equalsIgnoreCase(LONG_POLLING_TRANSPORT)) { req.setAttribute(RESUME_ON_BROADCAST, Boolean.TRUE); m.suspend(-1, false); } else { m.suspend(-1); } } public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException { Broadcaster b = lookupBroadcaster(req.getPathInfo()); String message = req.getReader().readLine(); if (message != null && message.indexOf("message") != -1) { b.broadcast(message.substring("message=".length())); } } Broadcaster lookupBroadcaster(String pathInfo) { String[] decodedPath = pathInfo.split("/"); Broadcaster b = BroadcasterFactory.getDefault() .lookup(decodedPath[decodedPath.length - 1], true); return b; } }
When a GET is received, we create a Meteor and use that Meteor to suspend the response, again using the path info. For post, we do the same as with AtmosphereHandler, e.g retrieve the Broadcaster and broadcast the message.
PubSub using Jersey’s Atmosphere Extension
With the Jersey extension, we can either use annotations or the programmatic API. As simple as”
@Path("/pubsub/{topic}")
@Produces("text/html;charset=ISO-8859-1")
public class JQueryPubSub {
private
@PathParam("topic")
Broadcaster topic;
@GET
public SuspendResponse subscribe() {
return new SuspendResponse.SuspendResponseBuilder()
.broadcaster(topic)
.outputComments(true)
.addListener(new EventsLogger())
.build();
}
@POST
@Broadcast
public Broadcastable publish(@FormParam("message") String message) {
return new Broadcastable(message, "", topic);
}
}
The GET could have been handled using the @Suspend annotation:
@GET
@Suspend(listeners = EventsLogger.class, outputComments = true)
public Broadcastable subscribe(){
return new Broadcastable(topic);
}
As you can see, it is quite simpler that with Meteor and AtmosphereHandler.
PubSub.
PubSub using WebSocket only
If you are planning to write pure WebSocket application and don’t plan to support normal HTTP, you can also write your own WebSocket sub protocol. It is quote important to note here that only WebSocket will be supported.
public class WebSocketPubSub implements WebSocketProtocol { private AtmosphereResource r; @Override public HttpServletRequest onMessage(WebSocket webSocket, String message) { Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo()); if (message != null && message.indexOf("message") != -1) { b.broadcast(message.substring("message=".length())); } //Do not dispatch to another Container like Jersey return null; } @Override public void onOpen(WebSocket webSocket) { // Accept the handshake by suspending the response. r = (AtmosphereResource) webSocket.atmosphereResource(); Broadcaster b = lookupBroadcaster(r.getRequest().getPathInfo()); r.setBroadcaster(b); r.addEventListener(new WebSocketEventListenerAdapter()); r.suspend(-1); } @Override public void onClose(WebSocket webSocket) { webSocket.atmosphereResource().resume(); } Broadcaster lookupBroadcaster(String pathInfo) { String[] decodedPath = pathInfo.split("/"); Broadcaster b = BroadcasterFactory.getDefault(). lookup(decodedPath[decodedPath.length - 1], true); return b; }
The important method here is onOpen (for accepting the handshake) and the onMessage, which is were the messages are received.
Conclusion
It is quite important to pick the best API when writing Atmosphere application as it can save you a lot of time! You can download all samples from here.
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Google Group forum, follow the team or myself and tweet your questions there! .
Configuring HAProxy for WebSocket
A lot of peoples (including myself at Wordnik) needed to configure HAProxy in order to make WebSocket working. For my Atmosphere Framework project, I’m using:
$ cat /etc/haproxy/haproxy.cfg
global
maxconn 4096 # Total Max Connections. This is dependent on ulimit
nbproc 1
defaults
mode http
frontend all 0.0.0.0:80
timeout client 86400000
default_backend www_backend
acl is_websocket hdr(Upgrade) -i WebSocket
acl is_websocket hdr_beg(Host) -i ws
use_backend socket_backend if is_websocket
backend www_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For
timeout server 30000
timeout connect 4000
server apiserver 127.0.0.1:8080 weight 1 maxconn 1024 check
backend socket_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For
timeout queue 5000
timeout server 86400000
timeout connect 86400000
server apiserver targetserver:7777 weight 1 maxconn 1024 check
Thanks to Matthias L. Jugel for sharing … see his use of Atmosphere at twimpact.com.
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Google Group forum, follow the team or myself and tweet your questions there! You can also checkout the code on Github.
Atmosphere.next Update: WebSocket, Javascript, full docs and 1.0.0 on the horizon!
I took this summer off in order to explore what can be done with the Atmosphere Framework. I have to admit I was extremely surprised about the number of emails I did received for supports, new features, venture capital stuff etc. As you may already know, I’ve decided to join Wordnik.com to pursue the work on Atmosphere.
The future of Atmosphere has never been brighter than now…starting mid September, I will be allowed as much as 50% of my time to work on Atmosphere. That’s A LOT, more time than I ever got allowed at Sun, Ning and Sonatype. For the last two years I’ve innovated on my own time, helped growing the community, do some talks, but I had never a chance to spend the time I wanted on the project. Not anymore!!
So soon I will restart contributing (created a lot of great things over the summer) and work on Atmosphere 1.0, which I hope I can do before next year. The roadmap is simple: stabilize, documents (quite needed), merge all the pull requests/donations for the client side, push the Socket.IO supports, etc. Since I haven’t received what I wanted from Oracle on Atmosphere, I will also rewrite some part of the framework completely to get rid of the CDDL/LGPL stuff in favor or a pure APL licensing (more than 75% is APL right now anyway). And of course the project will stay under Github, and Twitter will still be used for communicating news (either atmo_framework or jfarcand). Stay tuned, the future is bright for Atmosphere!
Quick Tip: Using Apache Shiro with your Atmosphere’s WebSocket/Comet app.
Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. When used with The Atmosphere Framework and a Servlet based Container, the security context of the thread that will execute the async operation may not carry the same SecurityContext, causing some unexpected issues.
As an example, let’s say you want to retrieve the user principal after you have suspended your request. Normally all you need to do is:
Subject currentUser = SecurityUtils.getSubject();
This work perfectly well when the request gets executed using the calling thread of the HTTP request, e.g. when the Servlet Container execute your Servlet.service method. Now when using the Atmosphere Framework, you may need to lookup the Subject once the async operation occurs: when a Broadcast (server side events) gets executed or when the suspended connection resume. Under that condition, doing SecurityUtils.getSubject() will NOT return the same value as when the call gets executed using the calling thread and hence can cause unexpected issues. The async Thread used in that case may be provided by the Servlet Container itself or by the Atmosphere’s BroadcasterConfig ExecutorServices. In both case, the security context is NOT the same as the original HTTP request thread, hence you should not call SecurityUtils API. Instead, one solution is to use the request attribute map and store the information required in it. As simple as:
request.setAttribute("subject", SecurityUtils.getSubject());
Then when the request resume or when a broadcast event occurs (inside your AtmosphereHandler#onStateChange method, your BroadcastFilter etc,), you can easily retrieve that information by doing:
Subject subject = request.getAttribute("subject");
The Request object is *always* the original object constructed by the Servlet Container when handling the HTTP request, hence attributes (and session) will always be available. This is a safe way to store Apache Shiro information.
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Google Group forum, follow the team or myself and tweet your questions there! You can also checkout the code on Github.
REST + WebSocket applications? Why not using the Atmosphere Framework
The Atmosphere Framework easily allow the creation of REST applications … using WebSocket. This time I will describe a super simple example on how to do it.
The Atmosphere Framework supports transparently both WebSocket and Comet transport and brings portability to any Java based application. An application written using Atmosphere can be deployed in any WebServer and Atmosphere will transparently make it work. Atmosphere is also able to transparently select the best transport to use, e.g. WebSocket or Comet. Now let’s write a very simple REST application with Comet support as we normally write:
@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); } }
Doing
GET /pubsub/something
will invoked the SuspendResponse. To make the exercise simple, all we do there is suspend the connection (e.g. do not return any response, wait for an event). If you want to make this exercise more difficult, you can always implements the ETag trick! Once the connection is suspended, we need to use a second connection in order to post some data
POST /pubsub/something
message=I love Comet
Executing the POST request will result in the invocation of the publish method. The @Broadcast annotation means the FormParam value will be broadcasted to all suspended connections.
WebSocket to rule them all
OK so let’s assume we now deploy your application in a WebServer that supports WebSocket like Jetty or GlassFish. Now Atmosphere will auto detect WebSockets are supported and use it when a WebSocket request is done. Now let’s assume we build the client using the Atmosphere JQuery Plug In and execute the GET request using Chrome (which support Websocket).The Atmosphere Javascript library is able to challenge the remote server and discover if the server and client support WebSocket, and use it.
In that scenario, suspending the connection will tell Atmosphere to execute the WebSocket handshake. Now the POST will be executed on the same connection, and the public method will be invoked this time. This is not a POST as you see normally with normal HTTP. Since WebSocket is used, only the form param will be send over the wire:
message=I love WebSocket
All of this occurs without any modification of your REST application. All you need to do to enable WebSocket is to “suspend” the connection when a @GET occurs. Transparent, is it
You can download the current version of the sample here.
Now what Atmosphere is doing under the hood is wrapping the WebSocket message into an HttpServletRequest so any framework like Jersey, Wicket, etc, works as it is. If you are familiar with Atmosphere, your AtmosphereHandler implementation will get invoked with an instance of HttpServletRequest that contains the WebSocket message, so you can use it as your will normally do using Comet or normal HTTP request.
For any questions or to download Atmosphere Client and Server Framework, go to our main site, use our Nabble forum, follow the team or myself and tweet your questions there! You can also checkout the code on Github.







