tags:

views:

3639

answers:

6

Hello fellow developers,

Is there any way to "subscribe" from GWT to JSON objects stream and listen to incoming events on keep-alive connection, without trying to fetch them all at once? I believe that the buzzword-du-jour for this technology is "Comet".

Let's assume that I have HTTP service which opens keep-alive connection and put JSON objects with incoming stock quotes there in real time:

{"symbol": "AAPL", "bid": "88.84", "ask":"88.86"}
{"symbol": "AAPL", "bid": "88.85", "ask":"88.87"}
{"symbol": "IBM", "bid": "87.48", "ask":"87.49"}
{"symbol": "GOOG", "bid": "305.64", "ask":"305.67"}
...

I need to listen to this events and update GWT components (tables, labels) in realtime. Any ideas how to do it?

+1  A: 

Some preliminary ideas for Comet implementation for GWT can be found here... though I wonder whether there is something more mature.

Alexander Temerev
+1  A: 

Also, some insight on GWT/Comet integration is available there, using even more cutting-and-bleeding edge technology: "Jetty Continuations". Worth taking a look.

Alexander Temerev
+2  A: 

there is indeed a cometd-like library for gwt - http://code.google.com/p/gwteventservice/

But i ve not personally used it, so cant really vouch for whether its good or not, but the doco seems quite good. worth a try.

Theres a few other ones i ve seen, like gwt-rocket's cometd library.

Chii
+3  A: 

I have used this technique in a couple of projects, though it does have it's problems. I should note that I have only done this specifically through GWT-RPC, but the principle is the same for whatever mechanism you are using to handle data. Depending on what exactly you are doing, there might not be much need to over complicate things.

First off, on the client side, I do not believe that GWT can properly support any sort of streaming data. The connection has to close before the client can actually process the data. What this means from a server-push standpoint is that your client will connect to the server and block until data is available at which point it will return. Whatever code executes on the completed connection should immediately re-open a new connection with the server to wait for more data.

From the server side of things, you simply drop into a wait cycle (the java concurrent package is particularly handy for this with blocks and timeouts), until new data is available. At that point in time, the server can return a package of data down to the client which will update accordingly. There are a bunch of considerations depending on what your data flow is like, but here are a few to think about:

  • Is a client getting every single update important? If so, then the server needs to cache any potential events between the time the client gets some data and then reconnects.
  • Are there going to be gobs of updates? If this is the case, it might be wiser to package up a number of updates and push down chunks at a time every several seconds rather than having the client get one update at a time.
  • The server will likely need a way to detect if a client has gone away to avoid piling up huge amounts of cached packages for that client.

I found there were two problems with the server push approach. With lots of clients, this means lots of open connections on the web server. Depending on the web server in question, this could mean lots of threads being created and held open. The second has to do with the typical browser's limit of 2 requests per domain. If you are able to serve your images, css and other static content fro second level domains, this problem can be mitigated.

bikesandcode
+1 Excellent post with some great insights.
day_trader
+1 This is exactly how I do it. The solution to the "lots of threads" problem is spelled "suspendable requests" in the Servlet 3.0 spec. Jetty has early support for this in 7.0. Tomcat calls it something else.
Per Wiklander
+4  A: 

There is a GWT Comet Module for StreamHub:

http://code.google.com/p/gwt-comet-streamhub/

StreamHub is a Comet server with a free community edition. There is an example of it in action here.

You'll need to download the StreamHub Comet server and create a new SubscriptionListener, use the StockDemo example as a starting point, then create a new JsonPayload to stream the data:

Payload payload = new JsonPayload("AAPL");
payload.addField("bid", "88.84");
payload.addField("ask", "88.86");
server.publish("AAPL", payload);
...

Download the JAR from the google code site, add it to your GWT projects classpath and add the include to your GWT module:

<inherits name="com.google.gwt.json.JSON" />
<inherits name="com.streamhub.StreamHubGWTAdapter" />

Connect and subscribe from your GWT code:

StreamHubGWTAdapter streamhub = new StreamHubGWTAdapter();
streamhub.connect("http://localhost:7979/");
StreamHubGWTUpdateListener listener = new StockListener();
streamhub.subscribe("AAPL", listener);
streamhub.subscribe("IBM", listener);
streamhub.subscribe("GOOG", listener);
...

Then process the updates how you like in the update listener (also in the GWT code):

public class StockListener implements StreamHubGWTUpdateListener {
      public void onUpdate(String topic, JSONObject update) {
          String bid = ((JSONString)update.get("bid")).stringValue();
          String ask = ((JSONString)update.get("ask")).stringValue();
          String symbol = topic;
          ...
      }
}

Don't forget to include streamhub-min.js in your GWT projects main HTML page.

Corehpf
Hey. Is there a way to disable the browser from doing the annoying 'loading' symbol on the cursor i.e. loading it in Chrome, brings up an annoying white circle. As you can imagine, having an application that needs to be open for a long time and having that loading symbol up constantly gets rather annoying! Thanks.
day_trader
A: 

Here you can find a description (with some source samples) of how to do this for IBM WebSphere Application Server. Shouldn't be too different with Jetty or any other Comet-enabled J2EE server. Briefly, the idea is: encode your Java object to JSON string via GWT RPC, then using cometd send it to the client, where it is received by Dojo, which triggers your JSNI code, which calls your widget methods, where you deserialize the object again using GWT RPC. Voila! :)

My experience with this setup is positive, there were no problems with it except for the security questions. It is not really clear how to implement security for comet in this case... Seems that Comet update servlets should have different URLs and then J2EE security can be applied.