Wednesday, December 17, 2008

Managing contexts in CXF JAXRS

In JAXRS, a number of classes representing various features of a given request exist, as opposed to a composite WebServiceContext in JAXWS which lets get to individual contexts and message properties.

Imagine this JAXRS resource class which needs to know where the request came from, how secure it is, what the structure of the request URI is, what servlet context parameters corresponding to a given request are, what HTTP headers are involved and if certain request preconditions are met. And if you're writing a composite message body provider then, in addition to the above requirements, you also want to query other available providers as well as to check if a certain context resolver is available.

How unreatistic these requirements are ? It's likely they won't arise in many cases at the same time but likewise it's likely they'll will have to be met in some cases.

So here's a portable JAXRS code showing how you can get an access to all the contexts :


public class CompositeMessageReader
implements MessageBodyReader<Composite> {

@Context UriInfo u;
@Context SecurityContext sc;
@Context HttpHeaders h;
@Context Request r;
@Context ServletContext sc;
@Context HttpServletRequest httpR;
@Context ContextResolver contextR;

// use the injected contexts

}



And here's a CXF JAXRS specific code on how you can get an access to all the contexts plus the properties of the underlying message.


public class CompositeMessageReader
implements MessageBodyReader<Composite> {

@Context org.apache.cxf.jaxrs.ext.MessageContext mc;
// use the injected contexts
mc.getSecurityContext();
mc.getHttpHeaders();
mc.getUriInfo();
mc.getContextResolver(JAXBContext.class)
mc.getRequest();
mc.getServletContext();
mc.getServletConfig();
mc.getHttpServletRequest();
mc.getHttpServletResponse();

FutureJAXRSContext newContext =
mc.getContext(FutureJAXRSContext.class);

mc.get(PROPERTY_KEY);

}

I'm contradicting here to my previous post where I'm whining :-) about the JAXRS portability.
But you know how long would it take you to get back to a portable JAXRS code.

JAXRS Wish List

I think I won't say anything new by repeating that a JAXRS specification has been a success.

It brings so many new annotations into a Java code but the main goal behind it, at least as far I see was to popularize the REST paradigm among java developers and surely, the goal has been achieved.

Marc Hadley, Paul Sandoz and indeed all the experts who contributed to the JAXRS specification have done a fantastic job. And no doubts more is to come from newer versions of JAXRS.

So here's my wish list. It's not a long one. May be it's a bit early given that JAXRS 1.0 was only released last September but here it goes :

Please focus on the Portability.
There's no uniform way to express that a given service class is a singleton. There's no portable client api - why is that ? In JAXWS one can do a portable code which creates and consumes services. There's no uniform way to query for a document describing a service.

That's it really - not a long list indeed :-)

Tuesday, December 9, 2008

CXF JAXRS Keeps Getting Better

I could not resist it, even though I'm not a Christina Aguilera's fan :-)

CXF JAXRS is catching up. Jersey is an extremely strong player, and I have little doubt about the top quality of other JAXRS implementations - but their CXF competitor has something to say on its own - right now.

CXF is there to offer a number of approaches toward building serious web services. The fusion of JAXWS and JAXRS is likely to appeal to many developers and this is just one of the areas where CXF JAXRS can play its part.

Stay tuned.

Monday, December 1, 2008

Continuations in CXF

It's a classic problem really, how a service can help a client to submit a request and obtain a response asynchronously. A number of approaches exist :

* Client does an invocation on a web service and provides an address to reply to - this requires a client to have a web service of its own for the callback to eventually arrive while on the server side, for the (HTTP) transport thread be released, a typical HTTP 201 may be sent back as an initial acknowledgement, depending on if it's a typical two-way or so-called one way operation.

* Service responds with a resource address a client needs to poll for the results be eventually obtained which requires a client to structure the code accordingly.

There's another approach emerging - using suspended invocations or continuations. Actually, it's not a new approach but with Jetty supporting and Servlet 3 embracing them the suspended invocations are bound to enter the mainstream.

Please read a Jetty Continuations page on when using continuations can make sense.

Without further ado, here's a sample code fragment showing how one can do continuations in CXF in a transport neutral way. CXF Continuations API is currently supported for SOAP-HTTP services based on Jetty 6 and SOAP-JMS services. CXF JAXRS runtime supports them too :



import org.apache.cxf.jaxrs.ext.MessageContext;

@Path("/")
public class WebResource {

private @Context MessageContext context;
private Executor executor = ...;

@GET @PATH("/quote/{id}")
public Quote getQuote(@PathParam("id") String policyId) {

String key =
"org.apache.cxf.continuations.ContinuationProvider";
ContinuationProvider provider = context.get(key);

Continuation c = provider.getContinuation();
synchronized (c) {
if (c.isNew()) {
FutureTask f = new FutureTask(
new CallablePolicyHandler(policyId, c));
c.setUserObject(f);
executor.execute(f);
c.suspend(timeout);
} else {
FutureTask f = (FutureTask)c.getUserObject();
if (f.done()) {
return f.get();
}
c.suspend(decreaseTimeout());
}
}
}
}


What happens is that when continuation.suspend(timeout) is called, the current transport thread gets immediately released and a pending request is put back in the requests queue. Once an asynchronous activity gets completed, it will call continuation.resume() - in this example it's done somewhere inside a CallablePolicyHandler, which results in a suspended request be returned to this method. The code now checks if the FutureTask is done and if not then it means an initial timeout was not enough for the asynchronous activity to complete - in this specific case we decide to suspend a request yet again but with a smaller timeout.

Note that in case of JAXWS the code will be absolutely identical for this specific sample, except that a ContinuationProvider instance will have to be obtained from a JAXWS WebServiceContext.getMessageContext().

Both CXF JAXRS MessageContext and JAXWS MessageContext will have to be used when combining JAXWS and JAXRS. I think we may need to come up with a common MessageContext interface for such cases.

Finally, this CXF Continuations API won't change when Jetty 7 (and indeed Tomcat) implementing Servlet 3 specification will ship.

For another example see this CXF-based demo in a Jetty 7 trunk. It shows the use of JAXWS asynchronous handlers among other things. Note in this demo a new ServletRequest.suspend() call is used as opposed to ContinuationsSupport.getContinuation() and Continuation.suspend() pair of calls in Jetty 6. Nothing to worry about though if you're a CXF Continuations API user - it all will be handled internally without you noticing it.