diff --git a/spring-boot-samples/spring-boot-sample-web-ui/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-web-ui/src/main/resources/application.properties index 166fe14d5d2..9c473745e50 100644 --- a/spring-boot-samples/spring-boot-sample-web-ui/src/main/resources/application.properties +++ b/spring-boot-samples/spring-boot-sample-web-ui/src/main/resources/application.properties @@ -1,2 +1,4 @@ # Allow Thymeleaf templates to be reloaded at dev time -spring.template.cache: false \ No newline at end of file +spring.template.cache: false +server.tomcat.access_log_enabled: true +server.tomcat.basedir: target/tomcat \ No newline at end of file diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/properties/ServerProperties.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/properties/ServerProperties.java index 94e4f4cd287..2efc2085b24 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/properties/ServerProperties.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/properties/ServerProperties.java @@ -21,12 +21,14 @@ import java.net.InetAddress; import javax.validation.constraints.NotNull; +import org.apache.catalina.Context; import org.apache.catalina.valves.AccessLogValve; import org.apache.catalina.valves.RemoteIpValve; import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainerFactory; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer; import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.StringUtils; @@ -107,12 +109,32 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer { private String accessLogPattern; + private boolean accessLogEnabled = false; + private String protocolHeader = "x-forwarded-proto"; private String remoteIpHeader = "x-forwarded-for"; private File basedir; + private int backgroundProcessorDelay = 30; // seconds + + public boolean getAccessLogEnabled() { + return this.accessLogEnabled; + } + + public void setAccessLogEnabled(boolean accessLogEnabled) { + this.accessLogEnabled = accessLogEnabled; + } + + public int getBackgroundProcessorDelay() { + return this.backgroundProcessorDelay; + } + + public void setBackgroundProcessorDelay(int backgroundProcessorDelay) { + this.backgroundProcessorDelay = backgroundProcessorDelay; + } + public File getBasedir() { return this.basedir; } @@ -150,6 +172,13 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer { factory.setBaseDirectory(getBasedir()); } + 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) @@ -160,10 +189,15 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer { factory.addContextValves(valve); } - String accessLogPattern = getAccessLogPattern(); - if (accessLogPattern != null) { + if (this.accessLogEnabled) { AccessLogValve valve = new AccessLogValve(); - valve.setPattern(accessLogPattern); + String accessLogPattern = getAccessLogPattern(); + if (accessLogPattern != null) { + valve.setPattern(accessLogPattern); + } + else { + valve.setPattern("common"); + } valve.setSuffix(".log"); factory.addContextValves(valve); } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatContextCustomizer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatContextCustomizer.java new file mode 100644 index 00000000000..7334fc1bade --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatContextCustomizer.java @@ -0,0 +1,31 @@ +/* + * 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.tomcat; + +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/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 57be0d7c03d..867d66aa78f 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 @@ -72,6 +72,8 @@ public class TomcatEmbeddedServletContainerFactory extends private List contextLifecycleListeners = new ArrayList(); + private List tomcatContextCustomizers = new ArrayList(); + private ResourceLoader resourceLoader; private String protocol = DEFAULT_PROTOCOL; @@ -221,6 +223,9 @@ public class TomcatEmbeddedServletContainerFactory extends context.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); } context.setSessionTimeout(getSessionTimeout()); + for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) { + customizer.customize(context); + } } /** @@ -342,4 +347,37 @@ public class TomcatEmbeddedServletContainerFactory extends 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/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 9b6a6ff9c05..8efee59b819 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 @@ -26,8 +26,6 @@ import org.apache.catalina.startup.Tomcat; import org.junit.Test; import org.mockito.InOrder; import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactoryTests; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer; -import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; @@ -65,6 +63,22 @@ public class TomcatEmbeddedServletContainerFactoryTests extends } } + @Test + public void tomcatCustomizers() throws Exception { + TomcatEmbeddedServletContainerFactory factory = getFactory(); + TomcatContextCustomizer[] listeners = new TomcatContextCustomizer[4]; + for (int i = 0; i < listeners.length; i++) { + listeners[i] = mock(TomcatContextCustomizer.class); + } + factory.setTomcatContextCustomizers(Arrays.asList(listeners[0], listeners[1])); + factory.addContextCustomizers(listeners[2], listeners[3]); + this.container = factory.getEmbeddedServletContainer(); + InOrder ordered = inOrder((Object[]) listeners); + for (TomcatContextCustomizer listener : listeners) { + ordered.verify(listener).customize((Context) anyObject()); + } + } + @Test public void sessionTimeout() throws Exception { TomcatEmbeddedServletContainerFactory factory = getFactory();