Atmosphere Websockets & Comet with Spring MVC

Since writing this guide, Spring has come out with their own Comet and Websocket implementations. I suggest you first read through their guides before deciding on atmosphere as your Comet & Websocket solution.

1. Messaging with Stomp over Websockets
2. Spring Messaging

On to the guide...

Feel free to clone the source of this project on github.
springMVC-atmosphere-comet-websockets

The Websocket protocol is defined by W3C here. The protocol is considered an HTTP upgrade protocol. Essentially what happens is, a websocket request is made by a client browser, via the HTTP protocol. Once, the request is in, the server should respond with a success. Then the browser and server establish a TCP link to handle communication from there on out. This protocol enables bi-directional communication between a client and server. Here is a link to browser and servers that support Websockets and/or Comet: comet/websocket support link

Comet is a protocol set that uses HTTP to perform the same tasks. It is a clear abuse of the protocol, but high demand has forced support on most servers. Websockets is less developed, but will be the engineers choice in the near future. Unfortunately, as of now, the AJP protocol does not support Websockets. See here. Although powerful, websockets may need to wait before release to production environments

In our example we will be working directly with server to client communication. Details about the Tomcat Websocket servlet API are not included. Instead we will use the atmosphere framework to do all the work for us. What's nice about the atmosphere framework, is that it supports both Websockets, and Comet protocols. If set up to support both, you can transition between each protocol seamlessly, without any modifications to your backend code. This demo, is an example of this.

Screen Shot of Demo


Demo Application Uses:
  1. Tomcat 7.0.27 (Required for websocket support)
  2. Atmosphere Runtime
  3. Spring MVC
  4. Web 3.0
  5. Spring Social 
Atmosphere Maven Dependency



Configuring Tomcat for Comet/Websocket support

First, locate and open the Tomcat server.xml file. This can be found in ${CATALINA_HOME}/conf/server.xml. Locate the Connector that configures your HTTP connections. Modify it as such:


Why do we change the protocol?
NIO stands for Non Blocking IO. This will allow Comet transports to be handled specifically as NIO connections. When a connection dies, it tells the server to close off any read/write resources attached to the connection.
We increase the connection timeout due to an existing bug in Tomcat. See here. **This issue is resolved as of Tomcat 7.0.28. We are expecting full websocket support with the .28 release.

Configuring Web.xml
Your web.xml requires a servlet declaration for atmosphere transactions.


The Meteor Servlet defined, will use the Spring DispatcherServlet when adding it as a param-value. Now all Spring Servlet requests are dispatched through the Meteor Servlet. For more details on each param value, click here.

Another note, atmosphere will not recognize your application as Comet supported, unless you add the following to your MET-INF/context.xml file.


The Spring MVC Controller Method


Click here, to view the source of this controller class. Some things to note. When a request is made to the method, it passes in an Atmosphere resource. This resource is attached to the client. It also has a broadcaster. By default all client's share the same broadcaster. What this method does, is schedules the client broadcaster to dispatch to the client, twitter messages every 10 seconds. Interestingly, with atmosphere we don't need to know how the server communicates to the client, we just pass it the text we want the client to see. In our case, JSON formated twitter messages.

Configuring the Client
Atmosphere has it's own javascript file to handle the different Comet/Websocket transport types and requests. By using this, you can set the Spring URL Controller method endpoint to the request. Once subscribed to the controller, you will receive dispatches, which can be handled by adding a request.onMessage method. Here is an example request with transport of websockets.


In this demo, we use jquery and jquery-tmpl to add the new twitter messages to a table. All in all, atmosphere is very useful for quick support of Comet in an existing web application.

If you are trying to add the MeteroServlet to an existing SpringMVC application. I suggest that you first add a subscription controller that handles endpoint subscriptions. Now you can configure websocket and comet Spring methods separately. You could use a context file like, comet-websocket-spring-context.xml to configure your websocket controller and services. Map this file to the MeteorServlet param-name: contextConfigLocation. Let all of your original spring stuff be handled by the original Spring DispatcherServlet you have in the web.xml. Now if you decide to use a different Comet framework later, you aren't required to nit pick out Comet supported Controller methods. Make sure your meteor servlet is set to load on startup first. Now choose a meaningful URL for your Comet and Websocket endpoints. For example: "feeds". In the servlet mapping, set your url-pattern attribute to it: "/feeds/**". This will override your original pattern mapping. Now any requests coming into /feeds will be handled by the MeteorServlet. All other requests are un-effected by atmosphere.

