Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 337586

Summary: Make loading of system resources more OSGi-friendly
Product: [RT] Jetty Reporter: Benjamin Bentmann <bentmann>
Component: serverAssignee: Hugues Malphettes <hmalphettes>
Status: CLOSED WONTFIX QA Contact:
Severity: normal    
Priority: P3 CC: bentmann, gregw, janb, jetty-inbox
Version: 7.3.0   
Target Milestone: 7.2.x   
Hardware: All   
OS: All   
Whiteboard:

Description Benjamin Bentmann CLA 2011-02-18 11:41:41 EST
Background:
I was trying to fire up an embedded Jetty 7.3.0 container via Cargo 1.0.6 within some Eclipse plugin. The required Jetty libs are brought into action by adding the Jetty p2 repo to the target platform and having my Eclipse plugin's manifest give the corresponding Require-Bundle header. Mostly using default settings for a web app, I ended up with the following exception while trying to deploy the webapp to the Jetty container:

java.io.FileNotFoundException: D:\eclipse\3.7\org\eclipse\jetty\webapp\webdefault.xml (Das System kann den angegebenen Pfad nicht finden)
  at java.io.FileInputStream.open(Native Method) ~[na:1.5.0_22]
  at java.io.FileInputStream.<init>(FileInputStream.java:106) ~[na:1.5.0_22]
  at java.io.FileInputStream.<init>(FileInputStream.java:66) ~[na:1.5.0_22]
  at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70) ~[na:1.5.0_22]
  at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:973) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:184) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:798) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:764) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148) ~[na:1.5.0_22]
  at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1242) ~[na:1.5.0_22]
  at javax.xml.parsers.SAXParser.parse(SAXParser.java:375) ~[na:1.5.0_22]
  at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:187) ~[na:na]
  at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:203) ~[na:na]
  at org.eclipse.jetty.webapp.Descriptor.parse(Descriptor.java:60) ~[na:na]
  at org.eclipse.jetty.webapp.WebDescriptor.parse(WebDescriptor.java:142) ~[na:na]
  at org.eclipse.jetty.webapp.MetaData.setDefaults(MetaData.java:142) ~[na:na]
  at org.eclipse.jetty.webapp.WebXmlConfiguration.preConfigure(WebXmlConfiguration.java:46) ~[na:na]
  at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:406) ~[na:na]
  at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:435) ~[na:na]
  at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55) [org.eclipse.jetty.util_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:226) [org.eclipse.jetty.server_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:164) [org.eclipse.jetty.server_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55) [org.eclipse.jetty.util_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:226) [org.eclipse.jetty.server_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55) [org.eclipse.jetty.util_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95) [org.eclipse.jetty.server_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.server.Server.doStart(Server.java:258) [org.eclipse.jetty.server_7.3.0.v20110203.jar:7.3.0.v20110203]
  at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55) [org.eclipse.jetty.util_7.3.0.v20110203.jar:7.3.0.v20110203]
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.5.0_22]
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.5.0_22]
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.5.0_22]
  at java.lang.reflect.Method.invoke(Method.java:592) ~[na:1.5.0_22]
  at org.codehaus.cargo.container.jetty.internal.JettyExecutorThread.run(JettyExecutorThread.java:69) [cargo-core-uberjar-1.0.6.jar:1.0.6]

Another helpful/related stack trace from the container a few instructions before the exception:
  org.eclipse.jetty.util.resource.Resource.newSystemResource(java.lang.String) line: 212  
  org.eclipse.jetty.webapp.WebXmlConfiguration.preConfigure(org.eclipse.jetty.webapp.WebAppContext) line: 43  
  org.eclipse.jetty.webapp.WebAppContext.preConfigure() line: 406 
  org.eclipse.jetty.webapp.WebAppContext.doStart() line: 435  
  org.eclipse.jetty.webapp.WebAppContext(org.eclipse.jetty.util.component.AbstractLifeCycle).start() line: 55 
  org.eclipse.jetty.server.handler.ContextHandlerCollection(org.eclipse.jetty.server.handler.HandlerCollection).doStart() line: 226 
  org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart() line: 164 
  org.eclipse.jetty.server.handler.ContextHandlerCollection(org.eclipse.jetty.util.component.AbstractLifeCycle).start() line: 55  
  org.eclipse.jetty.server.handler.HandlerCollection.doStart() line: 226  
  org.eclipse.jetty.server.handler.HandlerCollection(org.eclipse.jetty.util.component.AbstractLifeCycle).start() line: 55 
  org.eclipse.jetty.server.Server(org.eclipse.jetty.server.handler.HandlerWrapper).doStart() line: 95 
  org.eclipse.jetty.server.Server.doStart() line: 258 
  org.eclipse.jetty.server.Server(org.eclipse.jetty.util.component.AbstractLifeCycle).start() line: 55  
  sun.reflect.NativeMethodAccessorImpl.invoke0(java.lang.reflect.Method, java.lang.Object, java.lang.Object[]) line: not available [native method]  
  sun.reflect.NativeMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 39  
  sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 25  
  java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object...) line: 592  
  org.codehaus.cargo.container.jetty.internal.JettyExecutorThread.run() line: 69  

