mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Use reflection hack for error page in Tocmat 8
This commit is contained in:
parent
b4542f722f
commit
6e8cbbde3b
1
pom.xml
1
pom.xml
@ -22,7 +22,6 @@
|
|||||||
<module>spring-boot-starters</module>
|
<module>spring-boot-starters</module>
|
||||||
<module>spring-boot-cli</module>
|
<module>spring-boot-cli</module>
|
||||||
<module>spring-boot-integration-tests</module>
|
<module>spring-boot-integration-tests</module>
|
||||||
<module>spring-boot-containers/spring-boot-tomcat8</module>
|
|
||||||
</modules>
|
</modules>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
<?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>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-parent</artifactId>
|
|
||||||
<version>0.5.0.BUILD-SNAPSHOT</version>
|
|
||||||
<relativePath>../../spring-boot-parent</relativePath>
|
|
||||||
</parent>
|
|
||||||
<artifactId>spring-boot-tomcat8</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<properties>
|
|
||||||
<main.basedir>${basedir}/../..</main.basedir>
|
|
||||||
<tomcat8.version>8.0.0-RC1</tomcat8.version>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<!-- Compile -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>${project.groupId}</groupId>
|
|
||||||
<artifactId>spring-boot</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- Optional -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
|
||||||
<artifactId>tomcat-embed-core</artifactId>
|
|
||||||
<version>${tomcat8.version}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<!-- Test -->
|
|
||||||
</dependencies>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>test-jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2013 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.tomcat8;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
|
|
||||||
import org.apache.catalina.Lifecycle;
|
|
||||||
import org.apache.catalina.LifecycleEvent;
|
|
||||||
import org.apache.catalina.LifecycleListener;
|
|
||||||
import org.apache.catalina.core.StandardContext;
|
|
||||||
import org.springframework.boot.context.embedded.ServletContextInitializer;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tomcat {@link LifecycleListener} that calls {@link ServletContextInitializer}s.
|
|
||||||
*
|
|
||||||
* @author Phillip Webb
|
|
||||||
*/
|
|
||||||
public class ServletContextInitializerLifecycleListener implements LifecycleListener {
|
|
||||||
|
|
||||||
private ServletContextInitializer[] initializers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link ServletContextInitializerLifecycleListener} instance with the
|
|
||||||
* specified initializers.
|
|
||||||
* @param initializers the initializers to call
|
|
||||||
*/
|
|
||||||
public ServletContextInitializerLifecycleListener(
|
|
||||||
ServletContextInitializer... initializers) {
|
|
||||||
this.initializers = initializers;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void lifecycleEvent(LifecycleEvent event) {
|
|
||||||
if (Lifecycle.CONFIGURE_START_EVENT.equals(event.getType())) {
|
|
||||||
Assert.isInstanceOf(StandardContext.class, event.getSource());
|
|
||||||
StandardContext standardContext = (StandardContext) event.getSource();
|
|
||||||
for (ServletContextInitializer initializer : this.initializers) {
|
|
||||||
try {
|
|
||||||
initializer.onStartup(standardContext.getServletContext());
|
|
||||||
}
|
|
||||||
catch (ServletException ex) {
|
|
||||||
throw new IllegalStateException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2013 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.tomcat8;
|
|
||||||
|
|
||||||
import org.apache.catalina.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Dave Syer
|
|
||||||
*/
|
|
||||||
public interface TomcatContextCustomizer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context the context to customize
|
|
||||||
*/
|
|
||||||
void customize(Context context);
|
|
||||||
|
|
||||||
}
|
|
@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2013 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.tomcat8;
|
|
||||||
|
|
||||||
import org.apache.catalina.LifecycleException;
|
|
||||||
import org.apache.catalina.connector.Connector;
|
|
||||||
import org.apache.catalina.startup.Tomcat;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link EmbeddedServletContainer} that can be used to control an embedded Tomcat server.
|
|
||||||
* Usually this class should be created using the
|
|
||||||
* {@link TomcatEmbeddedServletContainerFactory} and not directly.
|
|
||||||
*
|
|
||||||
* @author Phillip Webb
|
|
||||||
* @author Dave Syer
|
|
||||||
* @see TomcatEmbeddedServletContainerFactory
|
|
||||||
*/
|
|
||||||
public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer {
|
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(TomcatEmbeddedServletContainer.class);
|
|
||||||
|
|
||||||
private static int containerCounter = 0;
|
|
||||||
|
|
||||||
private final Tomcat tomcat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link TomcatEmbeddedServletContainer} instance.
|
|
||||||
* @param tomcat the underlying Tomcat server
|
|
||||||
*/
|
|
||||||
public TomcatEmbeddedServletContainer(Tomcat tomcat) {
|
|
||||||
Assert.notNull(tomcat, "Tomcat Server must not be null");
|
|
||||||
this.tomcat = tomcat;
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void initialize() throws EmbeddedServletContainerException {
|
|
||||||
try {
|
|
||||||
this.tomcat.start();
|
|
||||||
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
|
|
||||||
// blocking non-daemon to stop immediate shutdown
|
|
||||||
Thread awaitThread = new Thread("container-" + (containerCounter++)) {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
TomcatEmbeddedServletContainer.this.tomcat.getServer().await();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
awaitThread.setDaemon(false);
|
|
||||||
awaitThread.start();
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new EmbeddedServletContainerException(
|
|
||||||
"Unable to start embdedded Tomcat", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start() throws EmbeddedServletContainerException {
|
|
||||||
Connector connector = this.tomcat.getConnector();
|
|
||||||
if (connector != null) {
|
|
||||||
try {
|
|
||||||
connector.getProtocolHandler().resume();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
this.logger.error("Cannot start connector: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void stop() throws EmbeddedServletContainerException {
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
this.tomcat.stop();
|
|
||||||
}
|
|
||||||
catch (LifecycleException ex) {
|
|
||||||
// swallow and continue
|
|
||||||
}
|
|
||||||
this.tomcat.destroy();
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new EmbeddedServletContainerException(
|
|
||||||
"Unable to stop embdedded Tomcat", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns access to the underlying Tomcat server.
|
|
||||||
*/
|
|
||||||
public Tomcat getTomcat() {
|
|
||||||
return this.tomcat;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,383 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2013 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.tomcat8;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.catalina.Context;
|
|
||||||
import org.apache.catalina.Host;
|
|
||||||
import org.apache.catalina.LifecycleListener;
|
|
||||||
import org.apache.catalina.Valve;
|
|
||||||
import org.apache.catalina.Wrapper;
|
|
||||||
import org.apache.catalina.connector.Connector;
|
|
||||||
import org.apache.catalina.core.StandardContext;
|
|
||||||
import org.apache.catalina.loader.WebappLoader;
|
|
||||||
import org.apache.catalina.startup.Tomcat;
|
|
||||||
import org.apache.catalina.startup.Tomcat.FixContextListener;
|
|
||||||
import org.apache.coyote.AbstractProtocol;
|
|
||||||
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
|
||||||
import org.springframework.boot.context.embedded.ErrorPage;
|
|
||||||
import org.springframework.boot.context.embedded.MimeMappings;
|
|
||||||
import org.springframework.boot.context.embedded.ServletContextInitializer;
|
|
||||||
import org.springframework.context.ResourceLoaderAware;
|
|
||||||
import org.springframework.core.io.ResourceLoader;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link EmbeddedServletContainerFactory} that can be used to create
|
|
||||||
* {@link TomcatEmbeddedServletContainer}s. Can be initialized using Spring's
|
|
||||||
* {@link ServletContextInitializer}s or Tomcat {@link LifecycleListener}s.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Unless explicitly configured otherwise this factory will created containers that
|
|
||||||
* listens for HTTP requests on port 8080.
|
|
||||||
*
|
|
||||||
* @author Phillip Webb
|
|
||||||
* @author Dave Syer
|
|
||||||
* @see #setPort(int)
|
|
||||||
* @see #setContextLifecycleListeners(Collection)
|
|
||||||
* @see TomcatEmbeddedServletContainer
|
|
||||||
*/
|
|
||||||
public class TomcatEmbeddedServletContainerFactory extends
|
|
||||||
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
|
||||||
|
|
||||||
private static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
|
|
||||||
|
|
||||||
private File baseDirectory;
|
|
||||||
|
|
||||||
private List<Valve> contextValves = new ArrayList<Valve>();
|
|
||||||
|
|
||||||
private List<LifecycleListener> contextLifecycleListeners = new ArrayList<LifecycleListener>();
|
|
||||||
|
|
||||||
private List<TomcatContextCustomizer> tomcatContextCustomizers = new ArrayList<TomcatContextCustomizer>();
|
|
||||||
|
|
||||||
private ResourceLoader resourceLoader;
|
|
||||||
|
|
||||||
private String protocol = DEFAULT_PROTOCOL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} instance.
|
|
||||||
*/
|
|
||||||
public TomcatEmbeddedServletContainerFactory() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} that listens for
|
|
||||||
* requests using the specified port.
|
|
||||||
* @param port the port to listen on
|
|
||||||
*/
|
|
||||||
public TomcatEmbeddedServletContainerFactory(int port) {
|
|
||||||
super(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link TomcatEmbeddedServletContainerFactory} with the specified
|
|
||||||
* context path and port.
|
|
||||||
* @param contextPath root the context path
|
|
||||||
* @param port the port to listen on
|
|
||||||
*/
|
|
||||||
public TomcatEmbeddedServletContainerFactory(String contextPath, int port) {
|
|
||||||
super(contextPath, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EmbeddedServletContainer getEmbeddedServletContainer(
|
|
||||||
ServletContextInitializer... initializers) {
|
|
||||||
|
|
||||||
Connector connector;
|
|
||||||
Tomcat tomcat = new Tomcat();
|
|
||||||
|
|
||||||
if (getPort() == 0) {
|
|
||||||
return EmbeddedServletContainer.NONE;
|
|
||||||
}
|
|
||||||
File baseDir = (this.baseDirectory != null ? this.baseDirectory
|
|
||||||
: createTempDir("tomcat"));
|
|
||||||
tomcat.setBaseDir(baseDir.getAbsolutePath());
|
|
||||||
connector = new Connector(this.protocol);
|
|
||||||
customizeConnector(connector);
|
|
||||||
tomcat.getService().addConnector(connector);
|
|
||||||
tomcat.setConnector(connector);
|
|
||||||
try {
|
|
||||||
// Allow the server to start so the ServletContext is available, but stop the
|
|
||||||
// connector to prevent requests from being handled before the Spring context
|
|
||||||
// is ready:
|
|
||||||
connector.getProtocolHandler().pause();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
this.logger.error("Cannot pause connector: ", e);
|
|
||||||
}
|
|
||||||
tomcat.getHost().setAutoDeploy(false);
|
|
||||||
tomcat.getEngine().setBackgroundProcessorDelay(-1);
|
|
||||||
|
|
||||||
prepareContext(tomcat.getHost(), initializers);
|
|
||||||
return getTomcatEmbeddedServletContainer(tomcat);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
|
|
||||||
File docBase = getValidDocumentRoot();
|
|
||||||
docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase"));
|
|
||||||
Context context = new StandardContext();
|
|
||||||
context.setName(getContextPath());
|
|
||||||
context.setPath(getContextPath());
|
|
||||||
context.setDocBase(docBase.getAbsolutePath());
|
|
||||||
context.addLifecycleListener(new FixContextListener());
|
|
||||||
context.setParentClassLoader(this.resourceLoader != null ? this.resourceLoader
|
|
||||||
.getClassLoader() : ClassUtils.getDefaultClassLoader());
|
|
||||||
WebappLoader loader = new WebappLoader(context.getParentClassLoader());
|
|
||||||
loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
|
|
||||||
context.setLoader(loader);
|
|
||||||
if (isRegisterDefaultServlet()) {
|
|
||||||
addDefaultServlet(context);
|
|
||||||
}
|
|
||||||
if (isRegisterJspServlet()
|
|
||||||
&& ClassUtils.isPresent(getJspServletClassName(), getClass()
|
|
||||||
.getClassLoader())) {
|
|
||||||
addJspServlet(context);
|
|
||||||
}
|
|
||||||
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
|
|
||||||
configureContext(context, initializersToUse);
|
|
||||||
host.addChild(context);
|
|
||||||
postProcessContext(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDefaultServlet(Context context) {
|
|
||||||
Wrapper defaultServlet = context.createWrapper();
|
|
||||||
defaultServlet.setName("default");
|
|
||||||
defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
|
|
||||||
defaultServlet.addInitParameter("debug", "0");
|
|
||||||
defaultServlet.addInitParameter("listings", "false");
|
|
||||||
defaultServlet.setLoadOnStartup(1);
|
|
||||||
// Otherwise the default location of a Spring DispatcherServlet cannot be set
|
|
||||||
defaultServlet.setOverridable(true);
|
|
||||||
context.addChild(defaultServlet);
|
|
||||||
context.addServletMapping("/", "default");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addJspServlet(Context context) {
|
|
||||||
Wrapper jspServlet = context.createWrapper();
|
|
||||||
jspServlet.setName("jsp");
|
|
||||||
jspServlet.setServletClass(getJspServletClassName());
|
|
||||||
jspServlet.addInitParameter("fork", "false");
|
|
||||||
jspServlet.setLoadOnStartup(3);
|
|
||||||
context.addChild(jspServlet);
|
|
||||||
context.addServletMapping("*.jsp", "jsp");
|
|
||||||
context.addServletMapping("*.jspx", "jsp");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needs to be protected so it can be used by subclasses
|
|
||||||
protected void customizeConnector(Connector connector) {
|
|
||||||
connector.setPort(getPort());
|
|
||||||
if (connector.getProtocolHandler() instanceof AbstractProtocol
|
|
||||||
&& getAddress() != null) {
|
|
||||||
((AbstractProtocol) connector.getProtocolHandler()).setAddress(getAddress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Tomcat {@link Context}.
|
|
||||||
* @param context the Tomcat context
|
|
||||||
* @param initializers initializers to apply
|
|
||||||
*/
|
|
||||||
protected void configureContext(Context context,
|
|
||||||
ServletContextInitializer[] initializers) {
|
|
||||||
context.addLifecycleListener(new ServletContextInitializerLifecycleListener(
|
|
||||||
initializers));
|
|
||||||
for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {
|
|
||||||
context.addLifecycleListener(lifecycleListener);
|
|
||||||
}
|
|
||||||
for (Valve valve : this.contextValves) {
|
|
||||||
context.getPipeline().addValve(valve);
|
|
||||||
}
|
|
||||||
for (ErrorPage errorPage : getErrorPages()) {
|
|
||||||
org.apache.tomcat.util.descriptor.web.ErrorPage tomcatPage = new org.apache.tomcat.util.descriptor.web.ErrorPage();
|
|
||||||
tomcatPage.setLocation(errorPage.getPath());
|
|
||||||
tomcatPage.setExceptionType(errorPage.getExceptionName());
|
|
||||||
tomcatPage.setErrorCode(errorPage.getStatusCode());
|
|
||||||
context.addErrorPage(tomcatPage);
|
|
||||||
}
|
|
||||||
for (MimeMappings.Mapping mapping : getMimeMappings()) {
|
|
||||||
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
|
|
||||||
}
|
|
||||||
context.setSessionTimeout(getSessionTimeout());
|
|
||||||
for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {
|
|
||||||
customizer.customize(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Post process the Tomcat {@link Context} before it used with the Tomcat Server.
|
|
||||||
* Subclasses can override this method to apply additional processing to the
|
|
||||||
* {@link Context}.
|
|
||||||
* @param context the Tomcat {@link Context}
|
|
||||||
*/
|
|
||||||
protected void postProcessContext(Context context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method called to create the {@link TomcatEmbeddedServletContainer}.
|
|
||||||
* Subclasses can override this method to return a different
|
|
||||||
* {@link TomcatEmbeddedServletContainer} or apply additional processing to the Tomcat
|
|
||||||
* server.
|
|
||||||
* @param tomcat the Tomcat server.
|
|
||||||
* @return a new {@link TomcatEmbeddedServletContainer} instance
|
|
||||||
*/
|
|
||||||
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
|
|
||||||
Tomcat tomcat) {
|
|
||||||
return new TomcatEmbeddedServletContainer(tomcat);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File createTempDir(String prefix) {
|
|
||||||
try {
|
|
||||||
File tempFolder = File.createTempFile(prefix + ".", "." + getPort());
|
|
||||||
tempFolder.delete();
|
|
||||||
tempFolder.mkdir();
|
|
||||||
tempFolder.deleteOnExit();
|
|
||||||
return tempFolder;
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new EmbeddedServletContainerException(
|
|
||||||
"Unable to create Tomcat tempdir", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
|
||||||
this.resourceLoader = resourceLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Tomcat base directory. If not specified a temporary directory will be used.
|
|
||||||
* @param baseDirectory the tomcat base directory
|
|
||||||
*/
|
|
||||||
public void setBaseDirectory(File baseDirectory) {
|
|
||||||
this.baseDirectory = baseDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Tomcat protocol to use when create the {@link Connector}.
|
|
||||||
* @see Connector#Connector(String)
|
|
||||||
*/
|
|
||||||
public void setProtocol(String protocol) {
|
|
||||||
Assert.hasLength(protocol, "Protocol must not be empty");
|
|
||||||
this.protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set {@link Valve}s that should be applied to the Tomcat {@link Context}. Calling
|
|
||||||
* this method will replace any existing listeners.
|
|
||||||
* @param contextValves the valves to set
|
|
||||||
*/
|
|
||||||
public void setContextValves(Collection<? extends Valve> contextValves) {
|
|
||||||
Assert.notNull(contextValves, "Valves must not be null");
|
|
||||||
this.contextValves = new ArrayList<Valve>(contextValves);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a mutable collection of the {@link Valve}s that will be applied to the
|
|
||||||
* Tomcat {@link Context}.
|
|
||||||
* @return the contextValves the valves that will be applied
|
|
||||||
*/
|
|
||||||
public Collection<Valve> getValves() {
|
|
||||||
return this.contextValves;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add {@link Valve}s that should be applied to the Tomcat {@link Context}.
|
|
||||||
* @param contextValves the valves to add
|
|
||||||
*/
|
|
||||||
public void addContextValves(Valve... contextValves) {
|
|
||||||
Assert.notNull(contextValves, "Valves must not be null");
|
|
||||||
this.contextValves.addAll(Arrays.asList(contextValves));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set {@link LifecycleListener}s that should be applied to the Tomcat {@link Context}
|
|
||||||
* . Calling this method will replace any existing listeners.
|
|
||||||
* @param contextLifecycleListeners the listeners to set
|
|
||||||
*/
|
|
||||||
public void setContextLifecycleListeners(
|
|
||||||
Collection<? extends LifecycleListener> contextLifecycleListeners) {
|
|
||||||
Assert.notNull(contextLifecycleListeners,
|
|
||||||
"ContextLifecycleListeners must not be null");
|
|
||||||
this.contextLifecycleListeners = new ArrayList<LifecycleListener>(
|
|
||||||
contextLifecycleListeners);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a mutable collection of the {@link LifecycleListener}s that will be applied
|
|
||||||
* to the Tomcat {@link Context} .
|
|
||||||
* @return the contextLifecycleListeners the listeners that will be applied
|
|
||||||
*/
|
|
||||||
public Collection<LifecycleListener> getContextLifecycleListeners() {
|
|
||||||
return this.contextLifecycleListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add {@link LifecycleListener}s that should be added to the Tomcat {@link Context}.
|
|
||||||
* @param contextLifecycleListeners the listeners to add
|
|
||||||
*/
|
|
||||||
public void addContextLifecycleListeners(
|
|
||||||
LifecycleListener... contextLifecycleListeners) {
|
|
||||||
Assert.notNull(contextLifecycleListeners,
|
|
||||||
"ContextLifecycleListeners must not be null");
|
|
||||||
this.contextLifecycleListeners.addAll(Arrays.asList(contextLifecycleListeners));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set {@link TomcatContextCustomizer}s that should be applied to the Tomcat
|
|
||||||
* {@link Context} . Calling this method will replace any existing customizers.
|
|
||||||
* @param tomcatContextCustomizers the customizers to set
|
|
||||||
*/
|
|
||||||
public void setTomcatContextCustomizers(
|
|
||||||
Collection<? extends TomcatContextCustomizer> tomcatContextCustomizers) {
|
|
||||||
Assert.notNull(this.contextLifecycleListeners,
|
|
||||||
"TomcatContextCustomizers must not be null");
|
|
||||||
this.tomcatContextCustomizers = new ArrayList<TomcatContextCustomizer>(
|
|
||||||
tomcatContextCustomizers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a mutable collection of the {@link TomcatContextCustomizer}s that will be
|
|
||||||
* applied to the Tomcat {@link Context} .
|
|
||||||
* @return the tomcatContextCustomizers the listeners that will be applied
|
|
||||||
*/
|
|
||||||
public Collection<TomcatContextCustomizer> getTomcatContextCustomizers() {
|
|
||||||
return this.tomcatContextCustomizers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add {@link TomcatContextCustomizer}s that should be added to the Tomcat
|
|
||||||
* {@link Context}.
|
|
||||||
* @param tomcatContextCustomizers the customizers to add
|
|
||||||
*/
|
|
||||||
public void addContextCustomizers(TomcatContextCustomizer... tomcatContextCustomizers) {
|
|
||||||
Assert.notNull(this.tomcatContextCustomizers,
|
|
||||||
"TomcatContextCustomizer must not be null");
|
|
||||||
this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
package org.springframework.boot.context.embedded.tomcat8;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012-2013 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.apache.catalina.loader.WebappClassLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of Tomcat's {@link WebappClassLoader} that does not consider the
|
|
||||||
* {@link ClassLoader#getSystemClassLoader() system classloader}. This is required to to
|
|
||||||
* ensure that any custom context classloader is always used (as is the case with some
|
|
||||||
* executable archives).
|
|
||||||
*
|
|
||||||
* @author Phillip Webb
|
|
||||||
*/
|
|
||||||
public class TomcatEmbeddedWebappClassLoader extends WebappClassLoader {
|
|
||||||
|
|
||||||
public TomcatEmbeddedWebappClassLoader() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TomcatEmbeddedWebappClassLoader(ClassLoader parent) {
|
|
||||||
super(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Class<?> loadClass(String name, boolean resolve)
|
|
||||||
throws ClassNotFoundException {
|
|
||||||
|
|
||||||
Class<?> resultClass = null;
|
|
||||||
|
|
||||||
// Check local class caches
|
|
||||||
resultClass = (resultClass == null ? findLoadedClass0(name) : resultClass);
|
|
||||||
resultClass = (resultClass == null ? findLoadedClass(name) : resultClass);
|
|
||||||
if (resultClass != null) {
|
|
||||||
return resolveIfNecessary(resultClass, resolve);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check security
|
|
||||||
checkPackageAccess(name);
|
|
||||||
|
|
||||||
// Perform the actual load
|
|
||||||
boolean delegateLoad = (this.delegate || filter(name));
|
|
||||||
|
|
||||||
if (delegateLoad) {
|
|
||||||
resultClass = (resultClass == null ? loadFromParent(name) : resultClass);
|
|
||||||
}
|
|
||||||
resultClass = (resultClass == null ? findClassIgnoringNotFound(name)
|
|
||||||
: resultClass);
|
|
||||||
if (!delegateLoad) {
|
|
||||||
resultClass = (resultClass == null ? loadFromParent(name) : resultClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultClass == null) {
|
|
||||||
throw new ClassNotFoundException(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveIfNecessary(resultClass, resolve);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> resolveIfNecessary(Class<?> resultClass, boolean resolve) {
|
|
||||||
if (resolve) {
|
|
||||||
resolveClass(resultClass);
|
|
||||||
}
|
|
||||||
return (resultClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> loadFromParent(String name) {
|
|
||||||
if (this.parent == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Class.forName(name, false, this.parent);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> findClassIgnoringNotFound(String name) {
|
|
||||||
try {
|
|
||||||
return findClass(name);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkPackageAccess(String name) throws ClassNotFoundException {
|
|
||||||
if (this.securityManager != null && name.lastIndexOf('.') >= 0) {
|
|
||||||
try {
|
|
||||||
this.securityManager.checkPackageAccess(name.substring(0,
|
|
||||||
name.lastIndexOf('.')));
|
|
||||||
}
|
|
||||||
catch (SecurityException se) {
|
|
||||||
throw new ClassNotFoundException("Security Violation, attempt to use "
|
|
||||||
+ "Restricted Class: " + name, se);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2013 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for Tomcat {@link org.springframework.boot.context.embedded.EmbeddedServletContainer EmbeddedServletContainers}.
|
|
||||||
*/
|
|
||||||
package org.springframework.boot.context.embedded.tomcat8;
|
|
||||||
|
|
@ -273,6 +273,11 @@
|
|||||||
<artifactId>spring-tx</artifactId>
|
<artifactId>spring-tx</artifactId>
|
||||||
<version>${spring.version}</version>
|
<version>${spring.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-websocket</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-web</artifactId>
|
<artifactId>spring-web</artifactId>
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<module>spring-boot-sample-traditional</module>
|
<module>spring-boot-sample-traditional</module>
|
||||||
<module>spring-boot-sample-web-static</module>
|
<module>spring-boot-sample-web-static</module>
|
||||||
<module>spring-boot-sample-web-ui</module>
|
<module>spring-boot-sample-web-ui</module>
|
||||||
|
<module>spring-boot-sample-websocket</module>
|
||||||
<module>spring-boot-sample-xml</module>
|
<module>spring-boot-sample-xml</module>
|
||||||
</modules>
|
</modules>
|
||||||
<build>
|
<build>
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.7</java.version>
|
<java.version>1.7</java.version>
|
||||||
<tomcat.version>8.0-SNAPSHOT</tomcat.version>
|
<tomcat.version>8.0.0-RC1</tomcat.version>
|
||||||
|
<spring.version>4.0.0.BUILD-SNAPSHOT</spring.version>
|
||||||
<start-class>org.springframework.boot.samples.websocket.config.ApplicationConfiguration</start-class>
|
<start-class>org.springframework.boot.samples.websocket.config.ApplicationConfiguration</start-class>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@ -23,7 +24,10 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- For SockJS -->
|
<!-- For SockJS -->
|
||||||
<dependency>
|
<dependency>
|
@ -32,7 +32,7 @@ import org.springframework.boot.samples.websocket.echo.DefaultEchoService;
|
|||||||
import org.springframework.boot.samples.websocket.echo.EchoService;
|
import org.springframework.boot.samples.websocket.echo.EchoService;
|
||||||
import org.springframework.boot.samples.websocket.echo.EchoWebSocketHandler;
|
import org.springframework.boot.samples.websocket.echo.EchoWebSocketHandler;
|
||||||
import org.springframework.boot.samples.websocket.snake.SnakeWebSocketHandler;
|
import org.springframework.boot.samples.websocket.snake.SnakeWebSocketHandler;
|
||||||
import org.springframework.boot.web.SpringServletInitializer;
|
import org.springframework.boot.web.SpringBootServletInitializer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
@ -40,13 +40,13 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||||
import org.springframework.web.socket.WebSocketHandler;
|
import org.springframework.web.socket.WebSocketHandler;
|
||||||
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
|
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
|
||||||
|
import org.springframework.web.socket.sockjs.SockJsHttpRequestHandler;
|
||||||
import org.springframework.web.socket.sockjs.SockJsService;
|
import org.springframework.web.socket.sockjs.SockJsService;
|
||||||
import org.springframework.web.socket.sockjs.support.DefaultSockJsService;
|
import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService;
|
||||||
import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler;
|
|
||||||
import org.springframework.web.socket.support.PerConnectionWebSocketHandler;
|
import org.springframework.web.socket.support.PerConnectionWebSocketHandler;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SampleWebSocketsApplication extends SpringServletInitializer {
|
public class SampleWebSocketsApplication extends SpringBootServletInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getConfigClasses() {
|
protected Class<?>[] getConfigClasses() {
|
||||||
|
@ -17,28 +17,59 @@ package org.springframework.boot.samples.websocket.echo;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.boot.CommandLineRunner;
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.samples.websocket.client.GreetingService;
|
import org.springframework.boot.samples.websocket.client.GreetingService;
|
||||||
import org.springframework.boot.samples.websocket.client.SimpleClientWebSocketHandler;
|
import org.springframework.boot.samples.websocket.client.SimpleClientWebSocketHandler;
|
||||||
import org.springframework.boot.samples.websocket.client.SimpleGreetingService;
|
import org.springframework.boot.samples.websocket.client.SimpleGreetingService;
|
||||||
|
import org.springframework.boot.samples.websocket.config.SampleWebSocketsApplication;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.socket.client.WebSocketConnectionManager;
|
import org.springframework.web.socket.client.WebSocketConnectionManager;
|
||||||
import org.springframework.web.socket.client.endpoint.StandardWebSocketClient;
|
import org.springframework.web.socket.client.endpoint.StandardWebSocketClient;
|
||||||
|
|
||||||
public class StandardClientApp {
|
public class SampleWebSocketsApplicationTests {
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(StandardClientApp.class);
|
private static Log logger = LogFactory.getLog(SampleWebSocketsApplicationTests.class);
|
||||||
|
|
||||||
private static final String WS_URI = "ws://localhost:8080/echo";
|
private static final String WS_URI = "ws://localhost:8080/echo";
|
||||||
|
|
||||||
|
private static ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void start() throws Exception {
|
||||||
|
Future<ConfigurableApplicationContext> future = Executors
|
||||||
|
.newSingleThreadExecutor().submit(
|
||||||
|
new Callable<ConfigurableApplicationContext>() {
|
||||||
|
@Override
|
||||||
|
public ConfigurableApplicationContext call() throws Exception {
|
||||||
|
return (ConfigurableApplicationContext) SpringApplication
|
||||||
|
.run(SampleWebSocketsApplication.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
context = future.get(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void stop() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runAndWait() throws Exception {
|
public void runAndWait() throws Exception {
|
||||||
ApplicationContext context = SpringApplication.run(ClientConfiguration.class, "--spring.main.web_environment=false");
|
ApplicationContext context = SpringApplication.run(ClientConfiguration.class, "--spring.main.web_environment=false");
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<!-- This POM file that can be used as a parent for your own builds. It provides
|
<!-- This POM file that can be used as a parent for your own builds. It provides
|
||||||
generally useful dependencies and plugins. NOTE: If you are editing a local
|
generally useful dependencies and plugins. NOTE: If you are editing a local
|
||||||
checkout of this file, be sure to modify 'spring-boot-starters/src/main/parent/pom.xml'. -->
|
checkout of this file, be sure to modify 'spring-boot-starter-parent/src/main/parent/pom.xml'. -->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
@ -88,6 +88,11 @@
|
|||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
<version>${spring.boot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<!-- This POM file that can be used as a parent for your own builds. It provides
|
<!-- This POM file that can be used as a parent for your own builds. It provides
|
||||||
generally useful dependencies and plugins. NOTE: If you are editing a local
|
generally useful dependencies and plugins. NOTE: If you are editing a local
|
||||||
checkout of this file, be sure to modify 'spring-boot-starters/src/main/parent/pom.xml'. -->
|
checkout of this file, be sure to modify 'spring-boot-starter-parent/src/main/parent/pom.xml'. -->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
@ -88,6 +88,11 @@
|
|||||||
<artifactId>spring-boot-starter-security</artifactId>
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
<version>${spring.boot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
<main.basedir>${basedir}/../..</main.basedir>
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
<tomcat.version>8.0-SNAPSHOT</tomcat.version>
|
<tomcat.version>8.0.0-RC1</tomcat.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -35,14 +35,13 @@
|
|||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>spring-boot-up-tomcat</artifactId>
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-websocket</artifactId>
|
<artifactId>spring-websocket</artifactId>
|
||||||
<version>${spring.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
@ -53,16 +52,4 @@
|
|||||||
<artifactId>tomcat-embed-logging-juli</artifactId>
|
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>tomcat-snapshots</id>
|
|
||||||
<url>https://repository.apache.org/content/repositories/snapshots</url>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</snapshots>
|
|
||||||
<releases>
|
|
||||||
<enabled>false</enabled>
|
|
||||||
</releases>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded.tomcat;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -34,6 +35,7 @@ import org.apache.catalina.loader.WebappLoader;
|
|||||||
import org.apache.catalina.startup.Tomcat;
|
import org.apache.catalina.startup.Tomcat;
|
||||||
import org.apache.catalina.startup.Tomcat.FixContextListener;
|
import org.apache.catalina.startup.Tomcat.FixContextListener;
|
||||||
import org.apache.coyote.AbstractProtocol;
|
import org.apache.coyote.AbstractProtocol;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
||||||
@ -45,6 +47,7 @@ import org.springframework.context.ResourceLoaderAware;
|
|||||||
import org.springframework.core.io.ResourceLoader;
|
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.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EmbeddedServletContainerFactory} that can be used to create
|
* {@link EmbeddedServletContainerFactory} that can be used to create
|
||||||
@ -213,11 +216,7 @@ public class TomcatEmbeddedServletContainerFactory extends
|
|||||||
context.getPipeline().addValve(valve);
|
context.getPipeline().addValve(valve);
|
||||||
}
|
}
|
||||||
for (ErrorPage errorPage : getErrorPages()) {
|
for (ErrorPage errorPage : getErrorPages()) {
|
||||||
org.apache.catalina.deploy.ErrorPage tomcatPage = new org.apache.catalina.deploy.ErrorPage();
|
new TomcatErrorPage(errorPage).addToContext(context);
|
||||||
tomcatPage.setLocation(errorPage.getPath());
|
|
||||||
tomcatPage.setExceptionType(errorPage.getExceptionName());
|
|
||||||
tomcatPage.setErrorCode(errorPage.getStatusCode());
|
|
||||||
context.addErrorPage(tomcatPage);
|
|
||||||
}
|
}
|
||||||
for (MimeMappings.Mapping mapping : getMimeMappings()) {
|
for (MimeMappings.Mapping mapping : getMimeMappings()) {
|
||||||
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
|
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
|
||||||
@ -380,4 +379,67 @@ public class TomcatEmbeddedServletContainerFactory extends
|
|||||||
this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers));
|
this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TomcatErrorPage {
|
||||||
|
|
||||||
|
private String location;
|
||||||
|
private String exceptionType;
|
||||||
|
private int errorCode;
|
||||||
|
|
||||||
|
private Object nativePage;
|
||||||
|
|
||||||
|
public TomcatErrorPage(ErrorPage errorPage) {
|
||||||
|
this.location = errorPage.getPath();
|
||||||
|
this.exceptionType = errorPage.getExceptionName();
|
||||||
|
this.errorCode = errorPage.getStatusCode();
|
||||||
|
this.nativePage = createNativePage(errorPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object createNativePage(ErrorPage errorPage) {
|
||||||
|
Object nativePage = null;
|
||||||
|
try {
|
||||||
|
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
|
||||||
|
nativePage = new org.apache.catalina.deploy.ErrorPage();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ClassUtils.isPresent(
|
||||||
|
"org.apache.tomcat.util.descriptor.web.ErrorPage", null)) {
|
||||||
|
nativePage = BeanUtils.instantiate(ClassUtils.forName(
|
||||||
|
"org.apache.tomcat.util.descriptor.web.ErrorPage", null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e) {
|
||||||
|
}
|
||||||
|
catch (LinkageError e) {
|
||||||
|
}
|
||||||
|
return nativePage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToContext(Context context) {
|
||||||
|
Assert.state(this.nativePage != null,
|
||||||
|
"Neither Tomcat 7 nor 8 detected so no native error page exists");
|
||||||
|
if (ClassUtils.isPresent("org.apache.catalina.deploy.ErrorPage", null)) {
|
||||||
|
org.apache.catalina.deploy.ErrorPage errorPage = (org.apache.catalina.deploy.ErrorPage) this.nativePage;
|
||||||
|
errorPage.setLocation(this.location);
|
||||||
|
errorPage.setErrorCode(this.errorCode);
|
||||||
|
errorPage.setExceptionType(this.exceptionType);
|
||||||
|
context.addErrorPage(errorPage);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
callMethod(this.nativePage, "setLocation", this.location, String.class);
|
||||||
|
callMethod(this.nativePage, "setErrorCode", this.errorCode, int.class);
|
||||||
|
callMethod(this.nativePage, "setExceptionType", this.exceptionType,
|
||||||
|
String.class);
|
||||||
|
callMethod(context, "addErrorPage", this.nativePage,
|
||||||
|
this.nativePage.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void callMethod(Object target, String name, Object value, Class<?> type) {
|
||||||
|
Method method = ReflectionUtils.findMethod(target.getClass(), name, type);
|
||||||
|
ReflectionUtils.invokeMethod(method, target, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user