Edit: I Previously forgot to include the project sources and people have rightly asked in the comments about it. I couldn't find the example I wrote this blog post from, but I found a similar example on my github. You can find it here
More and more it's becoming a common requirement to support some sort of bi-directional (asynchronous) channel in modern web applications. Atmosphere is a great library which does much of the heavy lifting if you're running on a Java, servlet based stack. It offers support for WebSockets, Server Side Events (SSE), Long-Polling, HTTP Streaming (Forever frame) and JSONP. There are, however, some pitfalls and, if you've not got a lot of experience in the area, it can be frustrating trying to work out whats going wrong.
Having run through the process once I thought it'd be nice to cover my implementation in some detail. Maybe you'll see something which can help you with your own configuration or implementation problems.
Overview of the stackThis is what I had in place before integrating atmosphere.
- Application server: Tomcat 7.0.32 (Must be greater than 7.0.30 for atmosphere to work correctly).
- Container: Spring 3.2 RC1 ( though anything post 3 is fine )
- Build Enginer/ Dependency Manager: Maven3
Include the DependenciesYou'll want to add the following entries to your POM :
Just a quick note about the cors-filter dependancy, you'll only need it if you want Cross-Origin-Resource-Sharing support. I thought about covering it in this article, but maybe i'll write it up as a follow up
The web.xmlIf you're not using servlet 3 already, time to upgrade. Change your web-app config to look like this:
The next step is to include the standard spring dispatcher etc to your configuration. You will probably you'll already have this anyway.
The Atmosphere Controller
Using The Atmosphere ServletI fully accept that everyone has their own pet way of setting up servlets, this is just one possible mutation. You want to add the following to your web.xml:
Pitfall 1: The broadcasterLifeCyclePolicy tells atmosphere to destroy any connections that been closed by the client, enabling it will prevent OOM (Out of Memory) issues in your application.
Pitfall 2: The recoverFromDestroyedBroadcaster prevents an exception being thrown when you try to reuse a broadcaster that you have recently destroyed ( useful if you want your client to subscribe using its own personal channel ).
So now you're able to use spring MVC alongside your atmosphere code without them stepping on each others' toes. Lets move on.
The Controller ClassMine was simple enough. It basically passes off the broadcasters that it creates to another service which whatever listeners you have configured ( Mine was RabbitMQ ) will call when they have an appropriate message.
@Configurable: Using @Configurable is a great way to use aop classweaving to inject spring dependencies into non-managed spring classes. There is extensive documentation on how to set this up in spring
Pitfall 3: Make sure you set the suspend period, or you're going to be dealing with a java.net.SocketException: Too many open files in pretty much no time.
The Service ClassAlso very simple. Using a map to store the in use channel ids -> broadcasters, the service is simply responsible for looping through the registered broadcasters and broadcasting a generic message.
The Async ClassProbably you'll have some asynchronous process which is waiting for messages, there are many possible implementations that this may take so i'll just show one of the popular ones RabbitMQ.
You'll need to make sure you add the following dependency to your pom:
RabbitMQ has a pretty clean java integration which is nice and quick to set up. The first component is a context configuration file where you bind your queues, connection factory, admin, exchanges and listeners.
Notice the reference to broadcastQueueConsumer we used there ? Lets write that now.
I've omitted the declaration of the Simple Message Converter in the context file but please dont forget about it. Once you're done you've got a pretty clean implementation of the serverside and should be ready to move onto the frontend.
JQuery frontend implementationReally its quite simple to build a small subscription handler. I've added an example of mine below :
Pitfall 4: Make sure you set enableXDR to true if you want to support cross domain requests.
Pitfall 5: To send custom request params it seems like you need to pass via url (maybe jfrancard has fixed now but not sure)
Thanks for reading, and feel free to ask any questions via a comment below or our twitter @nerd_ability