Not all information on Atmopshere setup can be found in this guide. There is still important information on suspending resources, resolving AtmosphereResource's, and configuring that resolver in Spring. All of this is boring, and can be found in the demo project's source code.

I would suggest cloning into the demo project I have created, to get yourself more familiar with the framework. 

10 comments :

  1. Is this also working with Glassfish 3.1?
    When checking with TamperData I can only see 404 errors.

    ReplyDelete
    Replies
    1. Try using my instruction on setting up with STS. Instead of downloading Tomcat Server, try using glassfish instead. Let me know how it pans out. Here is a link to the instructions:
      https://github.com/keaplogik/springMVC-atmosphere-comet-websockets/blob/master/README.md#steps-for-running-on-sts-or-eclipse

      Delete
  2. I never did test this on glassfish, only Tomcat. I believe some extra configuration is required. Also, ensure that your pointing to localhost:..../springMVC-atmosphere-comet-websockets.

    And issues with Glassfish can be found here: https://github.com/Atmosphere/atmosphere/wiki/GlassFish-WebSocket-Issues

    ReplyDelete
  3. Hi Billy,

    Could you please help to import the project into STS or eclipse?
    Thanks in advance.

    ReplyDelete
  4. I couldn't find a simple way to do this, but here it goes. I used STS.

    Pull down project from github like so:
    1. go to File -> Import
    2. Select Git -> Projects from Git -> Click Next
    3. Select URI -> Click Next
    4. URI: https://github.com/keaplogik/springMVC-atmosphere-comet-websockets.git
    Host: github.com
    Click Next
    5. Click Next
    6. Specify destination -> Click Next
    7. Click Cancel

    Now Import the project as a Maven Project like so:
    1. File -> Import
    2. Maven -> Existing Maven Projects -> Click Next
    3. In "Root Directory" Browse to this projects folder
    4. Click Finish

    Now Add the Tomcat Server:
    1. In the Package Explorer -> Right click on Servers -> New -> Other
    2. Click Server-> Server -> Click Next
    3. Chooses Apache Tomcat 7.0 Server -> Click Next
    4. Browse to where you installed Tomcat 7.0.27 or newer -> Click Finish
    5. If you haven't downloaded Tomcat here is the link: http://apache.mirrors.tds.net/tomcat/tomcat-7/v7.0.34/bin/apache-tomcat-7.0.34.zip

    Finally Run on the Tomcat server
    1. Right click on the project in the project explorer. Click Run as -> Run on Server
    2. Click the Tomcat Server, and click Finish.

    And your up and running!


    ReplyDelete
    Replies
    1. Hi Billy,

      My apology for the late reply as I was running out of internet connection for last couple of days. It worked fine according to your steps. I just had to add the version for the tomcat-maven-plugin. And then right click project->Maven->Update Project... to resolve the dependencies

      Thanks and Regards,
      -Zia

      Delete
  5. 1- I run this project 3 month ago and it worked very good
    however when i am trying now i am getting connection error from twitter , i am using the code from github without any change , any idea what cause this issue ?


    WARN : org.atmosphere.cpr.DefaultBroadcaster - Callable exception
    org.springframework.web.client.ResourceAccessException: I/O error: Connection timed out: connect; nested exception is java.net.ConnectExcept
    ion: Connection timed out: connect
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:206)
    at org.springframework.social.twitter.api.impl.SearchTemplate.search(SearchTemplate.java:65)
    at com.keaplogik.webapp.controllers.HomeController$2.call(HomeController.java:88)
    at com.keaplogik.webapp.controllers.HomeController$2.call(HomeController.java:81)


    2- what i need is to have a long polling meaning to open a connection between client-server and to make this connection alive so client will be able to send data to server (i prefer http/rest and not socket)
    does comet/atmosphere is the right choice or maybe DWR ?
    is there any servlet 3.0 support for this and how - what i need to configure in tomcat ?
    I am using Spring-MVC 3.2 in my web app and tomcat

    any help will be appriciate

    ReplyDelete
  6. Hi Billy this example is very good but it's not working any longer since twitter changed their API in the version 1.1 can you crosscheck and maybe update the example with the new version?

    ReplyDelete
    Replies
    1. Thanks, I have updated the demo application and example code.

      Delete
  7. Updated application to use latest Twitter API with OAuth enabled.

    ReplyDelete