Archive

Author Archive

PrimeFaces 4 released: What’s new with PrimeFaces Push

PrimeFaces 4 has been released. The PrimeFaces Push components has been updated to use some of the cool new features of Atmosphere 2.0!

To name a few:

  • Atmosphere’s Protocol now enabled by default. This allow an PrimeFaces application to receive events like: client disconnection, proxy disconnection, network outage, etc. It also make is pretty simple to enable the Atmosphere’s UUIDBroadcasterCache to prevent message’s lost.
  • Heart Beat: Atmosphere’s Hear Beat now turned on by default, preventing proxy/firewall to unexpectly close websockets or long polling connection.
  • Message Size Interceptor: Atmosphere’s tracking message length enabled by default. Client side callback will always be invoked only when the complete message has been received. This makes application’s logic much more simple.
  • Significant Performance improvement of the MetaBroadcaster
  • jsr356 supports.
  • All the new features that ships with Atmosphere 2.0!

For the next PrimeFaces release (4.1), we are working on a new component model based with injectable Push instance, which will makes it event more easier to write powerful websockets applications! with PrimeFaces.

To install Atmosphere and PrimeFaces, make sure you are using Atmosphere 2.0.2.

 

Categories: Uncategorized

The Atmosphere Framework 2.0 released

The Async-IO dev team are pleased to announce the release of The Atmosphere Framework 2.0! You can download it here

Besides all of the performance and cache memory improvements made between Atmosphere 1.0, version 2.0 comes with a host of improvements and new features. Probably the biggest improvement that our users will notice is much better memory usage under high load and improved WebSocket/fallbacks transport performance. This changes alone makes it worth upgrading!

Read the announcement here!

Categories: Uncategorized

wAsync: WebSockets with Fallbacks transports for Android, Node.js and Atmosphere

wAsync aims to make realtime apps possible in Android’s mobile device and Java/JVM clients communicating with framework like Node.js and Atmosphere, blurring the differences between the different transport mechanisms. Transports supported are WebSockets, Server Side Events, Long-Polling and Http Streaming. You can download all samples from wAsync’s main page.

wAsync is really simple to use. For this blog, let’s write a simple chat using Node.js. First, let’s define a super simple Node.js WebSockets server with static files support. I’m dropping the entire code here assumining you know how Node.js works.

Now let’s write a wAsync’s Android client that can communiate with this server. Graphically, it will looks like

Screen Shot 2013-04-04 at 10.49.26 AM

Pretty simple Android application

As with for the Node.js server, I assume you are familiar with Android development.

Now let’s explain the code. First, we create a new client (line 19)

Client client = ClientFactory.getDefault().newClient();

Next, let’s create a Request to send:

RequestBuilder request = client.newRequestBuilder()
   .method(Request.METHOD.GET)
   .uri(serverIpAddress)

This demo is using JSON, and we want to use Jackson for marshalling/unmarshalling Java POJO. So just we define a really simple Encoder:

.encoder(new Encoder<Data, String>() {
           @Override
           public String encode(Data data) {
              try {
                return mapper.writeValueAsString(data)
              } catch (IOException e) {
                throw new RuntimeException(e);
              }
           }
})

This code will be invoked before the message is sent to Node.js and will covert the POJO to JSON. Next we define a decoder that will handle Node.js’s JSON response. We only decode messages, we aren’t interested by other events wAsync propagates:

