Hello,

I encountered a class loading problem using CXF as the JAX-RS implementation in 
Equinox OSGi container. It seems that CXF, deep in its core, triggers 
unfortunately some Equinox-specific stuff that results later in the problems. I 
have no idea how to solve it and I would be thankful for any help. But let's 
start from the beginning.

We want to create a RESTful service based on Apache Olingo library, which uses 
JAX-RS, and we want to run the service in Equinox OSGi container with Jetty. 
Although we plan to move to another container in the future, we can't do that 
right now, so we are stuck with Equinox at this moment. For completeness our 
sample RESTful service is based on a sample from Olingo, we use Equinox 3.8.0 
with Apache Aries 1.1.0 (for Blueprint) and CXF 2.7.8, Olingo 1.2.0 and Jetty 
8.1.5. I can provide the complete bundle list if necessary, but I'm omitting it 
for brevity. Anyway, when the container starts, all bundles are resolved (or 
active), no mandatory dependencies are missing.

When I access our sample service, I get following stack trace:
java.lang.RuntimeException: org.apache.cxf.interceptor.Fault
        at 
org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:116)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:333)
        at 
org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
        at 
org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
        at 
org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:248)
        at 
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:222)
        at 
org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:153)
        at 
org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:167)
        at 
org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286)
        at 
org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:211)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
        at 
org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262)
        at 
org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:643)
        at 
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1331)
        at 
org.apache.olingo.sample.annotation.filter.ServiceFactoryFilter.doFilter(ServiceFactoryFilter.java:24)
        at 
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1302)
        at 
org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:448)
        at 
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
        at 
org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
        at 
org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
        at 
org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1067)
        at 
org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:377)
        at 
org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192)
        at 
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1001)
        at 
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
        at 
org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
        at 
org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
        at 
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
        at org.eclipse.jetty.server.Server.handle(Server.java:356)
        at 
org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
        at 
org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
        at 
org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
        at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
        at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
        at 
org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:77)
        at 
org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:622)
        at 
org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:46)
        at 
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
        at 
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
        at java.lang.Thread.run(Unknown Source)
Caused by: org.apache.cxf.interceptor.Fault
        at 
org.apache.cxf.service.invoker.AbstractInvoker.createFault(AbstractInvoker.java:162)
        at 
org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:128)
        at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:205)
        at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:269)
        at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:102)
        at 
org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:58)
        at 
org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:94)
        at 
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
        ... 38 more
Caused by: java.lang.ExceptionInInitializerError
        at 
org.apache.olingo.sample.annotation.processor.AnnotationSampleServiceFactory.createService(AnnotationSampleServiceFactory.java:67)
        at 
org.apache.olingo.odata2.core.rest.ODataSubLocator.handle(ODataSubLocator.java:146)
        at 
org.apache.olingo.odata2.core.rest.ODataSubLocator.handleGet(ODataSubLocator.java:56)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at 
org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
        at 
org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
        ... 44 more
Caused by: java.lang.IllegalArgumentException: No folder to scan found for 
package 'org.apache.olingo.sample.annotation.model'.
        at 
org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper.loadClasses(ClassHelper.java:71)
        at 
org.apache.olingo.odata2.annotation.processor.core.util.ClassHelper.loadClasses(ClassHelper.java:62)
        at 
org.apache.olingo.odata2.annotation.processor.core.edm.AnnotationEdmProvider.<init>(AnnotationEdmProvider.java:97)
        at 
org.apache.olingo.odata2.annotation.processor.core.rt.AnnotationServiceFactoryImpl.createAnnotationService(AnnotationServiceFactoryImpl.java:42)
        at 
org.apache.olingo.odata2.annotation.processor.api.AnnotationServiceFactory.createAnnotationService(AnnotationServiceFactory.java:103)
        at 
org.apache.olingo.sample.annotation.processor.AnnotationSampleServiceFactory$AnnotationInstances.<clinit>(AnnotationSampleServiceFactory.java:54)
        ... 53 more

The failure occurs within AnnotationServiceFactory.createAnnotationService() 
call, where Olingo attempts to discover and load classes with entity 
definitions for our sample service and it fails. The service factory uses TCCL 
(thread context class loader) for loading the classes. The notable thing is 
that this class loader at this point *is not* the webapp's class loader that 
was set by Jetty, it is an instance of 
org.eclipse.core.runtime.internal.adaptor.ContextFinder! The ContextFinder is 
Equinox's speciality, I suppose, and probably somewhat flawed anyway: 
http://blog.bjhargrave.com/2007/07/contextfinder-in-eclipse-is-broken.html

How the ContextFinder was set? Further exploration leads to the finding that 
the TCCL is set by org.apache.cxf.transport.servlet.CXFNonSpringServlet in 
invoke() method.
- The 'loader' field is filled in CXFNonSpringServlet.init(): loader = 
bus.getExtension(ClassLoader.class);
- The 'bus' is org.apache.cxf.bus.CXFBusImpl and the getExtension() method uses 
org.apache.cxf.bus.osgi.OSGiBeanLocator as the ConfiguredBeanLocator.

OSGiBeanLocator.getBeansFromOsgiService() asks the OSGi container for 
java.lang.ClassLoader service... and well, Equinox provides such a service! The 
returned reference displays: 
{java.lang.ClassLoader}={service.ranking=2147483647, 
service.pid=0.org.eclipse.core.runtime.internal.adaptor.ContextFinder, 
service.vendor=Eclipse.org - Equinox, 
equinox.classloader.type=contextClassLoader, service.id=5}

So, the summary:
- The CXF servlet creates a CXF bus.
- The CXF bus binds an OSGiBeanLocator during initialization.
- Equinox, unfortunately, provides an OSGi service for java.lang.ClassLoader 
type (the ContextFinder).
- The CXF servlet sets this OSGi service/class loader as TCCL when invoked, 
overriding the class loader for the webapp provided by Jetty.
- Well, later the ContextFinder is used by Olingo instead of the desired class 
loader.

Any ideas how to fix the TCCL override performed by the CXF servlet?

Thanks for help in advance,
Petr

Reply via email to