Getting GWT to work with Servlet 3 Async Requests
For one of our projects, we use a GWT client that needs to be updated in near-real time (< 1 second delay) when something relevant happens on the server. There are multiple ways of doing it, but I tried to get it working with the new Servlet 3 feature: Asynchronous Http Request handling.
Read on to find out how I got it done.
Servlet 3 and Asynchronous Requests
Until now requests to servlets require the calling thread to block until the whole response has been written to the HttpServletResponse. Once the method returns, the servlet container will commit the contents written to the response and send it to the client.
With Servlet 3, that isn’t necessary anymore. You can mark a request as asynchronous by calling the “startAsync()” method on the request. This tells the servlet container not to finish the request once the method returns, but to wait for a “complete” invocation.
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ... { final AsyncContext ctx = req.startAsync(); someAsyncProcess.run(new Runnable(){ @Override public void run() { // do stuff ctx.complete(); } }); }
The main advantage here is that when a request needs to wait for data, the thread can be use for something else. Given that sockets are a lot cheaper resource than threads, it is a good way to deal with a large number of requests.
Our use case
Our application uses a GWT front-end. One of the components in this frontend needs to be continuously updated with events from the server. Initially, we implemented this using a poller, that polls the server for new events each 500ms. Although the polling action on the server is quite cheap (it checks a component available in memory), setting up a request just to return a “there is no new information” response each time takes up valuable server and network resources.
We wanted a form of long polling, where a “no data available” is not sent to the user. Instead, it would wait for data to become available and send it to the front-end. Until servlet 3, this required either 3rd party components or a blocking thread. We didn’t want either of them.
What we can do with Servlet 3 Async is return the thread, and only use a thread (from a thread pool) to send the client’s response when it is ready. Not only is it a lot cheaper than the short polling, it also responds faster as data is sent to the client immediately when it is available.
Getting it to work in GWT
Client-server communication in GWT is done using RPC. You need to define 2 interfaces: MyServiceName and MyServiceNameAsync. The first is used on the server side to implement the service operation, the second is used client side, as javascript requires asynchronous execution to prevent the browser from hanging.
Let me put it simply: I want to implement the Async interface on the server. But GWT doesn’t support that. If forces you into the direct-response model of servlet 2.x.
So, I hacked my way through GWT’s RemoteServiceServlet and created a variant that allows you to implement the Async service interface instead. The result can be found in this class. It’s not really clean code yet, but it does the job.
If you want to use this class to create you need to create a Service implementation that extends this class, and implements the YourServiceNameAsync interface. You still need the YourServiceName interface, as GWT uses it to find method names and return types for serialization. Use the Callback to notify the container that the return value (or exception) is ready to be sent to the client.
Don’t forget to add the <async-supported>true</async-supported> tag in your web.xml servlet definition. If you forget that (which I did), you’ll get exceptions stating that Async support is not available.
Then it’s time to run. Make sure you run it in a container that supports the servlet 3 spec, such as Tomcat 7. The GWT SDK comes with a Jetty runner that doesn’t support Servlet 3. They also included the servlet 2.5 API in there. Just make sure Servlet 3 API is on the classpath before the 2.5 version, and you should be fine.
Conclusion
In the end, I got it all working, and the client is very responsive when the server send a notification. I certainly hope Google decides to provide their own implementation of this servlet. If you have any questions or other ideas, don’t hesitate to drop a comment or contact me through JTeam.