Add marker interface for non-embedded servlet container

ErrorPageFilter is itself an EmbeddedServletContainerFactory
but it runs in a non-embedded container. Any component that assumes
the presence of an EmbeddedServletContainerFactory implies we are
running embedded is therefore invalid. WebSocketAutoConfiguration
had that problem.

Fixes gh-551
This commit is contained in:
Dave Syer 2014-03-23 21:42:16 +00:00
parent b824a6ea05
commit 3496f3f9dc
4 changed files with 88 additions and 3 deletions

View File

@ -21,6 +21,8 @@ import javax.servlet.Servlet;
import org.apache.catalina.Context;
import org.apache.catalina.deploy.ApplicationListener;
import org.apache.catalina.startup.Tomcat;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -29,6 +31,7 @@ import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletCont
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.context.web.NonEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
@ -47,6 +50,8 @@ import org.springframework.web.socket.WebSocketHandler;
@AutoConfigureBefore(EmbeddedServletContainerAutoConfiguration.class)
public class WebSocketAutoConfiguration {
private static Log logger = LogFactory.getLog(WebSocketAutoConfiguration.class);
private static final ApplicationListener WS_APPLICATION_LISTENER = new ApplicationListener(
"org.apache.tomcat.websocket.server.WsContextListener", false);
@ -58,10 +63,14 @@ public class WebSocketAutoConfiguration {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof NonEmbeddedServletContainerFactory) {
logger.info("NonEmbeddedServletContainerFactory detected. Websockets support should be native so this normally is not a problem.");
return;
}
if (!(container instanceof TomcatEmbeddedServletContainerFactory)) {
throw new IllegalStateException(
"Websockets are currently only supported in Tomcat (found "
+ container.getClass() + ")");
+ container.getClass() + "). ");
}
((TomcatEmbeddedServletContainerFactory) container)
.addContextCustomizers(new TomcatContextCustomizer() {
@ -77,5 +86,4 @@ public class WebSocketAutoConfiguration {
return customizer;
}
}

View File

@ -53,7 +53,7 @@ import org.springframework.stereotype.Component;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class ErrorPageFilter extends AbstractConfigurableEmbeddedServletContainer implements
Filter {
Filter, NonEmbeddedServletContainerFactory {
// From RequestDispatcher but not referenced to remain compatible with Servlet 2.5

View File

@ -0,0 +1,29 @@
/*
* 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.web;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
/**
* Marker interface for {@link EmbeddedServletContainerFactory} types that are actually
* safe to run in a non-embedded container.
*
* @author Dave Syer
*/
public interface NonEmbeddedServletContainerFactory {
}

View File

@ -22,6 +22,7 @@ import javax.validation.constraints.NotNull;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -33,6 +34,7 @@ import org.springframework.validation.Validator;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
*
@ -51,12 +53,28 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
}
}
@Test
public void testValidationWithSetter() {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "test.foo:spam");
this.context.register(TestConfigurationWithValidatingSetter.class);
try {
this.context.refresh();
fail("Expected exception");
}
catch (BeanCreationException ex) {
BindException bex = (BindException) ex.getRootCause();
assertTrue(1 == bex.getErrorCount());
}
}
@Test
public void testValidationWithoutJSR303() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfigurationWithoutJSR303.class);
try {
this.context.refresh();
fail("Expected exception");
}
catch (BeanCreationException ex) {
BindException bex = (BindException) ex.getRootCause();
@ -70,6 +88,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
this.context.register(TestConfigurationWithJSR303.class);
try {
this.context.refresh();
fail("Expected exception");
}
catch (BeanCreationException ex) {
BindException bex = (BindException) ex.getRootCause();
@ -98,6 +117,35 @@ public class ConfigurationPropertiesBindingPostProcessorTests {
this.context.refresh();
}
@Configuration
@EnableConfigurationProperties
public static class TestConfigurationWithValidatingSetter {
@Bean
public PropertyWithValidatingSetter testProperties() {
return new PropertyWithValidatingSetter();
}
}
@ConfigurationProperties(name = "test")
public static class PropertyWithValidatingSetter {
private String foo;
public String getFoo() {
return this.foo;
}
public void setFoo(String foo) {
this.foo = foo;
if (!foo.equals("bar")) {
throw new IllegalArgumentException("Wrong value for foo");
}
}
}
@Configuration
@EnableConfigurationProperties
public static class TestConfigurationWithoutJSR303 {