.decoder(new Decoder<String, Data>() {
           @Override
           public Data decode(Transport.EVENT_TYPE type, 
                              String data) {
 
             if (type.equals(Transport.EVENT_TYPE.MESSAGE)) {
                try {
                   return mapper.readValue(data, Data.class);
                } catch (IOException e) {
                }
             }
             return null;        
})

Next, we create our Socket to Node.js (line 49)

final org.atmosphere.wasync.Socket socket = client.create();

And define two functions, one for handling the message, one for handling unexpected exceptions, and finally open the Socket

socket.on("message", new Function<Data>() {
           @Override
           public void on(final Data t) {
               uiHandler.post(new Runnable() {
               @Override
               public void run() {
                 Date d = new Date(t.getTime());
                 tv.append("Author " + t.getAuthor() + "@ " 
                   + d.getHours() + ":" + d.getMinutes() + ": "
                   + t.getMessage() + "\n");
                  }
              });
            }
            }).on(new Function<Throwable>() {
                @Override
                public void on(Throwable t) {
                    tv.setText("ERROR 3: " + t.getMessage());
                    t.printStackTrace();
                }
        }).open(request.build());

Finally, we just display what we are receiving on the Android screen:

  bt.setOnClickListener(new OnClickListener() {

           String name = null;
           public void onClick(View v) {
               try {
                 EditText et = (EditText) findViewById(R.id.EditText01);
                 String str = et.getText().toString();
                 if (name == null) {
                   name = str;
                 }
                 socket.fire(new Data(name, str));
                 et.setText("");
                 Log.d("Client", "Client sent message");
               } catch (Throwable e) {
                 tv.setText("ERROR " + e.getMessage());
                 e.printStackTrace();
                }
            }
       });

That’s all. If you want to chat between Android and a browser, you can install this HTML file, which will use atmosphere.js, the Atmosphere Framework’s client side to communicate with Node.js. You can use the Javascript WebSocket API directly as well, but with atmosphere.js, you get transports fallback support for free.

Now let’s write the same client, but this time using the Atmosphere Framework instead of Node.js. wAsync supports natively the Atmosphere protocol with fallback transports like long-polling, so we can tell wAsync to use long-polling in case the server doesn’t support websockets. For the server, instead of Node.js, we use the NettoSphere server.

The full code can be browsed here. The two differences are:

AtmosphereClient client =
   ClientFactory.getDefault().newClient(AtmosphereClient.class);

Here we create a specialized client, which will allow use to set some Atmosphere’s protocol specific property:

RequestBuilder request = client.newRequestBuilder()
   .method(Request.METHOD.GET)
   .uri(serverIpAddress)
   .trackMessageLength(true)
      [...]
   .transport(Request.TRANSPORT.WEBSOCKET)
   .transport(Request.TRANSPORT.LONG_POLLING);

The track message lenght feature make sure two JSON messages are never delivered to the function as a single message. To supports that with Node.js, we would have needed to install Socket.IO.

What’s next with wAsync? Add support for both Socket.IO and SocksJs protocol. Want to contribute? Fork us! For more information, ping me on Twitter or follow the Atmosphere Framework!

The wAsync developpement is powered by Async-IO.org, the company behind the Atmosphere Framework!

Snakes on the NettoSphere!

Want to build a game using Atmosphere?

Take a look at Building Games using WebSocket, Server-Side Events and Long-Polling with the Netty Framework and Atmosphere, from the Async-IO.org team.

Categories: Atmosphere, Websocket

Can I make a living out of my open source projects in 5 months?

I’m in the open source world for the last 12 years…it all started in 2002 as a member of the Tomcat team, then in 2005 I have created the Grizzly framework, lead the team that open sourced GlassFish, released the Grizzly Comet Framework, created the Atmosphere Framework in 2007 and its related projects. I also created the AsyncHttpClient library in 2009 and recently designed and implemented the Swagger Socket Protocol in 2012. I think I can say I have a little experience with open source development and management  :-)

All of that work was done under several companies umbrella: Sun Microsystems, Ning, Sonatype and more recently Reverb. In all cases, I was allowed to work on those frameworks because they were used internally. For example, I’ve spent the last 18 months working at Reverb, significantly improving the Atmosphere Framework and even deploying it on Wall Street Journal, one of the biggest/live deployment I’ve ever made so far supporting WebSockets and Internet Explorer 6/7/8/9 at the same time. Phew!!!

During that 18 months at Reverb, I was finally able to release the 1.0 version of Atmosphere, which was a major accomplishment for me after working on the framework for the last 4 years. Then, the popularity of the framework sky rocked and everything jumped: download are almost 200% up every months, Github “watcher” doubled, mailing list is now close to 500 users, Twitter account reached 1100 followers and emails traffic are stable months after months. More important, in December I’ve started getting requests for professionnal services with Atmosphere, contract support, etc.

So, with the current Atmosphere success, I’ve had a hard decision to take: work at Reverb and let the Atmosphere’s community grow and “leave by itself”,  or resign from Reverb and try to build a company to support Atmosphere. Last January was difficult for me as I was constantly under fire by having to work on Atmosphere and at the same time help scaling the Reverb’s platform. Not a nice situation!

