Allow JspServlet's init parameters to be configured via the environment

This commit adds support for configuring the JSP servlet’s init
parameters via the environment using server.jsp-servlet.init-parameters.*.
As part of this change the configuration of registerJspServlet and
jspServletClassName have been moved onto a new type, JspServlet, and the
existing setters on ConfigurableEmbeddedServletContainer have been 
deprecated. In addition to providing a model for configuring the JSP
servlet that’s consistent with the model for other configuration (SSL,
for example), this change also means that the class name and whether or
not the servlet is registered at all can now also be configured via the
environment.

Closes gh-2825
This commit is contained in:
Andy Wilkinson 2015-04-16 10:37:52 +01:00
parent 63a7b24d27
commit 18453c0eb0
11 changed files with 216 additions and 39 deletions

View File

@ -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<String, String> 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)

View File

@ -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<ServletContextInitializer> initializers = new ArrayList<ServletContextInitializer>();
@ -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());
}
}

View File

@ -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
* <code>org.apache.jasper.servlet.JspServlet</code>.
* @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);
}

View File

@ -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<String, String> initParameters = new HashMap<String, String>();
/**
* 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<String, String> getInitParameters() {
return this.initParameters;
}
public void setInitParameters(Map<String, String> initParameters) {
this.initParameters = initParameters;
}
public boolean getRegistered() {
return this.registered;
}
public void setRegistered(boolean registered) {
this.registered = registered;
}
}

View File

@ -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.

View File

@ -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<String, String> initParameter : getJspServlet().getInitParameters()
.entrySet()) {
jspServlet.addInitParameter(initParameter.getKey(), initParameter.getValue());
}
jspServlet.setLoadOnStartup(3);
context.addChild(jspServlet);
context.addServletMapping("*.jsp", "jsp");

View File

@ -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.
*/

View File

@ -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");
}

View File

@ -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<String, String> initParameters = new HashMap<String, String>();
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");
}
}

View File

@ -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<String, String> initParameters = new HashMap<String, String>();
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];

View File

@ -149,4 +149,9 @@ public class UndertowEmbeddedServletContainerFactoryTests extends
assertEquals("/", contextPath.get());
}
@Override
protected Object getJspServlet() {
return null; // Undertow does not support JSPs
}
}