Skip to content

Commit

Permalink
When searching for SCIs use Context.getParentClassLoader instead of C…
Browse files Browse the repository at this point in the history
…lassLoader.getParent.

Thus one can provide the correct parent class loader when running embedded Tomcat in other environments such as OSGi.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1668596 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
violetagg committed Mar 23, 2015
1 parent a03c48d commit 1b7a152
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 26 deletions.
7 changes: 3 additions & 4 deletions java/org/apache/catalina/startup/ContextConfig.java
Expand Up @@ -1124,7 +1124,7 @@ protected void webConfig() {

// Step 3. Look for ServletContainerInitializer implementations
if (ok) {
processServletContainerInitializers(sContext);
processServletContainerInitializers();
}

if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
Expand Down Expand Up @@ -1607,12 +1607,11 @@ protected WebXml createWebXml() {
/**
* Scan JARs for ServletContainerInitializer implementations.
*/
protected void processServletContainerInitializers(ServletContext servletContext) {
protected void processServletContainerInitializers() {

List<ServletContainerInitializer> detectedScis;
try {
WebappServiceLoader<ServletContainerInitializer> loader =
new WebappServiceLoader<>(servletContext, context.getContainerSciFilter());
WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
detectedScis = loader.load(ServletContainerInitializer.class);
} catch (IOException e) {
log.error(sm.getString(
Expand Down
19 changes: 12 additions & 7 deletions java/org/apache/catalina/startup/WebappServiceLoader.java
Expand Up @@ -33,6 +33,8 @@

import javax.servlet.ServletContext;

import org.apache.catalina.Context;

/**
* A variation of Java's JAR ServiceLoader that respects exclusion rules for
* web applications.
Expand All @@ -56,16 +58,19 @@ public class WebappServiceLoader<T> {
private static final String LIB = "/WEB-INF/lib/";
private static final String SERVICES = "META-INF/services/";

private final ServletContext context;
private final Context context;
private final ServletContext servletContext;
private final Pattern containerSciFilterPattern;

/**
* Construct a loader to load services from a ServletContext.
*
* @param context the context to use
*/
public WebappServiceLoader(ServletContext context, String containerSciFilter) {
public WebappServiceLoader(Context context) {
this.context = context;
this.servletContext = context.getServletContext();
String containerSciFilter = context.getContainerSciFilter();
if (containerSciFilter != null && containerSciFilter.length() > 0) {
containerSciFilterPattern = Pattern.compile(containerSciFilter);
} else {
Expand All @@ -86,17 +91,17 @@ public List<T> load(Class<T> serviceType) throws IOException {
LinkedHashSet<String> applicationServicesFound = new LinkedHashSet<>();
LinkedHashSet<String> containerServicesFound = new LinkedHashSet<>();

ClassLoader loader = context.getClassLoader();
ClassLoader loader = servletContext.getClassLoader();

// if the ServletContext has ORDERED_LIBS, then use that to specify the
// set of JARs from WEB-INF/lib that should be used for loading services
@SuppressWarnings("unchecked")
List<String> orderedLibs =
(List<String>) context.getAttribute(ServletContext.ORDERED_LIBS);
(List<String>) servletContext.getAttribute(ServletContext.ORDERED_LIBS);
if (orderedLibs != null) {
// handle ordered libs directly, ...
for (String lib : orderedLibs) {
URL jarUrl = context.getResource(LIB + lib);
URL jarUrl = servletContext.getResource(LIB + lib);
if (jarUrl == null) {
// should not happen, just ignore
continue;
Expand All @@ -117,7 +122,7 @@ public List<T> load(Class<T> serviceType) throws IOException {
}

// and the parent ClassLoader for all others
loader = loader.getParent();
loader = context.getParentClassLoader();
}

Enumeration<URL> resources;
Expand Down Expand Up @@ -174,7 +179,7 @@ void parseConfigFile(LinkedHashSet<String> servicesFound, URL url)

List<T> loadServices(Class<T> serviceType, LinkedHashSet<String> servicesFound)
throws IOException {
ClassLoader loader = context.getClassLoader();
ClassLoader loader = servletContext.getClassLoader();
List<T> services = new ArrayList<>(servicesFound.size());
for (String serviceClass : servicesFound) {
try {
Expand Down
60 changes: 45 additions & 15 deletions test/org/apache/catalina/startup/TestWebappServiceLoader.java
Expand Up @@ -31,6 +31,8 @@
import org.junit.Before;
import org.junit.Test;

import org.apache.catalina.Context;
import org.apache.catalina.core.TesterContext;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;

Expand All @@ -40,7 +42,8 @@ public class TestWebappServiceLoader {
private IMocksControl control;
private ClassLoader cl;
private ClassLoader parent;
private ServletContext context;
private Context context;
private ServletContext servletContext;
private WebappServiceLoader<ServletContainerInitializer> loader;

@Before
Expand All @@ -51,14 +54,15 @@ public void init() {
.withConstructor(parent)
.addMockedMethod("loadClass", String.class)
.createMock(control);
context = control.createMock(ServletContext.class);
EasyMock.expect(context.getClassLoader()).andStubReturn(cl);
servletContext = control.createMock(ServletContext.class);
EasyMock.expect(servletContext.getClassLoader()).andStubReturn(cl);
context = new ExtendedTesterContext(servletContext, parent);
}

@Test
public void testNoInitializersFound() throws IOException {
loader = new WebappServiceLoader<>(context, null);
EasyMock.expect(context.getAttribute(ServletContext.ORDERED_LIBS))
loader = new WebappServiceLoader<>(context);
EasyMock.expect(servletContext.getAttribute(ServletContext.ORDERED_LIBS))
.andReturn(null);
EasyMock.expect(cl.getResources(CONFIG_FILE))
.andReturn(Collections.<URL>emptyEnumeration());
Expand All @@ -73,8 +77,8 @@ public void testInitializerFromClasspath() throws IOException {
URL url = new URL("file://test");
loader = EasyMock.createMockBuilder(WebappServiceLoader.class)
.addMockedMethod("parseConfigFile", LinkedHashSet.class, URL.class)
.withConstructor(context, "").createMock(control);
EasyMock.expect(context.getAttribute(ServletContext.ORDERED_LIBS))
.withConstructor(context).createMock(control);
EasyMock.expect(servletContext.getAttribute(ServletContext.ORDERED_LIBS))
.andReturn(null);
EasyMock.expect(cl.getResources(CONFIG_FILE))
.andReturn(Collections.enumeration(Collections.singleton(url)));
Expand All @@ -93,14 +97,14 @@ public void testWithOrdering() throws IOException {
URL sci2 = new URL("file://dir/" + CONFIG_FILE);
loader = EasyMock.createMockBuilder(WebappServiceLoader.class)
.addMockedMethod("parseConfigFile", LinkedHashSet.class, URL.class)
.withConstructor(context, "").createMock(control);
.withConstructor(context).createMock(control);
List<String> jars = Arrays.asList("jar1.jar", "dir/");
EasyMock.expect(context.getAttribute(ServletContext.ORDERED_LIBS))
EasyMock.expect(servletContext.getAttribute(ServletContext.ORDERED_LIBS))
.andReturn(jars);
EasyMock.expect(context.getResource("/WEB-INF/lib/jar1.jar"))
EasyMock.expect(servletContext.getResource("/WEB-INF/lib/jar1.jar"))
.andReturn(url1);
loader.parseConfigFile(EasyMock.isA(LinkedHashSet.class), EasyMock.eq(sci1));
EasyMock.expect(context.getResource("/WEB-INF/lib/dir/"))
EasyMock.expect(servletContext.getResource("/WEB-INF/lib/dir/"))
.andReturn(url2);
loader.parseConfigFile(EasyMock.isA(LinkedHashSet.class), EasyMock.eq(sci2));
EasyMock.expect(parent.getResources(CONFIG_FILE))
Expand All @@ -114,15 +118,15 @@ public void testWithOrdering() throws IOException {
@Test
public void testParseConfigFile() throws IOException {
LinkedHashSet<String> found = new LinkedHashSet<>();
loader = new WebappServiceLoader<>(context, null);
loader = new WebappServiceLoader<>(context);
loader.parseConfigFile(found, getClass().getResource("service-config.txt"));
Assert.assertEquals(Collections.singleton("provider1"), found);
}

@Test
public void testLoadServices() throws Exception {
Class<?> sci = TesterServletContainerInitializer1.class;
loader = new WebappServiceLoader<>(context, null);
loader = new WebappServiceLoader<>(context);
cl.loadClass(sci.getName());
EasyMock.expectLastCall()
.andReturn(sci);
Expand All @@ -139,7 +143,7 @@ public void testLoadServices() throws Exception {
@Test
public void testServiceIsNotExpectedType() throws Exception {
Class<?> sci = Object.class;
loader = new WebappServiceLoader<>(context, null);
loader = new WebappServiceLoader<>(context);
cl.loadClass(sci.getName());
EasyMock.expectLastCall()
.andReturn(sci);
Expand All @@ -158,7 +162,7 @@ public void testServiceIsNotExpectedType() throws Exception {
@Test
public void testServiceCannotBeConstructed() throws Exception {
Class<?> sci = Integer.class;
loader = new WebappServiceLoader<>(context, null);
loader = new WebappServiceLoader<>(context);
cl.loadClass(sci.getName());
EasyMock.expectLastCall()
.andReturn(sci);
Expand All @@ -173,4 +177,30 @@ public void testServiceCannotBeConstructed() throws Exception {
control.verify();
}
}

private static class ExtendedTesterContext extends TesterContext {
private final ServletContext servletContext;
private final ClassLoader parent;

public ExtendedTesterContext(ServletContext servletContext, ClassLoader parent) {
this.servletContext = servletContext;
this.parent = parent;
}

@Override
public ServletContext getServletContext() {
return servletContext;
}

@Override
public String getContainerSciFilter() {
return "";
}

@Override
public ClassLoader getParentClassLoader() {
return parent;
}

}
}

0 comments on commit 1b7a152

Please sign in to comment.