Sock it to 'em

Server Side API

Java Client Side Adoption

Adoption

Conclusion

References

The recently released JSR 356 Java API for WebSocket[1], recommended for supporting the WebSocket protocol in Java [3], already ships with recent versions of Servlet Containers such as Tomcat, Wildfly, Jetty, and GlassFish. Although this is a really good step in the right direction, there are many areas where the API either lacks functionality or could benefit from significant improvement. In this article originally published in JAX Magazine, Jean Francis Arcand walks us through a few of them.Before the API, applications that wanted to use the WebSocket Protocol needed to either use proprietary WebSocket API, sacrificing portability, or use a framework such as Atmosphere[2], which abstracted an API layer allowing WebSocket applications across Servlet Container, and also frameworks like Vert.x, Play! and Netty.Another important difference is the fact that a JSR 356 WebSocket application will only work when the browser supports the WebSocket Protocol. If a browser doesn’t, the application won’t work. That’s not a problem with Atmosphere – the framework is able to transparently fallback to another transport like HTTP, without any change required to your application. Be aware that if you are planning to go on production, live on the web, with a pure JSR 356 websocket application, a lot of browsers won’t be able to communicate with your application.Let’s use a Chat Application to compare the use of JSR 356 and Atmosphere, and see where the JSR would benefit from some improvements. We‘ll start the comparison by writing the simplest endpoints. It is assumed here you have a little knowledge of JSR 356 annotationṡ. First, let’s write our skeleton class. With JSR 356, our endpoint will look like: With Atmosphere, our endpoint will look like: There is not much difference between JSR 356 and Atmosphere in terms of coding, with the exception that with Atmosphere you don’t need to implement the write operation, all that you need to do is to set the return value of your annotated method. But the @ManagedService annotation gives you much more than @ServerEndpoint in terms of quality of service. The @ManagedService annotation starts transparently, though under the hood, some functionality is needed for an application running on the web. One of the biggest issues with WebSockets is Proxy. Proxy that aren’t supporting the protocol or Proxy configured with timeout will eventually kill a websocket connection if no activity occurs on it. In this case, you need to make sure both the client and server code can re-handshake their state transparently, so that your application can survive disconnection. For JSR 356, that means we need a little more work Server side to prevent evil Proxy. One naive way would be to add: Another critical functionality missing is when a websocket connection is abruptly closed, either by a Proxy, or anything in between the browser and the server. For example, a mobile browser may suffer frequently suffer from unexpected disconnections. By the time the browser reconnects, messages may have been published, and lost messages will never be sent to the browser. The @ManagedService annotation transparently deals with this case, making sure to cache messages and send them back when the browser reconnects. With JSR 356, support for such a scenarion is missing, hence you need to write your own. This is far from simple, as you need to track the browser and make sure all messages will eventually be delivered. An extremely native implementation could be: Not impossible to implement, but consider you get the functionality transparently when using the @ManagedService annotation. Another functionality missing with JSR 356 is, if an application sends a message larger than the underlying server’s I/O buffer, the message can sometimes be delivered to the client in two chunks. When working with text messages, it is probably not an issue, but if you work with JSON for example, receiving a JSON message in two chunks will produce an error when try to decode it on the client side using: You can either add an ugly try/catch around that function, append the next message to the already received one until the parse operation succeed, or you can encode in the message itself the length of the expected message. It requires code on both client and server component. Using Atmosphere, you get that functionality for free transparently built in for you. This means you are guaranteed to receive the complete message when defining (more details on the client next section) Talking of JSON, let’s stop working with String and instead add some Encoder and Decoder. For example, let’s define the following Message class: JSR 356 deﬁned the notion of Message’s Encoder and Decoder. For example, let’s assume the browser is sending JSON message. To handle those messages, let’s write a JSR 356 Decoder using Jackson: The major difference here is with JSR 356 you can decide to not decode an object based on its String content. With Atmosphere, we instead support chaining for Decoder, e.g. a decoder decoded object be the input of another decoder. That way, the message doesn’t have to be parsed several times as with JSR 356. For encoding the Message class, use JSR 356 expose Encoder: The main difference here is as with Atmosphere’s Decoder, you can chain Encoder and pass an encoded object to the next Encoder. With JSR 356, you can only encode as String or PrintWriter. With Atmosphere, you don’t have such restriction. Putting the piece together, the JSR 356 implementation looks like: with Atmosphere, The main difference here is with Atmosphere, encoders/decoders can apply at method level, where with JSR 356 it applies only at class level.Let’s now explore the client side of a WebSocket application. JSR 356 doesn’t ship with a Javascript client library, so we will use the W3C interface that the majority of browsers support. For our simple application, we use: With Atmosphere: The API looks similar, with a major difference: If the WebSocket API is not supported by the browser, Atmosphere will transparently fallback and use long-polling instead. But not all applications need to use a fallback transport, so let’s not focus on that. Atmosphere client-side Javascript comes with nice functionality For example, as with the server, if the connection get interrupted, most of the time the client needs to reconnect. With W3C API, you have to implement the logic inside your onclose or onerror function. Nothing complicated, but you have to take care of it. Since the server may not be available automatically, you may need to try reconnecting after a five second pause. Put a limit on when trying to reconnect, etc. All this code needs to be implemented. With Atmosphere, it’s already built into the Javascript, so all you need to do is: Again, you can do it with W3C API, but that will require a lot of code. As pointed in the previous section, you may also have to make sure the websocket.onmessage(data) contains the full response send by the server before trying to parse it using a JSON parser.JSR 356 ships with a Client Side API as well, but I won’t go into the details in this article. Atmosphere also has a Client Side API called wAsync[4], which support websocket as well as other transport like Server Side Events, long-polling etc.As of November 2013, JSR 356 is supported by Tomcat 7/8 (Beta), Jetty 9.1.0 (Beta), GlassFish 4, Wildfly/Undertow (beta) and Resin 4. Atmosphere supports WebSocket natively Tomcat 7/8, Jetty 7/8/9, GlassFish 3/4, WebLogic 12, JBoss 7.1.x, Netty 3.x, Vert.x 2.x and Play! Framework 2.x and up. With Atmosphere, your application is portable and you can use server that are already production ready, without waiting for a newer version of it which support JSR 356.JSR 356 is a good step toward WebSocket adoption in the Java land, but there is a lack of important features like fallback transport for browsers that don’t support the websocket protocol, caching of messages to prevent message’s lost, proper life cycle reconnection, and wide adoption with servers deployed in production. Atmosphere is production ready and can be deployed almost anywhere. It already supports functionalities like message caching, proper reconnection life cycle, fallback transport, and much more besides. Atmosphere can run on servers supporting JSR 356, as well as well established server and framework. More importantly, Atmosphere ships with a client side Javascript which can solve a lot of issues. Finally, Atmosphere is supported by the majority of existing frameworks, and can transparently add WebSocket support to framework like PrimeFaces, RestEasy, Wicket, Jersey, etc. This means you can write a good old Servlet Application that transparently runs on top of the WebSocket protocol.[1] http://jcp.org/en/jsr/detail?id=356 [2] http://github.com/Atmosphere/atmosphere [3] http://tools.ietf.org/html/rfc6455 [4] http://github.com/Atmosphere/wasync