Thursday, April 4, 2013

On the way to making CXF JAX-RS run easily in your application container

Awhile back I posted an entry on how to get CXF JAX-RS loaded successfully within your favorite Java EE application container, and specifically within the containers like JBoss or Glassfish which have their preferred JAX-RS implementations actively supported.

I think it was a good enough initial step but it proved to be quite incomplete, with users reporting CXF failing to handle the objects of some of JAX-RS core types like Response.

In this rather technical post I will give an update on the situation.


What typically happens is that when Glassfish or JBoss loads a CXF-enabled application, the active subsystem (Jersey or RestEasy based) will still intercept the runtime  or application code doing a code like "Response.ok().build()" - this static sequence of calls will end up being processed by this subsystem which leads to a somewhat unusual case, where the CXF runtime ends up processing 'foreign' JAX-RS Response objects - attempting to cast to the CXF-aware Response object breaks the application.

So what we've decided to do now is to start working on making CXF JAX-RS completely isolated from the loaded third-party JAX-RS libraries, by minimizing and when possible completely removing the calls like "Response.fromResponse" which lead to the 3rd party subsystems intercepting the control. This makes CXF JAX-RS more robust when loaded alongside other JAX-RS runtimes, and also marginally faster - the cost of getting from the static code sequence to the actual Response builder implementation capable of producing Response is not completely negligible.

This is not possible to avoid completely - for example, you custom filter, exception mapper or indeed the user code will inevitably create a JAX-RS Response instance which will be 'foreign' to the CXF runtime.  In these cases CXF will simply copy such Responses into its own Response implementation. 

I hope it will make it very easy eventually to get CXF JAX-RS up and running in the latest JBoss and Glassfish distributions, due to it becoming effectively self-contained. Some more runtime code modifications may prove to be required but IMHO we are on the right path.

It is very well understood that for a given container it makes a lot of sense to optimize around a selected JAX-RS implementation, specifically in case of JBoss and Glassfish we are talking about well-known and recognized implementations.

This effort is all about helping those users who have decided to work with CXF JAX-RS in these containers continue doing so - this is all to it really :-).

2 comments:

Anonymous said...

Hi I am running jetty 9 with cxf 2.7.3, I want to use Async and continuation. Somehow I am getting ContinuationProvider null from message context.

ContinuationProvider provider = (ContinuationProvider) this.messageContext.get(ContinuationProvider.class.getName());

I have declared MessageContext like:
@Context
private MessageContext messageContext;

I came to know your name from http://osdir.com/ml/issues-cxf-apache/2013-07/msg00089.html. Seems you have fixed this issue but I am still facing this issue. Your help is appreciated.

Sergey Beryozkin said...

Are you seeing null at the initial attempt to get the provider ? If so I'm not sure why - this can be Jetty 9 issue may be, we have tests with Jetty 8.

The issue where the provider was null on resumed calls has just been fixed in CXF 2.7.7 - use PhaseInterceptorChain.getMessage() to get to it if you have to stay with CXF 2.7.3.

Also consider switching to using JAX-RS 2.0 AsyncResponse.

Hope the above helps.

Please note: if you have follow-up questions - please post them to CXF users list, thats needs to be done for the possible benefit of other users, thanks.