Archive

Archive for the ‘Comet’ Category

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.

Advertisements
Categories: Atmosphere, Comet, Websocket

Atmosphere.next Update: WebSocket, Javascript, full docs and 1.0.0 on the horizon!

September 8, 2011 8 comments

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!

 

Categories: Atmosphere, Comet, Websocket

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.


Categories: Atmosphere, Comet, Websocket

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.

Categories: Atmosphere, Comet, JQuery, Websocket

Small Survival guide when debugging your Comet/WebSocket application.

Under my Atmosphere’s Project works, I’m getting a lot of questions about how to debug WebSocket/Comet applications. Here is some simple tools and trick  I use.

ngrep.sourceforge.net

A lot of people use wireshark, I much prefer using ngrep for snooping the network packet. As simple as:

sudo ngrep -d en0 -q -W byline port 8080

For WebSocket it helps seeing what’s being sent being the client and the server. Of course you can always use FireBug or Chrome dev tool for debugging inside the browser,  but it is much easier IMO to see the interaction between the browser and the server from a terminal window:

T 127.0.0.1:61265 -> 127.0.0.1:8080 [AP]
GET /atmosphere-jquery-pubsub/pubsub/chat HTTP/1.1.
Upgrade: WebSocket.
Connection: Upgrade.
Host: 127.0.0.1:8080.
Origin: http://127.0.0.1:8080.
Sec-WebSocket-Key1: Z      mZ1  4 9 0W75 50!p13.
Sec-WebSocket-Key2: .mx1674Dy@ 69K  %K027C9:m.
.
.TQ..34.

T 127.0.0.1:8080 -> 127.0.0.1:61265 [AP]
HTTP/1.1 101 WebSocket Protocol Handshake.
Upgrade: WebSocket.
Connection: Upgrade.
Sec-WebSocket-Origin: http://127.0.0.1:8080.
Sec-WebSocket-Location: 
    ws://127.0.0.1:8080/atmosphere-jquery-pubsub/pubsub/chat.
.

T 127.0.0.1:8080 -> 127.0.0.1:61265 [AP]
B...%...K....[..

Using curl

If you are using curl to test your Comet application (or Websocket to test the initial handshake). make sure you pass the -N option as without, curl will buffer the server’s response and will not display it until the connection gets dropped by the server:

 curl -N http://127.0.0.1:8080/atmosphere-jquery-pubsub/pubsub/chat

Without the -N option any real time update will not get display live in the console:

curl -N http://127.0.0.1:8080/atmosphere-jquery-pubsub/pubsub/chat
<!--                                  http://github.com/Atmosphere                                      -->
<!-- Welcome to the Atmosphere Framework. To work with 
all the browsers when suspending connection, Atmosphere must output some
data to makes WebKit based browser working.-->
<!-- EOD -->

For any questions, use Twitter to reach me!

Categories: Atmosphere, Comet, Websocket

Atmosphere 0.7 released: WebSocket, GWT, Wicket, Redis, XMPP, Async I/O

February 25, 2011 4 comments

Atmosphere 0.7 is available! This release contains an impressive number of new functionality and bug fixes. The extensive list of fixed bugs for that release can be read here, and the new functionality are explained below

Native GWT support

Starting with 0.7, the Atmosphere-GWT project is now fully integrated into Atmosphere. That means you can add support for WebSocket/Comet to any GWT application. You can download demos from here.

Wicket Support

As described here, we do support the Wicket framework our of the box. As simple as:

public class PushPage extends WebPage
    implements AtmosphereResourceEventListener {

    private final AtomicBoolean scheduleStarted = new AtomicBoolean(false);

    public PushPage() {
        HttpServletRequest req = getWebRequestCycle()
               .getWebRequest().getHttpServletRequest();
        Meteor meteor = Meteor.build(req);
        if (!scheduleStarted.getAndSet(true)) {
            meteor.schedule(new Callable<String>() {
                public String call() {
                    String s = new Date().toString();
                    return s;
                }
            }, 1); // One second
        }
        meteor.addListener(this);

        // Depending on the connection
        String transport = req.getHeader("X-Atmosphere-Transport");
        meteor.suspend(-1, !(transport != null
              && transport.equalsIgnoreCase("long-polling")));
    }

    public void onBroadcast(AtmosphereResourceEvent
           <HttpServletRequest, HttpServletResponse> event) {

        String transport = event.getResource()
                .getRequest().getHeader("X-Atmosphere-Transport");
        if (transport != null
              && transport.equalsIgnoreCase("long-polling")) {
            Meteor meteor = Meteor.lookup(event.getResource().getRequest());

            meteor.removeListener(this);
            meteor.resume();
        }
    }

    ...
}

you can download the demo here.

Native Redis Support

As described here, you can now use Redis for massively distribute server sides events amongst your Atmosphere application. This is as simple as configuring Atmosphere to use the RedisBroadcaster to broadcast server sides events. If you already have an Atmosphere application, you don’t need to change anything except configuring Atmosphere. You can switch from your in memory broadcaster, JMSBroadcaster, JGroupsBroadcaster by simply doing:

    // JSMBroadcaster || XMPPBroadcaster
    private @PathParam("topic") RedisBroadcaster 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);
    }

