diff --git a/pom.xml b/pom.xml index 81994113773..96c26b71387 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,6 @@ spring-boot-starters spring-boot-cli spring-boot-integration-tests - spring-boot-containers/spring-boot-tomcat8 diff --git a/spring-boot-containers/spring-boot-tomcat8/pom.xml b/spring-boot-containers/spring-boot-tomcat8/pom.xml deleted file mode 100644 index e386511fc39..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/pom.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-parent - 0.5.0.BUILD-SNAPSHOT - ../../spring-boot-parent - - spring-boot-tomcat8 - jar - - ${basedir}/../.. - 8.0.0-RC1 - - - - - ${project.groupId} - spring-boot - ${project.version} - - - - org.apache.tomcat.embed - tomcat-embed-core - ${tomcat8.version} - true - - - - - - - maven-jar-plugin - - - - test-jar - - - - - - - diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/ServletContextInitializerLifecycleListener.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/ServletContextInitializerLifecycleListener.java deleted file mode 100644 index 72c2f8d9410..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/ServletContextInitializerLifecycleListener.java +++ /dev/null @@ -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); - } - } - } - } - -} diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatContextCustomizer.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatContextCustomizer.java deleted file mode 100644 index f7a7ebc3939..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatContextCustomizer.java +++ /dev/null @@ -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); - -} diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainer.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainer.java deleted file mode 100644 index 6b8b5a5052e..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainer.java +++ /dev/null @@ -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; - } - -} diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainerFactory.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainerFactory.java deleted file mode 100644 index 3bb0bb0a04c..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedServletContainerFactory.java +++ /dev/null @@ -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. - * - *

