Hi
The immediate workaround is available in 2.7.11-SNAPSHOT, extend
CXFNonSpringJaxrsServlet and override the protected initClassLoader
method and return null. Can you experiment with the snapshot ?
Some more changes went to the trunk, but that is being reviewed by now,
we can merge something to 2.7.x once the switch to Git is complete
Cheers, Sergey
On 18/02/14 13:19, Sergey Beryozkin wrote:
Hi
Thanks for the analysis, quite interesting.
I think we can tackle it at two levels, allow for the overriding of the
code dealing with setting the class loader in CXF servlet, filter the
ClassLoader OSGI services which have no the recognized marker property,
that should be reasonable for 3.0.0 only - meaning very minor migration
effort for cases where custom ClassLoader services have already been
deployed to work against CXF 2.7.x...
Thanks, Sergey
On 18/02/14 11:57, Dolezal, Petr wrote:
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
--
Sergey Beryozkin
Talend Community Coders
http://coders.talend.com/
Blog: http://sberyozkin.blogspot.com