So, I’ve decided to tale a leave on absent from Reverb and try to build my own company around the Atmosphere Framework, called Async-IO.org. The website is live and the traffic is already passing 500 unique hit per day, so this is positive…but, It’s a major challenge for the following reasons:

  • I cannot stay unemployed for several months. Hence I allocate myself 5 months to succeed with my crazy decision. I know it’s a very  small amount of time, but that’s all I can allocate.
  • I’m based in Canada (in Québec), not in California or in a city like London or Berlin where I can have funds from Venture Capitals Companies. Montréal is unfortunately stuck in the early 200o where IBM and Microsoft rules the city, so no luck on that side as well!
  • I want to try to do everything all by myself, from designing the website (thanks Github) and learn from existing open source projects that succeeded. I’m event sketching the official logo this week!
  • I don’t want to spend large amount of money on infrastructure. Instead, I would like to reward people that have been working with me in Atmosphere as soon as I can. But I need a solid foundation before I can do that.
  • I don’t have a large corporation financing my work. Since Atmosphere compete with framework like Socket.IO/Node.js, Vert.x and Play 2 (they are all powered by a big company), it’s a real challenge!
  • Atmosphere work with all browsers, mobile browsers and Java WebServers, and from version released sometimes 5 years ago. The testing matrix here is really complex and right now I  strongly need to rely on the community to help, and in return I’ve adopted a short release cycle to make every body happy. That way too much time consuming so I need to improve that situation.
  • Continue being active with the community like I have been for the last 4 years!

Now, after reading this you can call me crazy and I would fully understand! Interested to help? Pretty simple:

So, for the next 5 months I will use this blog to share my experience with this colossal adventure! Stay tuned!

Categories: Atmosphere, Websocket

Atmosphere 1.0, the Asynchronous JavaScript/Java Framework now available!

September 4, 2012 36 comments

Today, after almost 4 years of in and out works(*), I’m really happy to announce the immediate availability of the Atmosphere Framework version 1.0, the only Asynchronous JavaScript/Java Portable framework running on the JVM!

The Atmosphere Framework ships with multiple components, and can be used with JRuby, Scala, Groovy and Java:

  • Atmosphere Javascript: The client side of Atmosphere, supporting by all browsers. Supports Websockets and HTML 5 Server Sides Events when available, transparently fallback to Http Streaming/Long Polling or JSONP when not supported. Available for JQuery and Ext JS. Supports sharing/multiplexing a single connection amongst browser’s windows/tabs.
  • Atmosphere Runtime: The server side of Atmosphere, supporting all major WebServers. Supports WebSockets and HTML 5 Server Sides Events when available, fallback to WebServer’s Native Comet Implementation or the ugly Servlet 3 Async API at last. Also works transparently on top of the Netty and Grizzly Framework (no Servlet Container required). It also transparently brings WebSockets support to any exiting Servlet, without any changes required!
  • Atmosphere Jersey:  A native extension to the Jersey Framework (REST). Transparently brings WebSockets and HTML5 Server Side Events to  your REST architecture, using the JAX RS API. Also support the strange JAX RS 2 Async API.
  • Atmosphere GWT: A native extension to the GWT Framework. Transparently brings WebSockets and HTML5 Server Side Events.
  • Atmosphere Socket.IO: A native extension to the Socket.IO protocol. Free you from node.js, brings you the JVM scalabilty for free. WebSockets included.
  • Atmosphere Cometd: Run the Cometd Framework on top of Atmosphere, get portable WebSockets  and the cloud API for free.
  • Atmosphere Cloud API: Many module are available to make your application working into the cloud. Native Support for Redis PubSub, Hazelcast, JGroups, XMPP (GMail), JMS

Atmosphere is natively supported and available in PrimeFaces, Apache Wicket, Vaadin, Grails, RichFaces, Scalatra, Apache Tuscany, JQuery-Socket etc. and works fine with Spring and Google Guice.

Atmosphere works fine with Firefox 3+, Internet Explorer 6+, Opera 10+, Chrome 2+, Safari 2+, IOS 2+ and Android 2+ and supports connections sharing across multiple tabs and windows as. Open one connection, share it on all pages!

Atmosphere works with every Java EE Application Server and can automatically negotiates the best transport between the client and server. Atmosphere’s support portable WebSockets with Jetty, GlassFish, Grizzly 2, Tomcat and Netty. Write once, deploy anywhere!

