diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 17a9c0acc1b..fe4463281cf 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -36,6 +36,7 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomi import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer; +import org.springframework.boot.context.embedded.JspServlet; import org.springframework.boot.context.embedded.Ssl; import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; @@ -92,6 +93,9 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord private final Undertow undertow = new Undertow(); + @NestedConfigurationProperty + private JspServlet jspServlet; + /** * ServletContext parameters. */ @@ -110,6 +114,10 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord return this.undertow; } + public JspServlet jspServlet() { + return this.jspServlet; + } + public String getContextPath() { return this.contextPath; } @@ -182,6 +190,14 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord this.ssl = ssl; } + public JspServlet getJspServlet() { + return this.jspServlet; + } + + public void setJspServlet(JspServlet jspServlet) { + this.jspServlet = jspServlet; + } + public Map getContextParameters() { return this.contextParameters; } @@ -207,6 +223,9 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord if (getSsl() != null) { container.setSsl(getSsl()); } + if (getJspServlet() != null) { + container.setJspServlet(getJspServlet()); + } if (container instanceof TomcatEmbeddedServletContainerFactory) { getTomcat() .customizeTomcat((TomcatEmbeddedServletContainerFactory) container); @@ -436,6 +455,13 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer, Ord } }); + factory.addContextCustomizers(new TomcatContextCustomizer() { + @Override + public void customize(Context context) { + context.setBackgroundProcessorDelay(Tomcat.this.backgroundProcessorDelay); + } + }); + String remoteIpHeader = getRemoteIpHeader(); String protocolHeader = getProtocolHeader(); if (StringUtils.hasText(remoteIpHeader) diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java index 22f4fc4a2de..702098db17c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2015 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. @@ -26,12 +26,14 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * Abstract base class for {@link ConfigurableEmbeddedServletContainer} implementations. * * @author Phillip Webb * @author Dave Syer + * @author Andy Wilkinson * @see AbstractEmbeddedServletContainerFactory */ public abstract class AbstractConfigurableEmbeddedServletContainer implements @@ -44,10 +46,6 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements private boolean registerDefaultServlet = true; - private boolean registerJspServlet = true; - - private String jspServletClassName = "org.apache.jasper.servlet.JspServlet"; - private int port = 8080; private List initializers = new ArrayList(); @@ -64,6 +62,8 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements private Ssl ssl; + private JspServlet jspServlet = new JspServlet(); + /** * Create a new {@link AbstractConfigurableEmbeddedServletContainer} instance. */ @@ -228,18 +228,10 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements this.registerDefaultServlet = registerDefaultServlet; } - /** - * Flag to indicate that the JSP servlet should be registered if available on the - * classpath. - * @return true if the JSP servlet is to be registered - */ - public boolean isRegisterJspServlet() { - return this.registerJspServlet; - } - @Override public void setRegisterJspServlet(boolean registerJspServlet) { - this.registerJspServlet = registerJspServlet; + Assert.notNull(this.jspServlet); + this.jspServlet.setRegistered(registerJspServlet); } /** @@ -261,14 +253,17 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements @Override public void setJspServletClassName(String jspServletClassName) { - this.jspServletClassName = jspServletClassName; + Assert.notNull(this.jspServlet); + this.jspServlet.setClassName(jspServletClassName); } - /** - * @return the JSP servlet class name - */ - protected String getJspServletClassName() { - return this.jspServletClassName; + @Override + public void setJspServlet(JspServlet jspServlet) { + this.jspServlet = jspServlet; + } + + public JspServlet getJspServlet() { + return this.jspServlet; } /** @@ -287,4 +282,16 @@ public abstract class AbstractConfigurableEmbeddedServletContainer implements .toArray(new ServletContextInitializer[mergedInitializers.size()]); } + /** + * Returns whether or not he JSP servlet should be registered with the embedded + * container. + * @return {@code true} if the container should be registered, otherwise {@code false} + */ + protected boolean shouldRegisterJspServlet() { + return this.jspServlet != null + && this.jspServlet.getRegistered() + && ClassUtils.isPresent(this.jspServlet.getClassName(), getClass() + .getClassLoader()); + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java index 380df42f9a8..5b5f7d9187b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java @@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit; * {@link EmbeddedServletContainerFactory}. * * @author Dave Syer + * @author Andy Wilkinson * @see EmbeddedServletContainerFactory * @see EmbeddedServletContainerCustomizer */ @@ -76,7 +77,11 @@ public interface ConfigurableEmbeddedServletContainer { * Tomcat and Jetty use Jasper for their JSP implementation the default is * org.apache.jasper.servlet.JspServlet. * @param jspServletClassName the class name for the JSP servlet if used + * @deprecated in 1.3.0 in favor of {@link JspServlet#setClassName(String)} + * @see #setJspServlet + * @see JspServlet#setClassName(String) */ + @Deprecated void setJspServletClassName(String jspServletClassName); /** @@ -84,7 +89,11 @@ public interface ConfigurableEmbeddedServletContainer { * {@code true} so that files from the {@link #setDocumentRoot(File) document root} * will be served. * @param registerJspServlet if the JSP servlet should be registered + * @deprecated in 1.3.0 in favor of {@link JspServlet#setRegistered(boolean)} + * @see #setJspServlet + * @see JspServlet#setRegistered(boolean) */ + @Deprecated void setRegisterJspServlet(boolean registerJspServlet); /** @@ -146,4 +155,10 @@ public interface ConfigurableEmbeddedServletContainer { */ void setSsl(Ssl ssl); + /** + * Sets the configuration that will be applied to the container's JSP servlet + * @param jspServlet the JSP servlet configuration + */ + void setJspServlet(JspServlet jspServlet); + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/JspServlet.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/JspServlet.java new file mode 100644 index 00000000000..b2ce336b71d --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/JspServlet.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2015 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; + +import java.util.HashMap; +import java.util.Map; + +/** + * Configuration for the container's JSP servlet. + * + * @author Andy Wilkinson + * @since 1.3.0 + */ +public class JspServlet { + + /** + * The class name of the servlet to use for JSPs. If registered is true and this class + * is on the classpath then it will be registered. Since both Tomcat and Jetty use + * Jasper for their JSP implementation the default is + * org.apache.jasper.servlet.JspServlet. + */ + private String className = "org.apache.jasper.servlet.JspServlet"; + + /** + * Init parameters use to configure the JSP servlet. + */ + private Map initParameters = new HashMap(); + + /** + * Whether or not the JSP servlet should be registered with the embedded servlet + * container. + */ + private boolean registered = true; + + public String getClassName() { + return this.className; + } + + public void setClassName(String className) { + this.className = className; + } + + public Map getInitParameters() { + return this.initParameters; + } + + public void setInitParameters(Map initParameters) { + this.initParameters = initParameters; + } + + public boolean getRegistered() { + return this.registered; + } + + public void setRegistered(boolean registered) { + this.registered = registered; + } + +} \ No newline at end of file diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java index 4aa6ebc2e5b..498bb5f387d 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java @@ -235,9 +235,7 @@ public class JettyEmbeddedServletContainerFactory extends if (isRegisterDefaultServlet()) { addDefaultServlet(context); } - if (isRegisterJspServlet() - && ClassUtils.isPresent(getJspServletClassName(), getClass() - .getClassLoader())) { + if (shouldRegisterJspServlet()) { addJspServlet(context); } ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); @@ -297,8 +295,9 @@ public class JettyEmbeddedServletContainerFactory extends Assert.notNull(context, "Context must not be null"); ServletHolder holder = new ServletHolder(); holder.setName("jsp"); - holder.setClassName(getJspServletClassName()); + holder.setClassName(getJspServlet().getClassName()); holder.setInitParameter("fork", "false"); + holder.setInitParameters(getJspServlet().getInitParameters()); holder.setInitOrder(3); context.getServletHandler().addServlet(holder); ServletMapping mapping = new ServletMapping(); @@ -378,7 +377,7 @@ public class JettyEmbeddedServletContainerFactory extends } /** - * Factory method called to create the {@link JettyEmbeddedServletContainer}. + * Factory method called to create the {@link JettyEmbeddedServletContainer} . * Subclasses can override this method to return a different * {@link JettyEmbeddedServletContainer} or apply additional processing to the Jetty * server. 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 aa43dfd798f..9288b4e1d4b 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 @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -173,9 +174,7 @@ public class TomcatEmbeddedServletContainerFactory extends if (isRegisterDefaultServlet()) { addDefaultServlet(context); } - if (isRegisterJspServlet() - && ClassUtils.isPresent(getJspServletClassName(), getClass() - .getClassLoader())) { + if (shouldRegisterJspServlet()) { addJspServlet(context); addJasperInitializer(context); context.addLifecycleListener(new StoreMergedWebXmlListener()); @@ -202,8 +201,12 @@ public class TomcatEmbeddedServletContainerFactory extends private void addJspServlet(Context context) { Wrapper jspServlet = context.createWrapper(); jspServlet.setName("jsp"); - jspServlet.setServletClass(getJspServletClassName()); + jspServlet.setServletClass(getJspServlet().getClassName()); jspServlet.addInitParameter("fork", "false"); + for (Entry initParameter : getJspServlet().getInitParameters() + .entrySet()) { + jspServlet.addInitParameter(initParameter.getKey(), initParameter.getValue()); + } jspServlet.setLoadOnStartup(3); context.addChild(jspServlet); context.addServletMapping("*.jsp", "jsp"); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java index 099ba332388..46d3484225e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java @@ -110,7 +110,7 @@ public class UndertowEmbeddedServletContainerFactory extends */ public UndertowEmbeddedServletContainerFactory() { super(); - setRegisterJspServlet(false); + getJspServlet().setRegistered(false); } /** @@ -120,7 +120,7 @@ public class UndertowEmbeddedServletContainerFactory extends */ public UndertowEmbeddedServletContainerFactory(int port) { super(port); - setRegisterJspServlet(false); + getJspServlet().setRegistered(false); } /** @@ -131,7 +131,7 @@ public class UndertowEmbeddedServletContainerFactory extends */ public UndertowEmbeddedServletContainerFactory(String contextPath, int port) { super(contextPath, port); - setRegisterJspServlet(false); + getJspServlet().setRegistered(false); } /** @@ -441,12 +441,6 @@ public class UndertowEmbeddedServletContainerFactory extends this.directBuffers = directBuffers; } - @Override - public void setRegisterJspServlet(boolean registerJspServlet) { - Assert.isTrue(!registerJspServlet, "Undertow does not support JSPs"); - super.setRegisterJspServlet(registerJspServlet); - } - /** * Undertow {@link ResourceManager} for JAR resources. */ diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java index fd6bd4d54c0..49c508958cf 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java @@ -60,8 +60,10 @@ import org.springframework.util.concurrent.ListenableFuture; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.lessThan; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyObject; @@ -477,6 +479,14 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { equalTo("test")); } + @Test + public void disableJspServletRegistration() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + factory.getJspServlet().setRegistered(false); + this.container = factory.getEmbeddedServletContainer(); + assertThat(getJspServlet(), is(nullValue())); + } + private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore) { return getSsl(clientAuth, keyPassword, keyStore, null); } @@ -567,6 +577,8 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { protected abstract AbstractEmbeddedServletContainerFactory getFactory(); + protected abstract Object getJspServlet(); + protected ServletContextInitializer exampleServletRegistration() { return new ServletRegistrationBean(new ExampleServlet(), "/hello"); } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java index 79d74a8a04f..9e4e8e184a8 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java @@ -17,6 +17,8 @@ package org.springframework.boot.context.embedded.jetty; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.server.Handler; @@ -25,6 +27,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.Test; @@ -33,6 +36,7 @@ import org.springframework.boot.context.embedded.AbstractEmbeddedServletContaine import org.springframework.boot.context.embedded.Ssl; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.inOrder; @@ -159,4 +163,21 @@ public class JettyEmbeddedServletContainerFactoryTests extends testBasicSslWithKeyStore("classpath:test.jks"); } + @Test + public void jspServletInitParameters() { + JettyEmbeddedServletContainerFactory factory = getFactory(); + Map initParameters = new HashMap(); + initParameters.put("a", "alpha"); + factory.getJspServlet().setInitParameters(initParameters); + this.container = factory.getEmbeddedServletContainer(); + assertThat(getJspServlet().getInitParameters(), is(equalTo(initParameters))); + } + + @Override + protected ServletHolder getJspServlet() { + WebAppContext context = (WebAppContext) ((JettyEmbeddedServletContainer) this.container) + .getServer().getHandler(); + return context.getServletHandler().getServlet("jsp"); + } + } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java index b2bbcb4e110..bd13656bca8 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java @@ -21,15 +21,18 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.apache.catalina.Container; import org.apache.catalina.Context; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.LifecycleState; import org.apache.catalina.Service; import org.apache.catalina.Valve; +import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.coyote.http11.AbstractHttp11JsseProtocol; @@ -40,6 +43,7 @@ import org.springframework.boot.context.embedded.Ssl; import org.springframework.util.SocketUtils; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; @@ -310,6 +314,24 @@ public class TomcatEmbeddedServletContainerFactoryTests extends } + @Test + public void jspServletInitParameters() { + Map initParameters = new HashMap(); + initParameters.put("a", "alpha"); + TomcatEmbeddedServletContainerFactory factory = getFactory(); + factory.getJspServlet().setInitParameters(initParameters); + this.container = factory.getEmbeddedServletContainer(); + Wrapper jspServlet = getJspServlet(); + assertThat(jspServlet.findInitParameter("a"), is(equalTo("alpha"))); + } + + @Override + protected Wrapper getJspServlet() { + Container context = ((TomcatEmbeddedServletContainer) this.container).getTomcat() + .getHost().findChildren()[0]; + return (Wrapper) context.findChild("jsp"); + } + private void assertTimeout(TomcatEmbeddedServletContainerFactory factory, int expected) { Tomcat tomcat = getTomcat(factory); Context context = (Context) tomcat.getHost().findChildren()[0]; diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java index ccd81aea0a2..df8d772a0c4 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java @@ -149,4 +149,9 @@ public class UndertowEmbeddedServletContainerFactoryTests extends assertEquals("/", contextPath.get()); } + @Override + protected Object getJspServlet() { + return null; // Undertow does not support JSPs + } + }