Archive

Author Archive

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

Transparently adding WebSockets to your application using SwaggerSocket

Today at Wordnik we announced the immediate availability of SwaggerSocket, a REST over WebSockets protocol that build on of Atmosphere and AsyncHttpClient. In this blog I will give some details about how the protocol works and how we implemented it.

First let’s gives some details about how SwaggerSocket works. SwaggerSocket build on top of the Atmosphere WebSocketProtocol API. The Atmosphere Runtime dispatchs WebSocket events to WebSocketProtocol API, allowing the manipulation of WebSockets events. It is important to note that Atmosphere Runtime takes care of all the WebServer WebSocket details (remember there is no standard on the server side with WebSocket). That why writing a WebSocket application with Atmosphere is portable and can be run on top of Netty, Jetty, GlassFish and Tomcat WebSocket implementation. By default, Atmosphere uses the SimpleHttpProtocol for dispatching WebSocket events to framework or application.

The SimpleHttpProtocol is “simple”: when a WebSocket message is received, it is dispatched as a POST to applications and frameworks. As an example, the Jersey Framework works without any modification inside Atmosphere and transparently work with WebSocket. But you can’t dynamically pass information like form/query params and headers unless you add those inside the WebSocket message itself, by writing your own “sub protocol”. Worse, why waiting for a response to arrive before sending another one? Why not sending an array of requests and get responses as they come, asynchronously? This is where SwaggerSocket can saves our life!

The SwaggerSocket Protocol is exactly that, a Protocol on top of WebSocket. The First version of the Protocol is using JSON to pass information between the client and server. As an example, a WebSocket message looks like:

    "requests" : [
        {
            "uuid" : 0,
            "method" : "POST",
            "path" : "/foo",
            "headers" : [
                {
                    "name" : "Content-Type",
                    "value" : "application/json"
                }
            ],
            "queryStrings" : [
                {
                    "name" : "foo2",
                    "value" : "bar2"
                }
            ],
            "messageBody" : "SwaggerSocket Protocol is cool"
        }
    ]

A Response looks like

    "responses" : [
        {
            "uuid" : 0,
            "status" : "status",
            "path" : "/foo",
            "headers" : [
                {
                    "name" : "name",
                    "value" : "value"
                }
            ],
            "messageBody" : "You are right! SwaggerSocket is coool!"
        }
    ]

It is important to note that any existing applications will WORKS AS IT IS, without any modifications server side. That means your Wicket/GWT/Vaadin/Resis/Hazelcast/Jersey/Spring/Guice/RichFaces/etc. can take advantage of the protocol right now. As an example, a simple Jersey resource:

@Path("/helloworld")
class HelloWorld {

  @Path("/sayHello")
  @GET
  def get(): String = {
    "Swagger Socket Hello World"
  }
}

will run unmodified. For the client, you have choice:

  1. Open a WebSocket and use the swaggersocket-protocol library to create requests and responses
  2. Use the swaggersocket.js library
  3. Use the SwaggerSocket Scala Library, which build on top of AHC (AsyncHttpClient) WebSocket

I strongly recommends the use of 2 and 3, but would like to see contribution for 1 :-). Our goal is to integrate SwaggerSocket with Swagger and ships other client language as well.