Atmosphere ships with many samples, so get started very fast.

In short, Atmosphere works everywhere and with every framework. Websockets, Server Sides Events or any HTTP techniques are supported transparently. Write one javascript, one server file and Atmosphere will make it work every where, without any changes! As simple as (Client)

    var request = { url: document.location.toString() + 'chat',
                    contentType : "application/json",
                    transport : 'websocket' ,
                    fallbackTransport: 'long-polling'};

    request.onOpen = function(response) {
         // Display the user logged
    };

    request.onMessage = function (response) {
        var message = response.responseBody;
        var json = jQuery.parseJSON(message);
        addMessage(json);
    };

(Server)

@AtmosphereHandlerService(path = "/chat", 
interceptors= {AtmosphereResourceLifecycleInterceptor.class})
public class Chat implements AtmosphereHandler {

    @Override
    public void onRequest(AtmosphereResource r) throws IOException {
        r.getBroadcaster().broadcast(r.getRequest().getReader().readLine());
    }

    @Override
    public void onStateChange(AtmosphereResourceEvent event) throws IOException {
        AtmosphereResponse res = r.getResponse();

        if (event.isSuspended()) {
            String body = event.getMessage().toString();
            res.getWriter().write(new Data(body).toString());
        }
    }
}

You can see the Wordnik’s Atmosphere implementation lives, servicing approximatively between 40 to 50 millions of requests per day on WSJ.com (depending on enabled pages), or with any website using our Related Content PlugIn.

Atmosphere gets more than 25 000 downloads per month and widely used in production. Follow us on Github or Twitter. The more we are the better it will be!

(*) I would like to gigantically thanks Tony Tam and Erin McKean (and the team @Wordnik) for allowing me to work a significant amount of my time on Atmosphere every day, since last year!!.

Categories: Atmosphere, Comet, JQuery, Websocket

Writing Socket.IO application that runs on the JVM

The Socket.IO framework is defined as “Socket.IO aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms.”. If you are familiar with the Atmosphere Framework, this sound like a perfect match: The Atmosphere Framework aims to make realtime apps possible in every JVM based-Server, every browser and mobile device blurring the differences between the different transport mechanisms.

The major difference is with Socket.IO you are “stuck with node.js”, where with Atmosphere you can pick up the JVM based server of your choice, and get the guarantee that your application will works AS-IT-IS with any of those servers. Socket.IO + node.js forever? Not anymore! This blog introduces Socket.IO for the JVM, or how to write Socket.IO application running on the JVM, using the Atmosphere Framework!

If you are coming from the Socket.IO community, you may want to take a look at this page to grab more information about Atmosphere. For this blog, I will use the usual chat example I always use to demonstrate how simple Atmosphere is. And more important, all existing Atmosphere Application will works with Socket.IO WITHOUT ANY CHANGE! That means you can easily throw away your atmosphere.js code and instead use the Socket.IO library instead, without having to change anything on the server side.

Now, let’s write a really simple chat, let’s use an AtmosphereHandler, which is defined as:

@AtmosphereHandlerService(path = "/chat",
interceptors = {AtmosphereResourceLifecycleInterceptor.class})
public class SocketIOChatAtmosphereHandler implements AtmosphereHandler {

    @Override
    public void onRequest(AtmosphereResource r) 
          throws IOException {
        r.getBroadcaster().broadcast(
            r.getRequest().getReader().readLine());
    }

    @Override
    public void onStateChange(AtmosphereResourceEvent event) throws IOException {
        AtmosphereResource r = event.getResource();
        if (event.isSuspended()) {
            // THIS IS JUST FOR DEMO, use JACKSON instead.
            String body = event.getMessage().toString();
            String author = body.substring(body.indexOf(":") + 2,
                 body.indexOf(",") - 1);
            String message = body.substring(body.lastIndexOf(":") + 2,
                 body.length() - 2);
            event.write(("{ \"text\" : \"" 
                    + text + "\", \"author\" : \"" 
                    + author + "\" , \"time\" : " 
                    + new Date().getTime() + "}").getBytes());
        }
    }

    @Override
    public void destroy() {
    }
}

