Friday, March 30, 2012

Custom JAX-RS Contexts in CXF 2.6.0

CXF 2.6.0 is due to be released soon, with several new features likely to get the developers interested.

CXF is about to become much more OSGI-friendly which will open the way for many new interesting enhancements to come thanks to Dan and Christian leading this major refactoring effort.

The JAX-RS frontend has benefited (as usual :-)) from the core CXF improvements. One of the positive side-effects was that the initial go at splitting the fairly big JAXRS module was attempted.

Most of the optional JAX-RS providers were moved with all their optional dependencies to the new cxf-rt-rs-extension-providers module, Christian's refactoring of the clustering feature helped to drop the JAX-RS specific extension with JAX-RS clients now being able to use same fail-over feature configuration as their JAX-WS brothers :-), and the code to do with the WADL to Java code generation made its way to its real home, the cxf-tools-wadlto-jaxrs module. The CORS code now lives in cxf-rt-rs-security-cors, it needs to as enforcing the CORS across multiple servers will very likely require more enhancements to the current filter and the couple of annotations.

Finally the FIQL search extension code got moved to the new cxf-rt-rs-extensions-search module. I think this extension has a lot of offer and more enhancements will start coming in sooner or later due to the power and simplicity of FIQL.

Moving the FIQL code presented a challenge, how to get the core JAX-RS frontend to populate the SearchContext offering an optimized access to the FIQL queries ? The name of this custom JAX-RS Context class is hard-coded within the frontend in the earlier CXF versions but with the extension now moving away it was not an option any more.

The new ContextProvider extension was to be the answer I was looking for and here is the implementation which creates a SearchContext instance by relying on the CXF Message class which has all the information about the current request. The last thing that needs to be done is to get the ContextProvider registered with JAX-RS endpoints.

It is actually quite a major enhancement, now the users can inject whichever contexts they like. For example, JAX-RS 1.1 HttpHeaders context offers a number of utility methods for accessing the HTTP headers. Lets say you'd like to help the application developer to handle Origin headers but HttpHeaders can not help. Well, write a custom OriginHeader ContextProvider, extract the Origin out of the message and make it really easy for the application developer to access various Origin parameters. You can use ContextProviders whenever you'd like to offer an optimized access to some of the information available in the current request.

I believe Jersey was offering a similar extension probably from the very early start. One can not deny Jersey was an absolute star :-) at the start of the JAX-RS, and they continue to be the major JAX-RS implementation, but CXF just keeps catching up even though it took us a bit of time to get to the ContextProvider.

Note ContextProvider looks similar to JAX-RS ContextResolver but they actually serve different purposes with the latter meant to simplify processing the data possibly involving the custom media types, see this method. I believe it was originally introduced to handle custom JAXBContexts. After thinking a bit about reusing ContextResolver I decided not to in order to avoid possible conflicts.

Finally, having to register the ContextProvider providing SearchContext instances led to another enhancement request. In CXF one needs to explicitly register custom JAX-RS providers and I believe it works well most of the time due to the flexibility offered by the explicit configuration approach. However, having an option to get simple basic providers auto-discovered would be useful too - thus a new enhancement request to support the optional class scanning is now pending.

It is always useful to refactor and simplify code - more often than not it has the positive side-effect of the new features added :-)

2 comments:

Anonymous said...

Sergey,

Nice post. I was trying to inject the jaxrs messagecontext and search contexts using CXF 2.6.0, but contexts are always null.

I have provided "cxf-rt-rs-extension-providers" dependency as well.

Also injected "SearchContextProvider" explicitly.

Any idea?

Thanks
Chris

Sergey Beryozkin said...

cxf-rt-rs-extension-search should do for SearchContext.
If you have both MessageContext and SearchContext not injected then it must be to do with Spring proxifying the beans.

Try forcing CGLIB or introduce a dedicated interface with a method such as '@Context setSearchContext(SearchContext sc)', etc. Please ping me on IRC or cxf users if you have more questions