With Javascript, all you need to do is:

        $(document).ready(function() {
  new jQuery.swaggersocket.SwaggerSocket()
     .open(document.location.toString() + "ss",
          function(swaggerSocket, r) {
              if (r.getStatus() == 200) {
              var ss = new jQuery.swaggersocket.SwaggerSocketListener();
              ss.onResponse = function(r) {
               // Write the response
              };

              var request = new jQuery.swaggersocket.Request()
                       .method("GET")
                       .path('/helloworld')
                        listener(ss);

               swaggerSocket.send(request);
          } 
   ....

All you need to do is to create a SwaggerSocket, invoke the open method and pass a function that will be invoked when the initial handshake as succeeded. Then you can call swaggerSocket.sendto send a single or an array of requests. You can do the same using the SwaggerSocket Scala Library:

  val ss = SwaggerSocket().open("http://127.0.0.1:8080/helloworld")
  ss.send(new Request.Builder()
   .path("/sayHello")
   .build(), new SwaggerSocketListener() {
  	override def message(r: Request, s: Response) {
        // print the response using response.getData()
     }
   })

The fun just begin! We will soon add support for other transport like Server Side Events, Long-Polling, HTTP Streaming and JSONP so you can deploy your SwaggerSocket application in your current production infrastructure which most probably isn’t supporting WebSocket yet. But you don’t have to wait for WebSocket, Atmosphere always use the best available one and the framework makes sure to switch to WebSockets when available.

I strongly encourage you to take a look at our demos, specially the Twitter one that bring real time search to Twitter, as fast as what Google Search recently started to support.

For any questions or to download SwaggerSocket, go to our main site, use our Google Group forumfollow the team or myself and tweet your questions there!

Websockets or Comet or Both? What’s supported in the Java EE land

In preparation for the Atmosphere Framework 1.0.0 release, I’ve started listing what Java EE (or WebServer) supports in terms of Native Comet and WebSockets. This blog describes who supports what. I’ve also added a section describing what transport (WebSocket, Http Streaming, Long Polling or JSONP) Browsers are supporting, again tested using Atmosphere. Of course, Atmosphere supports both matrix, but that’s not the goal of this blog. I’ve also not included SPDY or Server Side Events Support because they are yet to be implemented by the majority of Servers.

Server Supports

The following table describes what Atmosphere supports but it can also be seen as what available in Java EE in general. The third and fourth columns are describing if the server has native support for Comet and WebSocket, by either supporting the ugly Servlet 3.0 API or if they have native implementation. The same apply for WebSockets native support (there is no WebSocket standard yet). Last four columns list the “most” popular transport, e.g WebSockets, Http Streaming (also called Forever Frame), Long-Polling and JSSONP. Note that servers like Tomcat 5 doesn’t support native Comet or WebSocket, but Comet can always be emulated by blocking a thread (this is what Atmosphere is doing when deployed there).

(LP: long-Polling HS: Http Streaming)

Server Version Native Comet Native WebSocket WebSockets LP HS JSONP
Netty 3.3.x X X X X X X
Jetty 5.x X X X
Jetty 6.x X X X X
Jetty 7.x X X X X X X
Jetty 8.x X X X X X X
GlassFish 2.x X X X X
GlassFish 3.x to 3.1.1 X X X X
GlassFish 3.1.2 X X X X X X
Tomcat 5.x X X X
Tomcat 6.x X X X X
Tomcat 7.0.26 and lower X X X X
Tomcat 7.0.27 and up X X X X X X
JBoss 5.x X X X
JBoss 6.x X X X X
JBoss 7.x X X X X
WebLogic 10.x X X X X
WebLogic 11.x and up X X X X
Resin 2.x X X X
Resin 3.x X  X X X X
WebSphere 7.x X X X
WebSphere 8.x X X X

Supported Browsers

The current list of Browsers have been tested with Atmosphere using the atmosphere.js Javascript library and the transport they supports.

Browser Version WebSockets Long-Polling Http Streaming JSONP
Firefox 3.x to 8.x X X X
Firefox 9.x to 11.x X X X X
Chrome 12.x and lower X X X
Chrome 13.x and higher X X X X
Internet Explorer 6x to 9.x X X X
Internet Explorer 10.x X X X X
Opera 10.x and lower X X
Opera 11.x X X X
Safari 4.x X X X
Safari 5.x X X X X
Android 2.x and up X X X
Safari (iOS) 1.x to 4.x X X X
Safari (iOS) 5.x X X X X

Note that I haven’t listed private/commercial/proprietary WebSockets implementations like Kaazing and JWebSocket or Pusher or framework like Cometd (who only works properly on Jetty).

That’s it. If you are planning to use WebSocket and Java EE, 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!

Categories: Atmosphere, Comet, Websocket

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

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

Categories: Atmosphere, Websocket

Writing Client/Server WebSocket Application using Scala

February 10, 2012 3 comments

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!

Categories: Atmosphere, WCS, Websocket
Follow

Get every new post delivered to your Inbox.

Join 51 other followers