Let’s make it clear, I could have used a JSON parser but for the sake of this blog I just want to make it really really simple. The idea here is all requests mapping the ‘chat’ pattern will be delegated to this AtmosphereHandler. Every time a broadcast operation happens (when the Socket.IO POST data), that data will be delivered to the AtmosphereHandler#onStateChange, which will write the data back to the Socket.IO client. If there is N connected client, the onStateChange will be asynchronously called N times, with the end result of sending N response back to Socket.IO. Note here that there is no special code for handling transport, e.g everything is all handled by Atmosphere. That means the above AtmosphereHandler TRANSPARENTLY supports WebSockets, HTML5 Server Side Events (SSE), HTTP long-polling, HTTP Streaming or the JSONP technique. The best transport will be picked by Atmosphere based on what the client and server supports. Of course if you like to write bare metal Socket.IO application, take a look at this class, which demonstrate the low level protocol support in Atmosphere.

Now we have the choice of WebServer, but for this blog I will use NettoSphere(Atmosphere running on top of the Netty Framework). You install SocketIOChatAtmosphereHandler by simply doing:

public class SocketIOServer {

    public static void main(String[] args) throws IOException {
        new Nettosphere.Builder().config(
                new Config.Builder()
                        .port(8080)
                        .host("127.0.0.1")
                        .resource(SocketIOChatAtmosphereHandler.class)
                        .build())
                .build().start();
    }   
}

That’s it, our Socket.IO server side components is done. Now let’s use the latest Socket.IO 0.9.6 library for the client. For fun let’s rewrite the atmosphere.js Chat client code, this time using Socket.IO:

$(function () {
    "use strict";

    var detect = $('#detect');
    var header = $('#header');
    var content = $('#content');
    var input = $('#input');
    var status = $('#status');
    var myName = false;
    var author = null;
    var logged = false;
    var socket = io.connect('', {'resource': 'chat'});

    socket.on('connect', function () {
        content.html($('<p>', { text: 'Atmosphere connected using ' 
             + this.socket.transport.name}));
        input.removeAttr('disabled').focus();
        status.text('Choose name:');

        $.each(this.socket.transports, function(index, item) {
            $("#transport").append(new Option(item, item));
        });
    });

    socket.on('chat message', msg);

    socket.on('disconnect', function () {
        content.html($('<p>', { text: 'Sorry, '
            + 'but there\'s some problem with your '
            + 'socket or the server is down' }));
    });

    socket.on('error', function (e) {
        content.html($('<p>', { text: 'Sorry, '
            + 'but there\'s some problem with your '
            + 'socket or the server is down' }));
    });

    input.keydown(function(e) {
        if (e.keyCode === 13) {
            var msg = $(this).val();

            // First message is always the author's name
            if (author == null) {
                author = msg;
            }

            socket.emit('chat message', 
                $.stringifyJSON({ author: author, message: msg }));
            $(this).val('');

            input.attr('disabled', 'disabled');
            if (myName === false) {
                myName = msg;
            }
        }
    });

    function message(msg) {
        try {
            var json = jQuery.parseJSON(msg);
        } catch (e) {
            console.log('This doesn\'t look like a valid JSON: '
                , message.data);
            return;
        }

        if (!logged) {
            logged = true;
            status.text(myName + ': ').css('color', 'blue');
            input.removeAttr('disabled').focus();
        } else {
            input.removeAttr('disabled');

            var me = json.author == author;
            addMessage(json.author, json.text, me ? 'blue' 
                   : 'black', new Date(json.time));
        }
    }

    function addMessage(author, message, color, datetime) {
        content.append('<p><span style="color:' + color 
            + '">' + author + '</span> @ ' +
            + (datetime.getHours() < 10 ? '0' 
            + datetime.getHours() : datetime.getHours()) + ':'
            + (datetime.getMinutes() < 10 ? '0' 
            + datetime.getMinutes() : datetime.getMinutes())
            + ': ' + message + '</p>');
    }
});

The key part is the socket.on(‘chat message’, message) which will be invoked every time a new chat message is published. That’s IT! Pretty simple, it is? Now, depending on the browser you are using, Websockets or Long-polling will be used, TRANSPARENTLY! You can browse the complete code here.

For more Atmosphere samples, go there and pick the best sample. To compare Socket.IO with Atmosphere.js, take a look at the Atmosphere Chat sample, which transparently support WebSocket, Server Sides Events, Long-Polling and Streaming. If you are planning to use WebSockets and Java, I strongly recommend you look at Atmosphere instead of using private native API and get stuck on a server/framework forever. For more information, ping me on Twitter or follow the Atmosphere Framework!

