In an earlier post, we stepped through the building of an asynchronous web service, deployed in Java SE. I saved my comments for this post to keep things a little cleaner. But there are some loose ends to discuss, especially when you hear my motivation for building an asynchronous web service in the first place.
Normally, you want to invoke a service asynchronously because you expect potentially long server response times. This, I would think, is the most likely reason for wanting asynchronous invocation. For example, in a user-facing application, you don't want to block on a call, especially if your front end has other things it could be doing.
Lately, I've been spending a lot of time on "server push" applications, using frameworks like DWR (Direct Web Remoting) and CometD; these frameworks provide a clean façade for logic which either maintains long-lived HTTP connections or polls for data, for example. I'd rather not have to rely on a servlet-based framework to do this, however; if possible, I'd prefer to simply leverage the Java SE. So my ulterior motive was to see if I could use it to implement server push. Unfortunately, server push and asynchronous response are not equivalent, of course, although there's some obvious overlap. The overlap lies in that first (and, for async, only) response.
What I found most interesting about this exercise is that the asynchronous logic (at least, the logic visible to us, the developers) was manifested only on the client side. In other words, the asynchronous versions of the operation were entirely a client-side artifact -- we did nothing on the web-service side to implement asynchronicity! I did not expect that result. We just implemented a synchronous Java method on the service side, and the Java SE runtime took care of the asynchronous-invocation details for us, simply by virtue of our using the asynchronous operations of the client-side API.
I really expected, when I started this exercise, that I would generate asynchronous service-side stubs and actually implement the asynchronous logic myself. In that case, it would have been natural to assume that I could play some neat trick and continue sending data "down the pipe", rather than providing just one response and seeing the connection get closed afterwards. I'm not sure how I thought I was going to do this (groundless optimism?), but I planned on figuring that out once I got the basics working.
What we ended up with is exactly what JAX-WS advertised, and that is actually quite handy; all you have to do is to make the asynchronous call and you can go on with whatever else you need to do; the runtime takes the response, when it returns, and updates your pollable object (or calls your callback).
One thing that is appealing about this result is that you really don't need to build your web service by starting with a WSDL file, since the asynchronicity is purely a client-side artifact. In other words, if you prefer to start with a Java bean and use wsgen to generate the web service, that is fine -- you don't need to do anything else on the service side to support asynchronous invocation. It's only when you create the client that you need to worry about asynchronous invocation, but by then you already have a deployed web service, so you can generate the client-side, asynchronous API by running wsimport against the deployed web service's published WSDL file. Overall, a rather convenient result!
So, to recap:
- JAX-WS in the Java SE provides relatively straightforward support for asynchronous web-service development. The service can be developed starting Java-first or WSDL-first, as the asynchronicity doesn't come into play until the client-side artifacts are generated.
- JAX-WS does not (as far as I know at this point) support the concept of server push, by which I mean a long-lived output stream over which data can be pushed to the client.