- * 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 contextValves = new ArrayList(); - - private List contextLifecycleListeners = new ArrayList(); - - private List tomcatContextCustomizers = new ArrayList(); - - 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 contextValves) { - Assert.notNull(contextValves, "Valves must not be null"); - this.contextValves = new ArrayList(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 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 contextLifecycleListeners) { - Assert.notNull(contextLifecycleListeners, - "ContextLifecycleListeners must not be null"); - this.contextLifecycleListeners = new ArrayList( - 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 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 tomcatContextCustomizers) { - Assert.notNull(this.contextLifecycleListeners, - "TomcatContextCustomizers must not be null"); - this.tomcatContextCustomizers = new ArrayList( - 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 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)); - } - -} diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedWebappClassLoader.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedWebappClassLoader.java deleted file mode 100644 index e091bc7cb2d..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/TomcatEmbeddedWebappClassLoader.java +++ /dev/null @@ -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); - } - } - } - -} diff --git a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/package-info.java b/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/package-info.java deleted file mode 100644 index f1a98a595f8..00000000000 --- a/spring-boot-containers/spring-boot-tomcat8/src/main/java/org/springframework/boot/context/embedded/tomcat8/package-info.java +++ /dev/null @@ -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; - diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 8aa48721708..af55b82e013 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -273,6 +273,11 @@ spring-tx ${spring.version} + + org.springframework + spring-websocket + ${spring.version} + org.springframework spring-web diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index b0d670ebc24..2615b09a9a4 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -26,6 +26,7 @@ spring-boot-sample-traditional spring-boot-sample-web-static spring-boot-sample-web-ui + spring-boot-sample-websocket spring-boot-sample-xml diff --git a/spring-boot-samples/spring-boot-sample-websocket/_om.xml b/spring-boot-samples/spring-boot-sample-websocket/pom.xml similarity index 87% rename from spring-boot-samples/spring-boot-sample-websocket/_om.xml rename to spring-boot-samples/spring-boot-sample-websocket/pom.xml index 8651ffbc395..b897c0e8784 100644 --- a/spring-boot-samples/spring-boot-sample-websocket/_om.xml +++ b/spring-boot-samples/spring-boot-sample-websocket/pom.xml @@ -14,7 +14,8 @@ 1.7 - 8.0-SNAPSHOT + 8.0.0-RC1 + 4.0.0.BUILD-SNAPSHOT org.springframework.boot.samples.websocket.config.ApplicationConfiguration @@ -23,7 +24,10 @@ org.springframework.boot spring-boot-starter-websocket - ${spring.boot.version} + + + org.springframework.boot + spring-boot-starter-actuator diff --git a/spring-boot-samples/spring-boot-sample-websocket/src/main/java/org/springframework/boot/samples/websocket/config/SampleWebSocketsApplication.java b/spring-boot-samples/spring-boot-sample-websocket/src/main/java/org/springframework/boot/samples/websocket/config/SampleWebSocketsApplication.java index f8f2aad3a56..6269a7e005a 100644 --- a/spring-boot-samples/spring-boot-sample-websocket/src/main/java/org/springframework/boot/samples/websocket/config/SampleWebSocketsApplication.java +++ b/spring-boot-samples/spring-boot-sample-websocket/src/main/java/org/springframework/boot/samples/websocket/config/SampleWebSocketsApplication.java @@ -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.EchoWebSocketHandler; 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.Configuration; 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.socket.WebSocketHandler; 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.support.DefaultSockJsService; -import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler; +import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService; import org.springframework.web.socket.support.PerConnectionWebSocketHandler; @Configuration -public class SampleWebSocketsApplication extends SpringServletInitializer { +public class SampleWebSocketsApplication extends SpringBootServletInitializer { @Override protected Class[] getConfigClasses() { diff --git a/spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/StandardClientApp.java b/spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/SampleWebSocketsApplicationTests.java similarity index 70% rename from spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/StandardClientApp.java rename to spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/SampleWebSocketsApplicationTests.java index 76c5dfd5130..44113d7b559 100644 --- a/spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/StandardClientApp.java +++ b/spring-boot-samples/spring-boot-sample-websocket/src/test/java/org/springframework/boot/samples/websocket/echo/SampleWebSocketsApplicationTests.java @@ -17,28 +17,59 @@ package org.springframework.boot.samples.websocket.echo; import static org.junit.Assert.assertEquals; +import java.util.concurrent.Callable; 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.LogFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.samples.websocket.client.GreetingService; import org.springframework.boot.samples.websocket.client.SimpleClientWebSocketHandler; 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.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.client.WebSocketConnectionManager; 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 ConfigurableApplicationContext context; + + @BeforeClass + public static void start() throws Exception { + Future future = Executors + .newSingleThreadExecutor().submit( + new Callable() { + @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 public void runAndWait() throws Exception { ApplicationContext context = SpringApplication.run(ClientConfiguration.class, "--spring.main.web_environment=false"); diff --git a/spring-boot-starters/spring-boot-starter-parent/pom.xml b/spring-boot-starters/spring-boot-starter-parent/pom.xml index 7fdba1bddf2..151dbe0bfd0 100644 --- a/spring-boot-starters/spring-boot-starter-parent/pom.xml +++ b/spring-boot-starters/spring-boot-starter-parent/pom.xml @@ -2,7 +2,7 @@ + checkout of this file, be sure to modify 'spring-boot-starter-parent/src/main/parent/pom.xml'. --> @@ -88,6 +88,11 @@ spring-boot-starter-security ${spring.boot.version} + + org.springframework.boot + spring-boot-starter-websocket + ${spring.boot.version} + diff --git a/spring-boot-starters/spring-boot-starter-parent/src/main/maven/pom.xml b/spring-boot-starters/spring-boot-starter-parent/src/main/maven/pom.xml index 90b5201ab95..6aaccd8048c 100644 --- a/spring-boot-starters/spring-boot-starter-parent/src/main/maven/pom.xml +++ b/spring-boot-starters/spring-boot-starter-parent/src/main/maven/pom.xml @@ -2,7 +2,7 @@ + checkout of this file, be sure to modify 'spring-boot-starter-parent/src/main/parent/pom.xml'. --> @@ -88,6 +88,11 @@ spring-boot-starter-security ${spring.boot.version} + + org.springframework.boot + spring-boot-starter-websocket + ${spring.boot.version} + diff --git a/spring-boot-starters/spring-boot-starter-websocket/pom.xml b/spring-boot-starters/spring-boot-starter-websocket/pom.xml index 2181209b16e..2f4121cb362 100644 --- a/spring-boot-starters/spring-boot-starter-websocket/pom.xml +++ b/spring-boot-starters/spring-boot-starter-websocket/pom.xml @@ -11,7 +11,7 @@ jar ${basedir}/../.. - 8.0-SNAPSHOT + 8.0.0-RC1 @@ -35,14 +35,13 @@ ${project.groupId} - spring-boot-up-tomcat + spring-boot-starter-tomcat org.springframework spring-websocket - ${spring.version} org.apache.tomcat.embed @@ -53,16 +52,4 @@ tomcat-embed-logging-juli - - - tomcat-snapshots - https://repository.apache.org/content/repositories/snapshots - - true - - - false - - - diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java index 867d66aa78f..dec9443e550 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java @@ -18,6 +18,7 @@ package org.springframework.boot.context.embedded.tomcat; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; 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.FixContextListener; import org.apache.coyote.AbstractProtocol; +import org.springframework.beans.BeanUtils; import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.EmbeddedServletContainer; 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.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; /** * {@link EmbeddedServletContainerFactory} that can be used to create @@ -213,11 +216,7 @@ public class TomcatEmbeddedServletContainerFactory extends context.getPipeline().addValve(valve); } for (ErrorPage errorPage : getErrorPages()) { - org.apache.catalina.deploy.ErrorPage tomcatPage = new org.apache.catalina.deploy.ErrorPage(); - tomcatPage.setLocation(errorPage.getPath()); - tomcatPage.setExceptionType(errorPage.getExceptionName()); - tomcatPage.setErrorCode(errorPage.getStatusCode()); - context.addErrorPage(tomcatPage); + new TomcatErrorPage(errorPage).addToContext(context); } for (MimeMappings.Mapping mapping : getMimeMappings()) { context.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); @@ -380,4 +379,67 @@ public class TomcatEmbeddedServletContainerFactory extends 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); + } + + } + }