Categories: Atmosphere, Comet, Websocket

Writing Portable WebSockets Application using Java

Writing Portable WebSockets’ applications using the Java Language can be challenging. Since there is no API standardization yet, several “native” API exists (Play!, Vert.x, Kaazing), you can easily get locked with their API, changes, single vendor etc. The same “problem” happens with well known WebServer: Jetty, Tomcat or GlassFish all have native API making your application not portable. Worse, the same problem happens on the client side: Grizzly, Netty, JWebSocket all have their own API. Not better on the browser side as well: Firefox went with its own API instead of the recommended one (MozWebSocket, fixed in Firefox 12).

So, already giving up? The solution is simple: use the AHC library(client) and the Atmosphere Framework (browser and server). The AHC library adds a thin layer on top of existing WebSockets’ client libraries, using the Netty Framework as default. The Atmosphere Framework allow portable WebSockets across Java based WebServers.

Part I — Writing the Server Component

The Atmosphere Framework works on top of existing native WebSocket implementation and currently supports Jetty, Tomcat, GlassFish and the Netty Framework (the NettoSphere). The Atmosphere Framework allows writing pure WebSockets applications as well as applications supporting the HTML 5 Server Side Events, Long-Polling or HTTP Streaming. Today this blog will only focus on writing WebSockets-only applications. So, no fallback on another transport in case WebSockets aren’t supported, but it is important to note that Atmosphere transparently support that transport’s fallback.

The portable API and easiest way to write pure WebSockets with Atmosphere is called WebSocketHandler, and can be defined as:

public abstract class WebSocketHandler implements WebSocketProtocol {

    public void onByteMessage(WebSocket webSocket, 
                              byte[] data, int offset, int length) {
    }

    public void onTextMessage(WebSocket webSocket, String data) {
    }

    public void onOpen(WebSocket webSocket) {
    }

    public void onClose(WebSocket webSocket) {
    }

    @Override
    public void onError(WebSocket webSocket, 
                        WebSocketProcessor.WebSocketException t) {
    }

For example, let’s say we want to write a simple echo server that broadcast received messages to all connected WebSockets, all we need to do is to extends that class with:

