Atmosphere Websockets & Comet with Spring MVC
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:
- Tomcat 7.0.27 (Required for websocket support)
- Atmosphere Runtime
- Spring MVC
- Web 3.0
- 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.
Is this also working with Glassfish 3.1?
ReplyDeleteWhen checking with TamperData I can only see 404 errors.
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:
Deletehttps://github.com/keaplogik/springMVC-atmosphere-comet-websockets/blob/master/README.md#steps-for-running-on-sts-or-eclipse
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.
ReplyDeleteAnd issues with Glassfish can be found here: https://github.com/Atmosphere/atmosphere/wiki/GlassFish-WebSocket-Issues
Hi Billy,
ReplyDeleteCould you please help to import the project into STS or eclipse?
Thanks in advance.
I couldn't find a simple way to do this, but here it goes. I used STS.
ReplyDeletePull 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!
Hi Billy,
DeleteMy 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
1- I run this project 3 month ago and it worked very good
ReplyDeletehowever 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
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?
ReplyDeleteThanks, I have updated the demo application and example code.
DeleteUpdated application to use latest Twitter API with OAuth enabled.
ReplyDelete