you can download the demo here.

Native XMPP Support

As described here, you can now use the XMPP protocol for massively distribute server sides events amongst your Atmosphere application. As with Redis and JMS, you just need to tell Atmosphere to use the XMPPBroadcaster. You can download the demo here.

Broadcasting Callable<T> now supported

As described here, you can now broadcast Callable, which gets executed just before the response is written back to the browser. This is quite useful when scheduled tasks are needed:

if (feed.getAtmosphereResources().size() == 0) {
    Future<?> future = feed.scheduleFixedBroadcast(new Callable<String>() {
        private final AtomicReference<String> refreshUrl
               = new AtomicReference<String>("");
           public String call() throws Exception {
              String query = null;
              if (!refreshUrl.get().isEmpty()) {
                  query = refreshUrl.get();
              } else {
                  query = "?q=" + tagid;
              }
              asyncClient.prepareGet(
                  "http://search.twitter.com/search.json"  + query)
                    .execute(new AsyncCompletionHandler <Integer>()) {
                          @Override
                          public Object onCompleted(Response response)
                               throws Exception {
                            String s = response.getResponseBody();
                            JSONObject json = new JSONObject(s);
                            refreshUrl.set(json.getString("refresh_url"));
                            feed.broadcast(s).get();
                            return response.getStatusCode();
                          }
                    });
                    return "OK";
                }
            }, 1, TimeUnit.SECONDS);
            futures.put(tagid, future);
        }

you can download the demo here.

WebSocket Emulator Supported (like Flash)

