Skip to content

Commit ed3df32

Browse files
author
Phillip Webb
committed
Extract resource handling to TomcatResources
Extract the nasty Tomcat resource handling reflection code to its own class.
1 parent 72a2e5b commit ed3df32

File tree

2 files changed

+201
-94
lines changed

2 files changed

+201
-94
lines changed

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

Lines changed: 1 addition & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
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;
2623
import java.nio.charset.Charset;
2724
import java.util.ArrayList;
2825
import java.util.Arrays;
@@ -40,12 +37,10 @@
4037
import org.apache.catalina.Valve;
4138
import org.apache.catalina.Wrapper;
4239
import org.apache.catalina.connector.Connector;
43-
import org.apache.catalina.core.StandardContext;
4440
import org.apache.catalina.loader.WebappLoader;
4541
import org.apache.catalina.startup.Tomcat;
4642
import org.apache.catalina.startup.Tomcat.FixContextListener;
4743
import org.apache.coyote.AbstractProtocol;
48-
import org.apache.naming.resources.FileDirContext;
4944
import org.springframework.beans.BeanUtils;
5045
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
5146
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
@@ -589,95 +584,7 @@ private void onStart(Context context) {
589584
if (servletContext.getAttribute(this.MERGED_WEB_XML) == null) {
590585
servletContext.setAttribute(this.MERGED_WEB_XML, getEmptyWebXml());
591586
}
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-
}
587+
TomcatResources.get(context).addClasspathResources();
681588
}
682589

683590
private String getEmptyWebXml() {
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright 2012-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.context.embedded.tomcat;
18+
19+
import java.io.File;
20+
import java.lang.reflect.Method;
21+
import java.net.MalformedURLException;
22+
import java.net.URL;
23+
import java.net.URLClassLoader;
24+
25+
import javax.servlet.ServletContext;
26+
27+
import org.apache.catalina.Context;
28+
import org.apache.catalina.core.StandardContext;
29+
import org.apache.naming.resources.FileDirContext;
30+
import org.springframework.util.ClassUtils;
31+
import org.springframework.util.ReflectionUtils;
32+
33+
/**
34+
* Abstraction to add resources that works with both Tomcat 8 and 7.
35+
*
36+
* @author Dave Syer
37+
* @author Phillip Webb
38+
*/
39+
abstract class TomcatResources {
40+
41+
private final Context context;
42+
43+
public TomcatResources(Context context) {
44+
this.context = context;
45+
}
46+
47+
/**
48+
* Add resources from the classpath
49+
*/
50+
public void addClasspathResources() {
51+
ClassLoader loader = getClass().getClassLoader();
52+
if (loader instanceof URLClassLoader) {
53+
for (URL url : ((URLClassLoader) loader).getURLs()) {
54+
String file = url.getFile();
55+
if (file.endsWith(".jar") || file.endsWith(".jar!/")) {
56+
String jar = url.toString();
57+
if (!jar.startsWith("jar:")) {
58+
// A jar file in the file system. Convert to Jar URL.
59+
jar = "jar:" + jar + "!/";
60+
}
61+
addJar(jar);
62+
}
63+
else if (url.toString().startsWith("file:")) {
64+
String dir = url.toString().substring("file:".length());
65+
if (new File(dir).isDirectory()) {
66+
addDir(dir, url);
67+
}
68+
}
69+
}
70+
}
71+
}
72+
73+
protected final Context getContext() {
74+
return this.context;
75+
}
76+
77+
/**
78+
* Called to add a JAR to the resources.
79+
* @param jar the URL spec for the jar
80+
*/
81+
protected abstract void addJar(String jar);
82+
83+
/**
84+
* Called to add a dir to the resource.
85+
* @param dir the dir
86+
* @param url the URL
87+
*/
88+
protected abstract void addDir(String dir, URL url);
89+
90+
/**
91+
* Return a {@link TomcatResources} instance for the currently running Tomcat version.
92+
* @param context the tomcat context
93+
* @return a {@link TomcatResources} instance.
94+
*/
95+
public static TomcatResources get(Context context) {
96+
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
97+
return new Tomcat7Resources(context);
98+
}
99+
return new Tomcat8Resources(context);
100+
}
101+
102+
/**
103+
* {@link TomcatResources} for Tomcat 7.
104+
*/
105+
private static class Tomcat7Resources extends TomcatResources {
106+
107+
public Tomcat7Resources(Context context) {
108+
super(context);
109+
}
110+
111+
@Override
112+
protected void addJar(String jar) {
113+
try {
114+
getContext().addResourceJarUrl(new URL(jar));
115+
}
116+
catch (MalformedURLException ex) {
117+
// Ignore?
118+
}
119+
}
120+
121+
@Override
122+
protected void addDir(String dir, URL url) {
123+
if (getContext() instanceof ServletContext) {
124+
FileDirContext files = new FileDirContext();
125+
files.setDocBase(dir);
126+
((StandardContext) getContext()).addResourcesDirContext(files);
127+
}
128+
}
129+
130+
}
131+
132+
/**
133+
* {@link TomcatResources} for Tomcat 8.
134+
*/
135+
static class Tomcat8Resources extends TomcatResources {
136+
137+
private Object resources;
138+
139+
private Method createWebResourceSetMethod;
140+
141+
private Enum<?> resourceJarEnum;
142+
143+
@SuppressWarnings({ "rawtypes", "unchecked" })
144+
public Tomcat8Resources(Context context) {
145+
super(context);
146+
try {
147+
this.resources = ReflectionUtils.findMethod(context.getClass(),
148+
"getResources").invoke(context);
149+
Class resourceSetType = ClassUtils.resolveClassName(
150+
"org.apache.catalina.WebResourceRoot.ResourceSetType", null);
151+
this.createWebResourceSetMethod = ReflectionUtils.findMethod(
152+
this.resources.getClass(), "createWebResourceSet",
153+
resourceSetType, String.class, URL.class, String.class);
154+
this.resourceJarEnum = Enum.valueOf(resourceSetType, "RESOURCE_JAR");
155+
}
156+
catch (Exception ex) {
157+
throw new IllegalStateException("Tomcat 8 reflection failed", ex);
158+
}
159+
}
160+
161+
@Override
162+
protected void addJar(String jar) {
163+
addResourceSet(jar);
164+
}
165+
166+
@Override
167+
protected void addDir(String dir, URL url) {
168+
addResourceSet(url.toString());
169+
}
170+
171+
private void addResourceSet(String resource) {
172+
try {
173+
if (isInsideNestedJar(resource)) {
174+
// It's a nested jar but we now don't want the suffix because Tomcat
175+
// is going to try and locate it as a root URL (not the resource
176+
// inside it)
177+
resource = resource.substring(0, resource.length() - 2);
178+
}
179+
URL url = new URL(resource);
180+
String path = "/META-INF/resources";
181+
createWebResourceSet("/", url, path);
182+
}
183+
catch (Exception ex) {
184+
// Ignore (probably not a directory)
185+
}
186+
}
187+
188+
private boolean isInsideNestedJar(String dir) {
189+
return dir.indexOf("!/") < dir.lastIndexOf("!/");
190+
}
191+
192+
private void createWebResourceSet(String webAppMount, URL url, String path)
193+
throws Exception {
194+
this.createWebResourceSetMethod.invoke(this.resources, this.resourceJarEnum,
195+
webAppMount, url, path);
196+
}
197+
198+
}
199+
200+
}

0 commit comments

Comments
 (0)