A Opionion Poll with Live Updates using Atmosphere

Hi all,

My favorite show in television is Airtel Super Singer Junior (that identifies and encourages music talent in kids). The season 3 of the show had its Grand Finale yesterday(26th Oct 2012). Final results were based on the Audience poll. Inspired by this – I wanted to try creating a web app that can leverage the ATMOSPHERE SERVER PUSH to show live updates as votes are being recorded.

I wanted to use Jersey RESTful webservices & a simple HTML form for gathering the VOTES. Reasoning behind this choice was that – existing user flows in applications I work with, have the UI interacts with RESTful webservices to capture data.

I wanted to understand how the java based atmosphere framework can be plugged into this scheme and be used for server push purposes alone. As a week old toddler in Atmosphere – I’m still exploring the framework – so there could be other, probably better integrations possible. But this acted as a very good exercise for me to explore different parts of atmosphere.

So here we go –

1. As a first step – I created a pom.xml (I extended the pom.xml from Atmosphere samples base directory). My pom.xml was again a verbatim replica of the pom.xml shipped with rest-chat sample.

2. I updated the web.xml to redirect all /rest/* URLs to Jersey REST Servlet. Similarly /assp/* (assp was actually airtel super singer poll that was the initial trigger ) URLs to Atmosphere Servlet

3. Next I wanted 2 sets of files

a. Voting related files based on JERSEY REST that consists of

(i) vote.html – basic html form with radio buttons (representing choices in the opinion poll)

(ii) voting.js – my custom script that will send the votes to server through ajax

(iii) VoteResource.java – Jersey REST based resource that will have the @POST method.

(iv) Contestant.java – A simple POJO with 2 attributes – contestantName, noOfVotes. For making sure that the noOfVotes  is incremented in a consistent way from multiple threads of the web application – I used a atomic long ( incrementAndGet is used to increment the votes)

(v) VoteMap.java – For the purposes of this post – this will be our in memory store and will be modeled as a singleton. This will contain a ConcurrentHashMap<String,Contestant> – contestantName will be the key and the instance of Contestant POJO will be the value.

In a typical flow – users will visit vote.html to make their choice for the opinion poll. This information will be posted back to server through ajax. @POST method in VoteResource will be invoked to record the vote. The contestantName will be used to lookup the Contestant instance from the voteMap. Increment method of Contestant POJO will use increment method of atomic long to increment the votes.

After updating the no of votes – it has to send a update to all the connected clients through server push. It will use the

MetaBroadcaster.getDefault().broadcastTo(“/”, VoteMap.getInstance().toString());

Above line does the magic to sending the JSON containing contestants and votes to clients.

For purposes of this post – I overrode the toString method of Contestant & VoteMap to return a JSON representation of these objects. I would definitely look forward to making use of automatic JSON conversion using JAXB / Jackson Mapping capabilities of Jersey.

Till now – this has been a regular JERSEY REST project that records the vote choices from UI sent through ajax.

b. Server Push related files that will display the results sent periodically through server push.

(i) results.html – a simple HTML file that will display the results of the poll as a bar chart

(ii)application.js – will use atmosphere based javascript APIs to connect to the server. Further everytime, server sends a update – it will parse the JSON to update the graph

(iii) jqBarChart.js – third party http://www.workshop.rs/jqbargraph/ that will be used for plotting the graph

(iv) AsspResource.java – Main Atmosphere based resource. It has a @GET method annotated additionally @Suspend. As explained in docs – requests to this resource through GET method will be suspended.

When a broadcaster sends data – it is received by these suspended broadcasters

I’m cleaning up the source code removing all unnecessary code – would attach the same soon!!

Here we go – I’ve uploaded the source code zip file to ubuntu one – rest-assp.zip

 

Getting started with Atmosphere

Atmosphere is a cool framework – I wanted to run atmosphere samples in my ubuntu 12.10

sai@sai-home:~$ git clone https://github.com/Atmosphere/atmosphere

sai@sai-home:~$ cd atmosphere/

sai@sai-home:~/atmosphere$ ls
integration-tests  modules  README.md  scripts
license            pom.xml  samples    tmpFile

sai@sai-home:~$ cd samples

sai@sai-home:~/atmosphere/samples$ mvn clean install

This did the magic of creating all the different war files in the target directory of each of the samples.

I then tried deploying the war files to tomcat 7 – but somehow it was not working. Worked very fine with Jetty 8.1.

sai@sai-home:~/atmosphere/samples$ cd ~/Downloads/jetty-distribution-8.1.7.v20120910/
sai@sai-home:~/Downloads/jetty-distribution-8.1.7.v20120910$ java -jar start.jar jetty.port=9090

Launch the sample by launching for instance the atmosphere-chat-sse

http://localhost:9090/atmosphere-chat-sse/

I could chat from 2 tabs.

Now that I have the samples working in jetty – I’d be trying my own samples in the next few days. Also I’d be interested in getting this to run in tomcat 7 as well

I found that the chat-sse sample was already fine in tomcat 7. Only atmosphere-twitter-live-feed sample was NOT working with tomcat 7. I was checking firebug what was happening when the application was deployed with tomcat 7. Found that the js files were not getting downloaded from the webapp context path for atmosphere-twitter-live-feed.

So after some debugging – I found the servlet mapping in web.xml

<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

I just had a thought that this could intercept all requests including those for static resources. So I changed it to

<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/tweet/*</url-pattern>
</servlet-mapping>

And in the index.html – I had to update the URL to which client sends a subscribe request

function subscribe() {
var request = { url : document.location.toString() + ‘/search/’ + getElementByIdValue(‘topic’),
transport: getElementByIdValue(‘transport’),
trackMessageLength : true
};

to

function subscribe() {
var request = { url : document.location.toString() + ‘/tweet/search/’ + getElementByIdValue(‘topic’),
transport: getElementByIdValue(‘transport’),
trackMessageLength : true
};

Bingo!! it is working now in tomcat 7 as well

http://stackoverflow.com/questions/132052/servlet-for-serving-static-content – seems to indicate this difference in behavior

Server Push In Java with Atmosphere

After socket.io and node.js – I wanted to check if there is something that can be useful for enterprise java webapps that are typically deployed into Tomcat.

I had read about Jetty Supporting Server push and tomcat 7 having something similar.

Wanted something that will have server and client side pieces – very similar to socket.io on node.

Stumbled upon Atmosphere – https://github.com/Atmosphere/atmosphere

The only Portable WebSocket/Comet Framework supporting Scala, Groovy and Java — Read more

http://jfarcand.wordpress.com

Will start my exploration on that