The Atmosphere JQuery Plugin can now be configured to use an external WebSocket implementation. As an example, you can use the web-socket-js library, which adds support for Flash.


     <script type="text/javascript" src="web_socket.js"></script>

     <script type="text/javascript">
         $(document).ready(function()
         {
             .....
         /* transport can be : long-polling, streaming or websocket */
         $.atmosphere.subscribe(uri,
                myEventCallback,
                $.atmosphere.request =
                    {transport: getElementByIdValue('transport'),
                     webSocketImpl: new WebSocket(uri) });

Asynchronous write I/O operation now supported

All the Broadcaster has been modified to support asynchronous I/O write operation using a dedicated ExecutorService. This will prevent slow clients to block the entire broadcast process. You can configure the thread pool strategy using the BroadcastConfig API:

Per Request BroadcastFilter

As described here, per request BroadcastFilter are now supported. That means you can transform an events based on some request’s headers, query string etc. This is quite useful when it is time to unify browser support, or take advantage of some browser native API. As simple as:

public class JavascriptClientFilter implements PerRequestBroadcastFilter {

    private final AtomicInteger uniqueScriptToken = new AtomicInteger();

    @Override
    public BroadcastFilter.BroadcastAction filter
                   (HttpServletRequest request, Object message) {

        if (request.getHeader("User-Agent") != null) {
            String userAgent =
               request.getHeader("User-Agent").toLowerCase();
            if (userAgent != null && userAgent.indexOf("MSIE") != -1
                    && message instanceof String) {
                StringBuilder sb = new StringBuilder
                    ("<script id=\"atmosphere_")
                    .append(uniqueScriptToken.getAndIncrement())
                    .append("\">")
                    .append("parent.callback")
                    .append("('")
                    .append(message.toString())
                    .append("');</script>");
                message = sb.toString();
            }
        }
        return new BroadcastFilter.BroadcastAction
            (BroadcastFilter.BroadcastAction.ACTION.CONTINUE, message);
    }

Improved Dependency Injection Support for Spring and Guice

With 0.7 we have added new API to allow easier integration with Spring and Guice.  You can download the demo here.

New Broadcaster’s Lifecycle Policy Support

Broadcaster implementation like the JMSBroadcaster can hold open connections and before 0.7 it was difficult to decide what to do with those connections when no WebSocket/Comet connections where alive. We have added a new API that allow an application to configure Atmosphere and decide when a Broadcaster’s resource get garbage collected. As simple as:

Broadcaster.setBroadcasterLifeCyclePolicy( IDLE | IDLE_DESTROY | EMPTY | EMPTY_DESTROY | NEVER );

Improve compatibility with other JavaScript Framework

It is now easier to integrate the Atmosphere JQuery Plugin with other framework like Prototype.

Jersey’s @DefaultValue and @Singleton now supported

You can now use these two annotations with Atmosphere’s object like Broadcaster. As simple as:

More WebContainer supported

Atmosphere 0.7 now support all flavor of Jetty 7 and 8 Websocket implementation, as well a GlassFish v3.1 WebSocket API. Tomcat 7 Servlet 3.0 implementation works also perfectly well.

Broadcaster new API

The Broadcaster API has been heavily improved and you can now look up per request Broadcaster and also you can configure Atmosphere to broadcast value when a resume operation occurs, etc. All new features are available to all Broadcaster. See the API for more information

What’s next

The Atmosphere 0.8 release should happens before the summer and will include Socket.IO support, Google App Engine channel support, Cometd 2.2.x support, unified Atmosphere Client Javascript library and of course all the requests asked by the community.

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.

Categories: Atmosphere, Comet, JQuery, Websocket

Friday’s Trick #5: Per Request Filtering of WebSocket/Comet Server Side Events

November 26, 2010 1 comment

This week I will describe how you can filter, transform and aggregate WebSocket/Comet’s server side events per request using the Atmosphere Framework.

As you may know, Atmosphere already support global filtering for a set of WebSocket/Comet connection that are associated with a Broadcaster. Those filters are called BroadcastFilter and are applied every time a server side event (SSE) is broadcasted.  In that case, all connections associated with the Broadcaster, which include WebSocket, long-polling and http streaming connections will receive a SSE that may have been transformed by a BroadcastFilter. As an example, in order to support http streaming in Internet Explorer, the following BroadcastFilter needs to be added (in web.xml or programmatically):

public class JavaScriptClientFilter implements BroadcastFilter {
    private final AtomicInteger uniqueScriptToken = new AtomicInteger();

    @Override
    public BroadcastAction filter(Object message) {
        if (message instanceof String) {
            StringBuilder sb = new StringBuilder("<script id=\"atmosphere_")
                    .append(uniqueScriptToken.getAndIncrement())
                    .append("\">")
                    .append("parent.callback")
                    .append("('")
                    .append(message.toString())
                    .append("');</script>");
            message = sb.toString();
        }
        return new BroadcastAction(BroadcastAction.ACTION.CONTINUE, message);
    }
}

If we use the Atmosphere JQuery PubSub sample, which is defined 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);
    }

BroadcastFilter will be invoked after the publish method return. Hence the browse generates SSE “hello sent using websocket” to be broadcasted to all connections associated with the Broadcaster’s “topic”, the remote browser will receive the transformed message

<script id="atmosphere_0">parent.callback('hello sent using websocket');</script> 

If you use the Atmosphere JQuery Plugin, the IE specific code for supporting http streaming will be executed. But that solution is far from optimal because we do process every message independently of the browser user-agent, which is a waste of resource. The JQuery Plugin will have no problem parsing the message, but it would be far more optimal if we could transform SSE only when IE is used. This is where the PerRequestBroadcastFilter comes into the picture. To implements a per request transformation, all we need to do is:

public class JavascriptClientFilter implements PerRequestBroadcastFilter {

    private final AtomicInteger uniqueScriptToken = new AtomicInteger();

    @Override
    public BroadcastFilter.BroadcastAction filter
                   (HttpServletRequest request, Object message) {

        if (request.getHeader("User-Agent") != null) {
            String userAgent = request.getHeader("User-Agent").toLowerCase();
            if (userAgent != null && userAgent.indexOf("MSIE") != -1
                    && message instanceof String) {
                StringBuilder sb = new StringBuilder
                    ("<script id=\"atmosphere_")
                    .append(uniqueScriptToken.getAndIncrement())
                    .append("\">")
                    .append("parent.callback")
                    .append("('")
                    .append(message.toString())
                    .append("');</script>");
                message = sb.toString();
            }
        }
        return new BroadcastFilter.BroadcastAction
            (BroadcastFilter.BroadcastAction.ACTION.CONTINUE, message);
    }

Now we talk! With the above, our SSE is only transformed when the IE browser is used. Filtering WebSocket’s message can also be transformed using the same technique. If you have play/read with the JQuery PubSub, the sample can be used with WebSocket/Comet and the JQueryPubSub code described above. When the browser send form param via a Websocket connection, we need to extract the form data in order to broadcast it back. A simple way to do it is by:

public class FormParamFilter implements PerRequestBroadcastFilter{

    @Override
    public BroadcastFilter.BroadcastAction filter
          (HttpServletRequest request, Object message) {

        if (request.getHeaders("X-Atmosphere-Transport").equals("WebSocket")) {
            if ( (message instanceof String) 
               && ((String) message).indexOf("=") != -1) {
                message =  message.toString().split("=")[1];
            }
        }
        return new BroadcastFilter.BroadcastAction
             (BroadcastFilter.BroadcastAction.ACTION.CONTINUE, message);
    }
}

With the above filter we are parsing the form param value only when Websocket is used, in order to extract the SSE we want to broadcast to all other connections. Of course, you can do much more complex operations inside filters!

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.

Categories: Atmosphere, Comet, JQuery, Websocket