    @Override
    public void onTextMessage(WebSocket webSocket, String message) {
        MetaBroadcaster.getDefault().broadcastTo("/*", messages);
    }

All this code is doing is to broadcast the received messages to all connected client using the MetaBroadcaster utility classes. Since, by default, all connected WebSockets are registered at ‘/*’, no extra code is required. Of course we could have wrote something more complicated (like writing our own WebSocket Protocol), but that’s not the goal of this blog.

Part II — Writing the Browser Component

For the Browser component, let’s use the Atmosphere JQuery Plugin, which supports all browsers and could fallback to another transport in case WebSocket aren’t supported. In the easiest form, all we need to do to receive WebSockets messages is:

   var socket = $.atmosphere;
   var req = new $.atmosphere.AtmosphereRequest();
   req.url = document.location.toString() + '/echo';
   req.transport = "websocket';

   req.onOpen = function(response) {
       alert("WebSocket opened");
   }

   req.onTransportFailure = function(request) {
       alert("This browser or the remote Server doesn't support WebSocket");
   }

   req.onMessage(response) {
      var message = response.responseBody;
      alert("WebSocket Message received: " + message);
   }

   var subSocket = socket.subscribe(request);

Of course a real application will not use the alert call. An interesting callback here is the onTransportFailure, which is called in case the browser or the server isn’t supporting WebSockets. For sending WebSocket’s message:

    subSocket.push("Hello World");

Part III — Writing a Java Client

Now let’s write a portable Java client using the AHC library. As simple as

    AsyncHttpClient c = new AsyncHttpClient();
    WebSocket w = c.prepareGet("ws://127.0.0.1:8080")
                   .execute(new WebSocketUpgradeHandler.Builder().build())
                  .get();
    w.addWebSocketListener(new WebSocketTextListener() {

       public void onMessage(String message) {
         System.out.println("Message Received: " + message);
       }

       public void onOpen(WebSocket websocket) {
         System.out.println("WebSocket Opened");
       }
   }).sendTextMessage("Hello World");

By default the AHC library use the Netty Framework for WebSockets support, but other framework (like the Grizzly Framework) can easily be replaced.

For a more complex, portable WebSockets application, take a look at the Atmosphere Chat sample, which transparently support WebSocket, Server Sides Events, Long-Polling and Streaming. If you are planning to use WebSockets and Java, I strongly recommend you look at Atmosphere instead of using private native API and get stuck on a server/framework forever. For more information, ping me on Twitter or follow the Atmosphere Framework!

Safari’s WebSocket implementation and Java: Problematic!

The current Safari version (~5.1.5 … on OS X and iOS) implements an old version of the WebSockets specifications. This old version can  cause major issues with Java WebServer  in production. Here is some recommendations to workaround Safari. Important note: my observation are based on large deployments using the Atmosphere Framework.

First, let’s take a look at Java WebServers supporting WebSockets

WebServers Version Specification Safari Stability
Tomcat 7.0.27 and up hybi-13 and up NOT SUPPORTED
Jetty 7.0 to 7.4.5 Up to hybi-12 UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty 7.5.x to 7.6.2 Up to hybi-12 UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty 7.5.x to 7.6.2 Up to hybi-13 UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty 8.x to 8.1.2 Up to hybi-13 UNSTABLE: Server suffer High CPU when Safari’s WebSocket connection get closed.
Jetty 7.6.3 All hybi version STABLE
Jetty 8.1.3 All hybi version STABLE
GlassFish 3.1.1 All hybi version UNSTABLE: Suffer many API bugs
GlassFish 3.1.2 All hybi version STABLE
NettoSphere (based on Netty Framework) 1.x All hybi version STABLE

My recommendation is if you need to put a WebSocket application in production, use Jetty 7.6.3 or 8.1.3. GlassFish is also a good server but much more heavyweight to use if you are planning to write pure WebSocket applications. NettoSphere is fairly new and until Atmosphere 1.0.0 is released, I’m not yet recommending it (yet!). Note that the Netty Framework’s WebSocket implementation can be considered a STABLE as well, but to run Atmosphere on top of it you need NettoSphere.

Now if you can’t any of the stable WebServer, you can still use WebSockets. All you need to do is to write a Servlet’s Filter that will detect the WebSocket version and force Safari to downgrade to another “transport” or communication channel. Server Sides Events, long-polling, http streaming, polling or JSONP can then be used to reconnect. You just need to implement the reconnect inside your websocket#onClose function. With Atmosphere JQuery PlugIn, the reconnect is done transparently, e./g no special code needed. The Atmosphere Filter looks like:

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String draft = filterConfig
            .getInitParameter(ApplicationConfig.WEB_SOCKET_BANNED_VERSION);
        if (draft != null) {
            bannedVersion = draft.split(",");
            logger.debug("Blocked WebSocket Draft version {}", draft);
        }
    }

    @Override
    public void doFilter(ServletRequest request, 
                         ServletResponse response, 
                         FilterChain chain) 
        throws IOException, ServletException {

        HttpServletRequest r = HttpServletRequest.class.cast(request);
        if (Utils.webSocketEnabled(r)) {
            int draft =r.getIntHeader("Sec-WebSocket-Version");
            if (draft < 0) {
                draft = r.getIntHeader("Sec-WebSocket-Draft");
            }

            if (bannedVersion != null) {
                for (String s : bannedVersion) {
                    if (Integer.parseInt(s) == draft) {
                       HttpServletResponse.class.cast(response) 
                           .sendError(501, "Websocket protocol not supported"); 
                       return;
                    }
                }
            }
        }
        chain.doFilter(request, response);
    }

So if you aren’t using the Atmosphere Framework, make sure you have some sort of Filter than will block Safari from creating problem.

If you are planning to use WebSocket and Java, I strongly recommend you look at Atmosphere instead of using private native API and get stuck on a server forever. For more information, ping me on Twitter!

Writing Portable HTML5 Server Side Events Applications using the Atmosphere Framework

The Atmosphere Framework easily allow the creation of HTML5 Server Side Events (SSE). Better, any existing Servlet based application can add SSE support without any changes to their existing application.

HTML5 Server Side Events (SSE) are getting more and more adopted and support for it starts to appear. As an example,  the GlassFish Application Server recently added support for it,  the upcoming release of the Jersey Framework is also adding some sort of support, and framework like jQuery-Socket has sample supporting SSE as well. Both GlassFish and Jersey suffer major issues: First, you need to use non portable API to start using SSE (will only work in GlassFish or Jersey) and second, they expose special API to support SSE, which is a major mistake in my opinion. Just take a look at how simple it can be to implement SSE using the jQuery-Socket sample. Why would you use heavyweight API like GlassFish or Jersey to achieve something that simple? Not only that, but currently Internet Explorer isn’t supporting SSE, so if you use either use GlassFish or Jersey, your application will NOT WORK with Internet Exporer. Oups!!!

This is where Atmosphere comes to the rescue. With Atmosphere, you don’t have to add anything special to have SSE supported by your application. Event better, you can ask Atmosphere to fallback to another technique if SSE is not supported. As an example, you can ask for WebSocket or Long-Polling to be used when SSE is not available. Atmosphere will transparently fall back. On the server side, you don’t need to care about anything as Atmosphere will do it for you. As an example, let’s write a simple Chat application using Atmosphere and Jersey (but not the Jersey SSE implementation!).

First, let’s define a super simple Jersey Resource:

  1 @Path("/")
  2 public class ResourceChat {
  3 
  4     @Suspend(contentType = "application/json")
  5     @GET
  6     public String suspend() {
  7        return "";
  8     }
  9 
 10     @Broadcast(writeEntity = false)
 11     @POST
 12     @Produces("application/json")
 13     public Response broadcast(Message message) {
 14          return new Response(message.author, message.message);
 15     }
 16 }

The important code here is line 4, where the Atmosphere Suspend annotation is used to suspend to tell Atmosphere to not commit the response, e.g leave the connection open. Under the hood it means the Atmosphere native SSE implementation will be enabled and SSE message transparently handled. With line 10, we are telling Atmosphere to broadcast the message back the client to all suspended connections, or stated differently, to all our connected Browser, supporting SSE or not. This is important to not here that if the remote browser isn’t supporting SSE, a fallback transport will be used. For that sample let’s use long-polling, but if you are using Internet Explorer 10 we could have chosen WebSockets as a fallback mechanism. You can download the server code (complete sample) here.

No on the client side, all we need to do is to tell Atmosphere to use SSE as its main transport (complete code here):

  1 var request = { url: document.location.toString() + 'chat',
  2     contentType : "application/json",
  3     logLevel : 'debug',
  4     transport : 'sse' ,
  5     fallbackTransport: 'long-polling'};
  6 
  7     
  8 request.onOpen = function(response) {
  9     content.html($('<p>', { text: 'Atmosphere connected using '
          + response.transport }));
 10     input.removeAttr('disabled').focus();
 11     status.text('Choose name:');
 12 };
 13     
 14 request.onMessage = function (response) {
 15     var message = response.responseBody;
 16     try {
 17         var json = JSON.parse(message); 
 18     } catch (e) {
 19         console.log('This doesn\'t look like a valid JSON: ',
                    message.data);
 20         return;
 21     }
 22         
 23     if (!logged) {
 24         logged = true;
 25         status.text(myName + ': ').css('color', 'blue');
 26         input.removeAttr('disabled').focus();
 27     } else {
 28         input.removeAttr('disabled');
 29         
 30         var me = json.author == author;
 31         var date =  json.time;
 32         addMessage(json.author, json.text, me 
               ? 'blue' : 'black', new Date(date));
 33     }
 34 };
 35     
 36 request.onError = function(response) {
 37     content.html($('<p>', { text: 
           'Sorry, but there\'s some problem with your '
 38                 + 'socket or the server is down' }));
 39 };
 40                                                                                                                                                          
 41 var subSocket = socket.subscribe(request);

Important code here is line 1 where we create a request and configuring SSE as the main transport and Long-Polling as a fallback transport. Note that we could replace SSE with WebSocket and our application WILL STILL WORK, WITHOUT ANY CHANGES NEEDED ON THE SERVER SIDE!!! Line 8, 14 and 36 are used to define some function that will be invoked when the connection gets established, when messages are received and when network errors occurs. And your application will works everywhere Servlet 2.5 is supported. So the question is: Why using private/non portable API and worse, special API just to support only Server Side Events? Don’t go that route and use Atmosphere, and get all for free!

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! .

Categories: Atmosphere, Comet, JQuery, Websocket
Follow

Get every new post delivered to your Inbox.

Join 50 other followers