Commit 0e476391 authored by Andy Wilkinson's avatar Andy Wilkinson

Merge pull request #7495 from Eddú Meléndez

* gh-7495:
  Complete removing support for Tomcat 7
  Start removing support for Tomcat 7
parents 5c006d05 0807c27c
...@@ -50,14 +50,10 @@ The following embedded servlet containers are supported out of the box: ...@@ -50,14 +50,10 @@ The following embedded servlet containers are supported out of the box:
|=== |===
|Name |Servlet Version |Java Version |Name |Servlet Version |Java Version
|Tomcat 8 |Tomcat 8.5
|3.1 |3.1
|Java 7+ |Java 7+
|Tomcat 7
|3.0
|Java 6+
|Jetty 9.3 |Jetty 9.3
|3.1 |3.1
|Java 8+ |Java 8+
......
...@@ -930,57 +930,6 @@ add a listener to the `Builder`: ...@@ -930,57 +930,6 @@ add a listener to the `Builder`:
[[howto-use-tomcat-7]]
=== Use Tomcat 7.x or 8.0
Tomcat 7 & 8.0 work with Spring Boot, but the default is to use Tomcat 8.5. If you cannot
use Tomcat 8.5 (for example, because you are using Java 1.6) you will need to change your
classpath to reference a different version.
[[howto-use-tomcat-7-maven]]
==== Use Tomcat 7.x or 8.0 with Maven
If you are using the starters and parent you can change the Tomcat version property
and additionally import `tomcat-juli`. E.g. for a simple webapp or service:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<properties>
<tomcat.version>7.0.59</tomcat.version>
</properties>
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
...
</dependencies>
----
==== Use Tomcat 7.x or 8.0 with Gradle
[[howto-use-tomcat-7-gradle]]
With Gradle, you can change the Tomcat version by setting the `tomcat.version` property
and then additionally include `tomcat-juli`:
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
----
ext['tomcat.version'] = '7.0.59'
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile group:'org.apache.tomcat', name:'tomcat-juli', version:property('tomcat.version')
}
----
[[howto-use-jetty-9.2]] [[howto-use-jetty-9.2]]
=== Use Jetty 9.2 === Use Jetty 9.2
Jetty 9.2 works with Spring Boot, but the default is to use Jetty 9.3. If you cannot use Jetty 9.2 works with Spring Boot, but the default is to use Jetty 9.3. If you cannot use
......
...@@ -207,12 +207,6 @@ The following sample applications are provided: ...@@ -207,12 +207,6 @@ The following sample applications are provided:
| link:spring-boot-sample-tomcat-ssl[spring-boot-sample-tomcat-ssl] | link:spring-boot-sample-tomcat-ssl[spring-boot-sample-tomcat-ssl]
| Web application that uses Tomcat configured with SSL | Web application that uses Tomcat configured with SSL
| link:spring-boot-sample-tomcat7-jsp[spring-boot-sample-tomcat7-jsp]
| Web application that uses JSP templates with Tomcat 7
| link:spring-boot-sample-tomcat7-ssl[spring-boot-sample-tomcat7-ssl]
| Web application that uses Tomcat 7 configured with SSL
| link:spring-boot-sample-tomcat80-ssl[spring-boot-sample-tomcat80-ssl] | link:spring-boot-sample-tomcat80-ssl[spring-boot-sample-tomcat80-ssl]
| Web application that uses Tomcat 8.0 configured with SSL | Web application that uses Tomcat 8.0 configured with SSL
......
...@@ -89,8 +89,6 @@ ...@@ -89,8 +89,6 @@
<module>spring-boot-sample-tomcat-jsp</module> <module>spring-boot-sample-tomcat-jsp</module>
<module>spring-boot-sample-tomcat-ssl</module> <module>spring-boot-sample-tomcat-ssl</module>
<module>spring-boot-sample-tomcat-multi-connectors</module> <module>spring-boot-sample-tomcat-multi-connectors</module>
<module>spring-boot-sample-tomcat7-jsp</module>
<module>spring-boot-sample-tomcat7-ssl</module>
<module>spring-boot-sample-tomcat80-ssl</module> <module>spring-boot-sample-tomcat80-ssl</module>
<module>spring-boot-sample-traditional</module> <module>spring-boot-sample-traditional</module>
<module>spring-boot-sample-undertow</module> <module>spring-boot-sample-undertow</module>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-tomcat7-jsp</artifactId>
<packaging>war</packaging>
<name>Spring Boot Tomcat 7 JSP Sample</name>
<description>Spring Boot Tomcat 7 JSP Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot>
<tomcat.version>7.0.59</tomcat.version>
</properties>
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- Provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat7.jsp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SampleTomcat7JspApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SampleTomcat7JspApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleTomcat7JspApplication.class, args);
}
}
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat7.jsp;
import java.util.Date;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class WelcomeController {
@Value("${application.message:Hello World}")
private String message = "Hello World";
@GetMapping("/")
public String welcome(Map<String, Object> model) {
model.put("time", new Date());
model.put("message", this.message);
return "welcome";
}
}
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
application.message: Hello Phil
\ No newline at end of file
<!DOCTYPE html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<body>
<c:url value="/resources/text.txt" var="url"/>
<spring:url value="/resources/text.txt" htmlEscape="true" var="springUrl" />
Spring URL: ${springUrl} at ${time}
<br>
JSTL URL: ${url}
<br>
Message: ${message}
</body>
</html>
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat7.jsp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Basic integration tests for JSP application.
*
* @author Phillip Webb
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class SampleWebJspApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testJspWithEl() throws Exception {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("/resources/text.txt");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-tomcat7-ssl</artifactId>
<name>Spring Boot Tomcat 7 SSL Sample</name>
<description>Spring Boot Tomcat 7 SSL Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
<tomcat.version>7.0.69</tomcat.version>
</properties>
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat.ssl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleTomcatSslApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleTomcatSslApplication.class, args);
}
}
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat.ssl.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SampleController {
@GetMapping("/")
@ResponseBody
public String helloWorld() {
return "Hello, world";
}
}
server.port = 8443
server.ssl.key-store = classpath:sample.jks
server.ssl.key-store-password = secret
server.ssl.key-password = password
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.tomcat.ssl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class SampleTomcatSslApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testHome() throws Exception {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).isEqualTo("Hello, world");
}
}
...@@ -16,19 +16,13 @@ ...@@ -16,19 +16,13 @@
package org.springframework.boot.context.embedded.tomcat; package org.springframework.boot.context.embedded.tomcat;
import java.lang.reflect.Method;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletContext;
import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScanner;
import org.apache.tomcat.JarScannerCallback;
import org.apache.tomcat.util.scan.StandardJarScanFilter; import org.apache.tomcat.util.scan.StandardJarScanFilter;
import org.apache.tomcat.util.scan.StandardJarScanner; import org.apache.tomcat.util.scan.StandardJarScanner;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -42,40 +36,15 @@ import org.springframework.util.StringUtils; ...@@ -42,40 +36,15 @@ import org.springframework.util.StringUtils;
*/ */
class SkipPatternJarScanner extends StandardJarScanner { class SkipPatternJarScanner extends StandardJarScanner {
private static final String JAR_SCAN_FILTER_CLASS = "org.apache.tomcat.JarScanFilter";
private final JarScanner jarScanner; private final JarScanner jarScanner;
private final Set<String> patterns;
SkipPatternJarScanner(JarScanner jarScanner, Set<String> patterns) { SkipPatternJarScanner(JarScanner jarScanner, Set<String> patterns) {
Assert.notNull(jarScanner, "JarScanner must not be null"); Assert.notNull(jarScanner, "JarScanner must not be null");
Assert.notNull(jarScanner, "Patterns must not be null"); Assert.notNull(jarScanner, "Patterns must not be null");
this.jarScanner = jarScanner; this.jarScanner = jarScanner;
this.patterns = patterns; StandardJarScanFilter filter = new StandardJarScanFilter();
setPatternToTomcat8SkipFilter(); filter.setTldSkip(StringUtils.collectionToCommaDelimitedString(patterns));
} this.jarScanner.setJarScanFilter(filter);
private void setPatternToTomcat8SkipFilter() {
if (ClassUtils.isPresent(JAR_SCAN_FILTER_CLASS, null)) {
new Tomcat8TldSkipSetter(this).setSkipPattern(this.patterns);
}
}
// For Tomcat 7 compatibility
public void scan(ServletContext context, ClassLoader classloader,
JarScannerCallback callback, Set<String> jarsToSkip) {
Method scanMethod = ReflectionUtils.findMethod(this.jarScanner.getClass(), "scan",
ServletContext.class, ClassLoader.class, JarScannerCallback.class,
Set.class);
Assert.notNull(scanMethod, "Unable to find scan method");
try {
scanMethod.invoke(this.jarScanner, context, classloader, callback,
(jarsToSkip == null ? this.patterns : jarsToSkip));
}
catch (Exception ex) {
throw new IllegalStateException("Tomcat 7 reflection failed", ex);
}
} }
/** /**
...@@ -89,23 +58,4 @@ class SkipPatternJarScanner extends StandardJarScanner { ...@@ -89,23 +58,4 @@ class SkipPatternJarScanner extends StandardJarScanner {
context.setJarScanner(scanner); context.setJarScanner(scanner);
} }
/**
* Tomcat 8 specific logic to setup the scanner.
*/
private static class Tomcat8TldSkipSetter {
private final StandardJarScanner jarScanner;
Tomcat8TldSkipSetter(StandardJarScanner jarScanner) {
this.jarScanner = jarScanner;
}
public void setSkipPattern(Set<String> patterns) {
StandardJarScanFilter filter = new StandardJarScanFilter();
filter.setTldSkip(StringUtils.collectionToCommaDelimitedString(patterns));
this.jarScanner.setJarScanFilter(filter);
}
}
} }
...@@ -100,7 +100,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer ...@@ -100,7 +100,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
Context context = findContext(); Context context = findContext();
try { try {
ContextBindings.bindClassLoader(context, getNamingToken(context), ContextBindings.bindClassLoader(context, context.getNamingToken(),
getClass().getClassLoader()); getClass().getClassLoader());
} }
catch (NamingException ex) { catch (NamingException ex) {
...@@ -194,7 +194,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer ...@@ -194,7 +194,7 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
} }
finally { finally {
Context context = findContext(); Context context = findContext();
ContextBindings.unbindClassLoader(context, getNamingToken(context), ContextBindings.unbindClassLoader(context, context.getNamingToken(),
getClass().getClassLoader()); getClass().getClassLoader());
} }
} }
...@@ -317,15 +317,4 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer ...@@ -317,15 +317,4 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer
return this.tomcat; return this.tomcat;
} }
private Object getNamingToken(Context context) {
try {
return context.getNamingToken();
}
catch (NoSuchMethodError ex) {
// Use the context itself on Tomcat 7
return context;
}
}
} }
...@@ -18,8 +18,6 @@ package org.springframework.boot.context.embedded.tomcat; ...@@ -18,8 +18,6 @@ package org.springframework.boot.context.embedded.tomcat;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -34,7 +32,6 @@ import java.util.Set; ...@@ -34,7 +32,6 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import org.apache.catalina.Context; import org.apache.catalina.Context;
import org.apache.catalina.Engine; import org.apache.catalina.Engine;
...@@ -74,7 +71,6 @@ import org.springframework.core.io.ResourceLoader; ...@@ -74,7 +71,6 @@ import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -217,7 +213,6 @@ public class TomcatEmbeddedServletContainerFactory ...@@ -217,7 +213,6 @@ public class TomcatEmbeddedServletContainerFactory
if (shouldRegisterJspServlet()) { if (shouldRegisterJspServlet()) {
addJspServlet(context); addJspServlet(context);
addJasperInitializer(context); addJasperInitializer(context);
context.addLifecycleListener(new StoreMergedWebXmlListener());
} }
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
configureContext(context, initializersToUse); configureContext(context, initializersToUse);
...@@ -802,49 +797,6 @@ public class TomcatEmbeddedServletContainerFactory ...@@ -802,49 +797,6 @@ public class TomcatEmbeddedServletContainerFactory
this.backgroundProcessorDelay = delay; this.backgroundProcessorDelay = delay;
} }
/**
* {@link LifecycleListener} that stores an empty merged web.xml. This is critical for
* Jasper on Tomcat 7 to prevent warnings about missing web.xml files and to enable
* EL.
*/
private static class StoreMergedWebXmlListener implements LifecycleListener {
private static final String MERGED_WEB_XML = "org.apache.tomcat.util.scan.MergedWebXml";
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
onStart((Context) event.getLifecycle());
}
}
private void onStart(Context context) {
ServletContext servletContext = context.getServletContext();
if (servletContext.getAttribute(MERGED_WEB_XML) == null) {
servletContext.setAttribute(MERGED_WEB_XML, getEmptyWebXml());
}
TomcatResources.get(context).addClasspathResources();
}
private String getEmptyWebXml() {
InputStream stream = TomcatEmbeddedServletContainerFactory.class
.getResourceAsStream("empty-web.xml");
Assert.state(stream != null, "Unable to read empty web.xml");
try {
try {
return StreamUtils.copyToString(stream, Charset.forName("UTF-8"));
}
finally {
stream.close();
}
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
}
/** /**
* {@link LifecycleListener} to disable persistence in the {@link StandardManager}. A * {@link LifecycleListener} to disable persistence in the {@link StandardManager}. A
* {@link LifecycleListener} is used so not to interfere with Tomcat's default manager * {@link LifecycleListener} is used so not to interfere with Tomcat's default manager
......
...@@ -36,8 +36,6 @@ class TomcatErrorPage { ...@@ -36,8 +36,6 @@ class TomcatErrorPage {
private static final String ERROR_PAGE_CLASS = "org.apache.tomcat.util.descriptor.web.ErrorPage"; private static final String ERROR_PAGE_CLASS = "org.apache.tomcat.util.descriptor.web.ErrorPage";
private static final String LEGACY_ERROR_PAGE_CLASS = "org.apache.catalina.deploy.ErrorPage";
private final String location; private final String location;
private final String exceptionType; private final String exceptionType;
...@@ -59,10 +57,6 @@ class TomcatErrorPage { ...@@ -59,10 +57,6 @@ class TomcatErrorPage {
return BeanUtils return BeanUtils
.instantiateClass(ClassUtils.forName(ERROR_PAGE_CLASS, null)); .instantiateClass(ClassUtils.forName(ERROR_PAGE_CLASS, null));
} }
if (ClassUtils.isPresent(LEGACY_ERROR_PAGE_CLASS, null)) {
return BeanUtils.instantiateClass(
ClassUtils.forName(LEGACY_ERROR_PAGE_CLASS, null));
}
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
// Swallow and continue // Swallow and continue
...@@ -75,7 +69,7 @@ class TomcatErrorPage { ...@@ -75,7 +69,7 @@ class TomcatErrorPage {
public void addToContext(Context context) { public void addToContext(Context context) {
Assert.state(this.nativePage != null, Assert.state(this.nativePage != null,
"Neither Tomcat 7 nor 8 detected so no native error page exists"); "No Tomcat 8 detected so no native error page exists");
if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) { if (ClassUtils.isPresent(ERROR_PAGE_CLASS, null)) {
org.apache.tomcat.util.descriptor.web.ErrorPage errorPage = (org.apache.tomcat.util.descriptor.web.ErrorPage) this.nativePage; org.apache.tomcat.util.descriptor.web.ErrorPage errorPage = (org.apache.tomcat.util.descriptor.web.ErrorPage) this.nativePage;
errorPage.setLocation(this.location); errorPage.setLocation(this.location);
......
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.context.embedded.tomcat;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import javax.naming.directory.DirContext;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.WebResourceRoot.ResourceSetType;
import org.apache.catalina.core.StandardContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
* Abstraction to add resources that works with both Tomcat 8 and 7.
*
* @author Dave Syer
* @author Phillip Webb
*/
abstract class TomcatResources {
private final Context context;
TomcatResources(Context context) {
this.context = context;
}
/**
* Add resources from the classpath.
*/
public void addClasspathResources() {
ClassLoader loader = getClass().getClassLoader();
if (loader instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) loader).getURLs()) {
String file = url.getFile();
if (file.endsWith(".jar") || file.endsWith(".jar!/")) {
String jar = url.toString();
if (!jar.startsWith("jar:")) {
// A jar file in the file system. Convert to Jar URL.
jar = "jar:" + jar + "!/";
}
addJar(jar);
}
else if (url.toString().startsWith("file:")) {
String dir = url.toString().substring("file:".length());
if (new File(dir).isDirectory()) {
addDir(dir, url);
}
}
}
}
}
protected final Context getContext() {
return this.context;
}
/**
* Called to add a JAR to the resources.
* @param jar the URL spec for the jar
*/
protected abstract void addJar(String jar);
/**
* Called to add a dir to the resource.
* @param dir the dir
* @param url the URL
*/
protected abstract void addDir(String dir, URL url);
/**
* Return a {@link TomcatResources} instance for the currently running Tomcat version.
* @param context the tomcat context
* @return a {@link TomcatResources} instance.
*/
public static TomcatResources get(Context context) {
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
return new Tomcat7Resources(context);
}
return new Tomcat8Resources(context);
}
/**
* {@link TomcatResources} for Tomcat 7.
*/
private static class Tomcat7Resources extends TomcatResources {
private final Method addResourceJarUrlMethod;
Tomcat7Resources(Context context) {
super(context);
this.addResourceJarUrlMethod = ReflectionUtils.findMethod(context.getClass(),
"addResourceJarUrl", URL.class);
}
@Override
protected void addJar(String jar) {
URL url = getJarUrl(jar);
if (url != null) {
try {
this.addResourceJarUrlMethod.invoke(getContext(), url);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
private URL getJarUrl(String jar) {
try {
return new URL(jar);
}
catch (MalformedURLException ex) {
// Ignore
return null;
}
}
@Override
protected void addDir(String dir, URL url) {
if (getContext() instanceof ServletContext) {
try {
Class<?> fileDirContextClass = Class
.forName("org.apache.naming.resources.FileDirContext");
Method setDocBaseMethod = ReflectionUtils
.findMethod(fileDirContextClass, "setDocBase", String.class);
Object fileDirContext = fileDirContextClass.newInstance();
setDocBaseMethod.invoke(fileDirContext, dir);
Method addResourcesDirContextMethod = ReflectionUtils.findMethod(
StandardContext.class, "addResourcesDirContext",
DirContext.class);
addResourcesDirContextMethod.invoke(getContext(), fileDirContext);
}
catch (Exception ex) {
throw new IllegalStateException("Tomcat 7 reflection failed", ex);
}
}
}
}
/**
* {@link TomcatResources} for Tomcat 8.
*/
static class Tomcat8Resources extends TomcatResources {
Tomcat8Resources(Context context) {
super(context);
}
@Override
protected void addJar(String jar) {
addResourceSet(jar);
}
@Override
protected void addDir(String dir, URL url) {
addResourceSet(url.toString());
}
private void addResourceSet(String resource) {
try {
if (isInsideNestedJar(resource)) {
// It's a nested jar but we now don't want the suffix because Tomcat
// is going to try and locate it as a root URL (not the resource
// inside it)
resource = resource.substring(0, resource.length() - 2);
}
URL url = new URL(resource);
String path = "/META-INF/resources";
getContext().getResources().createWebResourceSet(
ResourceSetType.RESOURCE_JAR, "/", url, path);
}
catch (Exception ex) {
// Ignore (probably not a directory)
}
}
private boolean isInsideNestedJar(String dir) {
return dir.indexOf("!/") < dir.lastIndexOf("!/");
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment