Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 369363 - SpringServletContainerInitializer class load error when deploying WAR files with Spring 3.1
Summary: SpringServletContainerInitializer class load error when deploying WAR files w...
Status: CLOSED FIXED
Alias: None
Product: Virgo
Classification: RT
Component: runtime (show other bugs)
Version: unspecified   Edit
Hardware: PC Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Chris Frost CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-01-23 04:51 EST by Glyn Normington CLA
Modified: 2012-01-25 11:22 EST (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Glyn Normington CLA 2012-01-23 04:51:56 EST
org.springframework.web.SpringServletContainerInitializer (SSCI), described in the Spring docs ([1]), is automatically loaded and driven by any servlet 3.0 container which has Spring web on the servlet container's class path. Its purpose is to find and drive user-provided org.springframework.web.WebApplicationInitializer implementations.

SSCI is loaded using the current thread context class loader ([2]).

[1] http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/web/SpringServletContainerInitializer.html

[2] http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html?is-external=true#load(java.lang.Class)
Comment 1 Glyn Normington CLA 2012-01-23 05:16:50 EST
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=357102#c2 for the diagnostics produced.
Comment 2 Glyn Normington CLA 2012-01-23 06:55:42 EST
The stack trace:

[2012-01-18 16:02:07.790] start-signalling-2       The ServletContentInitializer [org.springframework.web.SpringServletContainerInitializer] could not be created java.lang.ClassNotFoundException: org.springframework.web.SpringServletContainerInitializer
    at org.eclipse.gemini.web.tomcat.internal.loading.BundleWebappClassLoader.loadClass(BundleWebappClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at org.apache.catalina.startup.ContextConfig.getServletContainerInitializer(ContextConfig.java:1543)
    at ...

points to the following class loading logic in the ContextConfig.getServletContainerInitializer method (see [1]):

Class<?> clazz = Class.forName(className,true,
                    context.getLoader().getClassLoader());

where context is a field of type org.apache.catalina.Context declared as:

    /**
     * The Context we are associated with.
     */
    protected Context context = null;

So it seems that if this class load is to succeed, we need to be able to load org.springframework.web.SpringServletContainerInitializer from the class loader obtained from the Context via getLoader().getClassLoader().

[1] http://svn.apache.org/repos/asf/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/ContextConfig.java
Comment 3 Glyn Normington CLA 2012-01-23 07:20:34 EST
I suggest we start by debugging ContextConfig.webConfig to see how Tomcat ends up finding Spring web. One question is: if the WAR file has access to Spring web, why can't the class SSCI be loaded?
Comment 4 Glyn Normington CLA 2012-01-25 09:44:36 EST
It turns out that Tomcat makes a hierarchical class loader assumption and ends up searching the parent class loader of the web application and finds Spring web because of the way integration tests are run under Ant. This would not be a problem using the normal launcher (i.e. outside an integration test environment) because Spring web would not be on the application class path.

The fix is to specify a different parent class loader by setting the property osgi.parentClassloader to "ext". This makes all the OSGi bundles in the system have a parent class loader of the JRE extension class loader (which is the parent of the application class loader). However, Gemini Web uses the application class loader as the parent for WebBundleClassLoader and so it will be necessary to change Gemini Web to ensure WebBundleClassLoader's parent class loader is the same as that of the OSGi bundles.
Comment 5 Chris Frost CLA 2012-01-25 10:58:17 EST
This was cause by junk in the app class loader when running tests. Changing the parent class loader of all bundles in tests (including web app classloaders) fixes this.
Comment 6 Chris Frost CLA 2012-01-25 11:18:56 EST
See 2390176a622634228de0c732a0272a9113698dca
Comment 7 Chris Frost CLA 2012-01-25 11:22:50 EST
Previous SHA is for web.

This is for Gemini Web
534397ad2a49d57d2de4f46fb507814d07034a38