Skip to content

Commit 1bcc136

Browse files
author
Dave Syer
committed
Hack around with Tomcat resource paths
Tomcat 8 has different APIs again so it was quite difficult to get it working and test it. The test is manual anyway (multi-module project with JSPs in /META-INF/resources, not part of the samples), and requires you to build a war and execute it (since the resource paths are different when it's an archive). Fixes gh-1131
1 parent 51496b4 commit 1bcc136

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import java.io.IOException;
2121
import java.io.InputStream;
2222
import java.lang.reflect.Method;
23+
import java.net.MalformedURLException;
24+
import java.net.URL;
25+
import java.net.URLClassLoader;
2326
import java.nio.charset.Charset;
2427
import java.util.ArrayList;
2528
import java.util.Arrays;
@@ -37,10 +40,12 @@
3740
import org.apache.catalina.Valve;
3841
import org.apache.catalina.Wrapper;
3942
import org.apache.catalina.connector.Connector;
43+
import org.apache.catalina.core.StandardContext;
4044
import org.apache.catalina.loader.WebappLoader;
4145
import org.apache.catalina.startup.Tomcat;
4246
import org.apache.catalina.startup.Tomcat.FixContextListener;
4347
import org.apache.coyote.AbstractProtocol;
48+
import org.apache.naming.resources.FileDirContext;
4449
import org.springframework.beans.BeanUtils;
4550
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
4651
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
@@ -584,6 +589,95 @@ private void onStart(Context context) {
584589
if (servletContext.getAttribute(this.MERGED_WEB_XML) == null) {
585590
servletContext.setAttribute(this.MERGED_WEB_XML, getEmptyWebXml());
586591
}
592+
addClasspathResources(context);
593+
}
594+
595+
private void addClasspathResources(Context context) {
596+
ClassLoader loader = getClass().getClassLoader();
597+
if (loader instanceof URLClassLoader) {
598+
for (URL url : ((URLClassLoader) loader).getURLs()) {
599+
String file = url.getFile();
600+
if (file.endsWith(".jar") || file.endsWith(".jar!/")) {
601+
addJarContext(context, url);
602+
}
603+
else if (url.toString().startsWith("file:")) {
604+
addDirContext(context, url);
605+
}
606+
}
607+
}
608+
}
609+
610+
private void addJarContext(Context context, URL url) {
611+
String jar = url.toString();
612+
if (!jar.startsWith("jar:")) {
613+
// A jar file in the file system. Convert to Jar URL.
614+
jar = "jar:" + jar + "!/";
615+
}
616+
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
617+
// Tomcat 7
618+
try {
619+
context.addResourceJarUrl(new URL(jar));
620+
}
621+
catch (MalformedURLException e) {
622+
// Ignore?
623+
}
624+
}
625+
else {
626+
// Tomcat 8
627+
addResourceSet(context, "RESOURCE_JAR", jar);
628+
}
629+
}
630+
631+
private void addDirContext(Context context, URL url) {
632+
String dir = url.toString().substring("file:".length());
633+
if (new File(dir).isDirectory()) {
634+
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
635+
// Tomcat 7
636+
if (context instanceof StandardContext) {
637+
FileDirContext files = new FileDirContext();
638+
files.setDocBase(dir);
639+
((StandardContext) context).addResourcesDirContext(files);
640+
}
641+
}
642+
else {
643+
// Tomcat 8
644+
addResourceSet(context, "RESOURCE_JAR", url.toString());
645+
}
646+
}
647+
}
648+
649+
@SuppressWarnings({ "rawtypes", "unchecked" })
650+
private void addResourceSet(Context context, String name, String dir) {
651+
Object resources;
652+
Method create;
653+
Class type;
654+
try {
655+
Method getResources = ReflectionUtils.findMethod(context.getClass(),
656+
"getResources");
657+
resources = getResources.invoke(context);
658+
type = ClassUtils.resolveClassName(
659+
"org.apache.catalina.WebResourceRoot.ResourceSetType", null);
660+
create = ReflectionUtils.findMethod(resources.getClass(),
661+
"createWebResourceSet", type, String.class, URL.class,
662+
String.class);
663+
}
664+
catch (Exception e) {
665+
throw new IllegalStateException("Tomcat 8 reflection failed", e);
666+
}
667+
try {
668+
if (dir.indexOf("!/") < dir.lastIndexOf("!/")) {
669+
// It's a nested jar but we now don't want the suffix because Tomcat
670+
// is going to try and locate it as a root URL (not the resource
671+
// inside it)
672+
dir = dir.substring(0, dir.length() - 2);
673+
}
674+
URL url = new URL(dir);
675+
String path = "/META-INF/resources";
676+
create.invoke(resources, Enum.valueOf(type, name), "/", url, path);
677+
}
678+
catch (Exception e) {
679+
// Ignore (probably not a directory)
680+
}
587681
}
588682

589683
private String getEmptyWebXml() {

0 commit comments

Comments
 (0)