What happens is that WebXmlConfiguration.preConfigure() calls Resource.newSystemResource("org/eclipse/jetty/webapp/webdefault.xml"). newSystemResource() queries the TCCL and next the loader of the Resource class for the resource. In my setting, the TCCL (which I can't control) effectively resolves to the bundle loader of org.eclipse.jetty.util (as per Eclipse's ContextFinder logic) which also is the loader of o.e.j.u.r.Resource. However, the resource in question is actually contained in the org.eclipse.jetty.webapp bundle whose contents is not visible to the org.eclipse.jetty.util loader.

In a nutshell, the class loader of o.e.j.u.r.Resource does not see all of the Jetty classes/resources when using Jetty as OSGi bundles which can easily make loading of "system" resources fail.

As a potential solution, I could think of extending Resource.newSystemResource() to additionally take a class loader as input which would be queried as well. So basically, WebXmlConfiguration.preConfigure() could call Resource.newSystemResource( ..., WebXmlConfiguration.class.getClassLoader() ), i.e. thereby providing access to the class loader which actually contains the system resource.
Comment 1 Greg Wilkins CLA 2011-02-22 22:34:23 EST
hughes,

can you give me your considered opinion on this issue.   I'm open to the suggestion of changing newSystemResource, but I wonder why you have not hit this problem with your OSGi work?
Comment 2 Hugues Malphettes CLA 2011-02-23 14:12:05 EST
I am probably missing the complete testcase: according to the stack trace the jetty server is started without using org.eclipse.jetty.osgi.boot
We have solved this type of issues inside org.eclipse.jetty.osgi.boot

Could you attach the jetty.xml file you use to configure your application and maybe some more pieces to be able to reproduce the issue?
Comment 3 Benjamin Bentmann CLA 2011-02-25 07:12:56 EST
(In reply to comment #2)
> according to the stack trace the
> jetty server is started without using org.eclipse.jetty.osgi.boot

This is correct. My plugin's manifest had
Require-Bundle: org.eclipse.jetty.server, [other-jetty-bundles]
and tried to fire up the server programmatically, much like as described in http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty but with Cargo's Jetty7xEmbeddedLocalContainer doing the actual calls to start the server.

> We have solved this type of issues inside org.eclipse.jetty.osgi.boot

Should this be mentioned in the above mentioned tutorial?

> Could you attach the jetty.xml file you use to configure your application and
> maybe some more pieces to be able to reproduce the issue?

There is no jetty.xml and no local install of the server, it was all programmatically setup. I won't be able to provide a complete show case as I dropped the original approach to embed Jetty and start the server outside OSGi now.
Comment 4 Hugues Malphettes CLA 2011-02-27 22:13:39 EST
(In reply to comment #3)
> (In reply to comment #2)
> > according to the stack trace the
> > jetty server is started without using org.eclipse.jetty.osgi.boot
> 
> This is correct. My plugin's manifest had
> Require-Bundle: org.eclipse.jetty.server, [other-jetty-bundles]
> and tried to fire up the server programmatically, much like as described in
> http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty but with Cargo's
> Jetty7xEmbeddedLocalContainer doing the actual calls to start the server.
> 
> > We have solved this type of issues inside org.eclipse.jetty.osgi.boot
> 
> Should this be mentioned in the above mentioned tutorial?
Thanks a lot for explaining the user-case.
I must confess I had not read that tutorial before. That part of jetty is not ready for OSGi.
There is some work related to this in bug #309250; to manage multiple instances of jetty in the same equinox and to be able to programatically create the jetty server.

Reading the tutorial, we would need to make some APIs of org.eclipse.jetty.osgi.boot public to support the type of example above: in particular the setup of the WebAppContext is quite different in OSGi.

> 
> > Could you attach the jetty.xml file you use to configure your application and
> > maybe some more pieces to be able to reproduce the issue?
> 
> There is no jetty.xml and no local install of the server, it was all
> programmatically setup. I won't be able to provide a complete show case as I
> dropped the original approach to embed Jetty and start the server outside OSGi
> now.
OK. We will prepare for the opportunity to support this in OSGi.
Comment 5 Jan Bartel CLA 2014-11-13 04:06:51 EST
The jetty-osgi API has changed significantly since this issue was raised. It is possible to use the classes in the jetty-osgi-boot jar to provide a classloader for the webapp that will allow it to resolve the webdefaults.xml file from the jetty-webapp jar.  Look at the OSGIWebAppClassLoader, ServerInstanceWrapper, LibExtClassLoader and FakeURLClassLoader classes for how to construct the classloader for the webapp.

Jan