Merge branch 'undertow'
This commit is contained in:
commit
7392e2b4d2
|
|
@ -8,6 +8,7 @@
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
|
.metadata
|
||||||
bin
|
bin
|
||||||
build
|
build
|
||||||
lib/
|
lib/
|
||||||
|
|
@ -28,4 +29,3 @@ overridedb.*
|
||||||
*.iws
|
*.iws
|
||||||
.idea
|
.idea
|
||||||
*.jar
|
*.jar
|
||||||
.DS_Store
|
|
||||||
|
|
@ -160,6 +160,11 @@
|
||||||
<artifactId>jetty-webapp</artifactId>
|
<artifactId>jetty-webapp</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-servlet</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.freemarker</groupId>
|
<groupId>org.freemarker</groupId>
|
||||||
<artifactId>freemarker</artifactId>
|
<artifactId>freemarker</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.web;
|
package org.springframework.boot.autoconfigure.web;
|
||||||
|
|
||||||
|
import io.undertow.Undertow;
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
import javax.servlet.Servlet;
|
||||||
|
|
||||||
import org.apache.catalina.startup.Tomcat;
|
import org.apache.catalina.startup.Tomcat;
|
||||||
|
|
@ -37,6 +39,7 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomi
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
@ -51,6 +54,7 @@ import org.springframework.util.ObjectUtils;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Ivan Sopov
|
||||||
*/
|
*/
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
@ -88,6 +92,21 @@ public class EmbeddedServletContainerAutoConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nested configuration if Undertow is being used.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ Servlet.class, Undertow.class })
|
||||||
|
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
|
||||||
|
public static class EmbeddedUndertow {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
|
||||||
|
return new UndertowEmbeddedServletContainerFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link EmbeddedServletContainerCustomizerBeanPostProcessor}. Registered
|
* Registers a {@link EmbeddedServletContainerCustomizerBeanPostProcessor}. Registered
|
||||||
* via {@link ImportBeanDefinitionRegistrar} for early registration.
|
* via {@link ImportBeanDefinitionRegistrar} for early registration.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import org.springframework.boot.context.embedded.Ssl;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
|
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
|
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
@ -52,6 +53,7 @@ import org.springframework.util.StringUtils;
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
|
* @author Ivan Sopov
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = false)
|
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = false)
|
||||||
public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
||||||
|
|
@ -72,12 +74,18 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
||||||
|
|
||||||
private final Tomcat tomcat = new Tomcat();
|
private final Tomcat tomcat = new Tomcat();
|
||||||
|
|
||||||
|
private final Undertow undertow = new Undertow();
|
||||||
|
|
||||||
private final Map<String, String> contextParameters = new HashMap<String, String>();
|
private final Map<String, String> contextParameters = new HashMap<String, String>();
|
||||||
|
|
||||||
public Tomcat getTomcat() {
|
public Tomcat getTomcat() {
|
||||||
return this.tomcat;
|
return this.tomcat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Undertow getUndertow() {
|
||||||
|
return this.undertow;
|
||||||
|
}
|
||||||
|
|
||||||
public String getContextPath() {
|
public String getContextPath() {
|
||||||
return this.contextPath;
|
return this.contextPath;
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +187,10 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
||||||
getTomcat()
|
getTomcat()
|
||||||
.customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
|
.customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
|
||||||
}
|
}
|
||||||
|
if (container instanceof UndertowEmbeddedServletContainerFactory) {
|
||||||
|
getUndertow().customizeUndertow(
|
||||||
|
(UndertowEmbeddedServletContainerFactory) container);
|
||||||
|
}
|
||||||
container.addInitializers(new InitParameterConfiguringServletContextInitializer(
|
container.addInitializers(new InitParameterConfiguringServletContextInitializer(
|
||||||
getContextParameters()));
|
getContextParameters()));
|
||||||
}
|
}
|
||||||
|
|
@ -396,4 +407,66 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Undertow {
|
||||||
|
|
||||||
|
private Integer bufferSize;
|
||||||
|
|
||||||
|
private Integer buffersPerRegion;
|
||||||
|
|
||||||
|
private Integer ioThreads;
|
||||||
|
|
||||||
|
private Integer workerThreads;
|
||||||
|
|
||||||
|
private Boolean directBuffers;
|
||||||
|
|
||||||
|
public Integer getBufferSize() {
|
||||||
|
return this.bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBufferSize(Integer bufferSize) {
|
||||||
|
this.bufferSize = bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBuffersPerRegion() {
|
||||||
|
return this.buffersPerRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBuffersPerRegion(Integer buffersPerRegion) {
|
||||||
|
this.buffersPerRegion = buffersPerRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getIoThreads() {
|
||||||
|
return this.ioThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIoThreads(Integer ioThreads) {
|
||||||
|
this.ioThreads = ioThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getWorkerThreads() {
|
||||||
|
return this.workerThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorkerThreads(Integer workerThreads) {
|
||||||
|
this.workerThreads = workerThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDirectBuffers() {
|
||||||
|
return this.directBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectBuffers(Boolean directBuffers) {
|
||||||
|
this.directBuffers = directBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void customizeUndertow(UndertowEmbeddedServletContainerFactory factory) {
|
||||||
|
factory.setBufferSize(this.bufferSize);
|
||||||
|
factory.setBuffersPerRegion(this.buffersPerRegion);
|
||||||
|
factory.setIoThreads(this.ioThreads);
|
||||||
|
factory.setWorkerThreads(this.workerThreads);
|
||||||
|
factory.setDirectBuffers(this.directBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.web;
|
package org.springframework.boot.autoconfigure.web;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
@ -25,10 +27,16 @@ import org.junit.rules.ExpectedException;
|
||||||
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||||
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.env.PropertySource;
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
@ -55,6 +63,7 @@ import static org.mockito.Mockito.mock;
|
||||||
* @author Greg Turnquist
|
* @author Greg Turnquist
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
* @author Josh Long
|
* @author Josh Long
|
||||||
|
* @author Ivan Sopov
|
||||||
*/
|
*/
|
||||||
public class MultipartAutoConfigurationTests {
|
public class MultipartAutoConfigurationTests {
|
||||||
|
|
||||||
|
|
@ -71,10 +80,11 @@ public class MultipartAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containerWithNothing() {
|
public void containerWithNothing() throws Exception {
|
||||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
ContainerWithNothing.class, BaseConfiguration.class);
|
ContainerWithNothing.class, BaseConfiguration.class);
|
||||||
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
|
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
|
||||||
|
verify404();
|
||||||
assertNotNull(servlet.getMultipartResolver());
|
assertNotNull(servlet.getMultipartResolver());
|
||||||
assertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)
|
assertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)
|
||||||
.size(), equalTo(1));
|
.size(), equalTo(1));
|
||||||
|
|
@ -112,6 +122,32 @@ public class MultipartAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void containerWithNoMultipartUndertowConfiguration() {
|
||||||
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
|
ContainerWithNoMultipartUndertow.class, BaseConfiguration.class);
|
||||||
|
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
|
||||||
|
verifyServletWorks();
|
||||||
|
assertNotNull(servlet.getMultipartResolver());
|
||||||
|
assertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)
|
||||||
|
.size(), equalTo(1));
|
||||||
|
assertThat(this.context.getBeansOfType(MultipartResolver.class).size(),
|
||||||
|
equalTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class ContainerWithNoMultipartUndertow {
|
||||||
|
@Bean
|
||||||
|
UndertowEmbeddedServletContainerFactory containerFactory() {
|
||||||
|
return new UndertowEmbeddedServletContainerFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebController controller() {
|
||||||
|
return new WebController();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containerWithNoMultipartTomcatConfiguration() {
|
public void containerWithNoMultipartTomcatConfiguration() {
|
||||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
|
|
@ -148,6 +184,16 @@ public class MultipartAutoConfigurationTests {
|
||||||
verifyServletWorks();
|
verifyServletWorks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void containerWithAutomatedMultipartUndertowConfiguration() {
|
||||||
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
|
ContainerWithEverythingUndertow.class, BaseConfiguration.class);
|
||||||
|
this.context.getBean(MultipartConfigElement.class);
|
||||||
|
verifyServletWorks();
|
||||||
|
assertSame(this.context.getBean(DispatcherServlet.class).getMultipartResolver(),
|
||||||
|
this.context.getBean(StandardServletMultipartResolver.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containerWithMultipartConfigDisabled() {
|
public void containerWithMultipartConfigDisabled() {
|
||||||
|
|
||||||
|
|
@ -178,6 +224,16 @@ public class MultipartAutoConfigurationTests {
|
||||||
not(instanceOf(StandardServletMultipartResolver.class)));
|
not(instanceOf(StandardServletMultipartResolver.class)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verify404() throws Exception {
|
||||||
|
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||||
|
ClientHttpRequest request = requestFactory.createRequest(new URI(
|
||||||
|
"http://localhost:"
|
||||||
|
+ this.context.getEmbeddedServletContainer().getPort() + "/"),
|
||||||
|
HttpMethod.GET);
|
||||||
|
ClientHttpResponse response = request.execute();
|
||||||
|
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyServletWorks() {
|
private void verifyServletWorks() {
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
assertEquals("Hello", restTemplate.getForObject("http://localhost:"
|
assertEquals("Hello", restTemplate.getForObject("http://localhost:"
|
||||||
|
|
@ -256,6 +312,27 @@ public class MultipartAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
public static class ContainerWithEverythingUndertow {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MultipartConfigElement multipartConfigElement() {
|
||||||
|
return new MultipartConfigElement("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
UndertowEmbeddedServletContainerFactory containerFactory() {
|
||||||
|
return new UndertowEmbeddedServletContainerFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
WebController webController() {
|
||||||
|
return new WebController();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static class ContainerWithCustomMultipartResolver {
|
public static class ContainerWithCustomMultipartResolver {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomi
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||||
import org.springframework.context.ApplicationContextException;
|
import org.springframework.context.ApplicationContextException;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -46,6 +47,7 @@ import static org.mockito.Mockito.verify;
|
||||||
* Tests for {@link ServerPropertiesAutoConfiguration}.
|
* Tests for {@link ServerPropertiesAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Ivan Sopov
|
||||||
*/
|
*/
|
||||||
public class ServerPropertiesAutoConfigurationTests {
|
public class ServerPropertiesAutoConfigurationTests {
|
||||||
|
|
||||||
|
|
@ -97,9 +99,9 @@ public class ServerPropertiesAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customizeWithContainerFactory() throws Exception {
|
public void customizeWithJettyContainerFactory() throws Exception {
|
||||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||||
this.context.register(CustomContainerConfig.class,
|
this.context.register(CustomJettyContainerConfig.class,
|
||||||
ServerPropertiesAutoConfiguration.class,
|
ServerPropertiesAutoConfiguration.class,
|
||||||
PropertyPlaceholderAutoConfiguration.class);
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
this.context.refresh();
|
this.context.refresh();
|
||||||
|
|
@ -112,6 +114,20 @@ public class ServerPropertiesAutoConfigurationTests {
|
||||||
assertEquals(3000, containerFactory.getPort());
|
assertEquals(3000, containerFactory.getPort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customizeWithUndertowContainerFactory() throws Exception {
|
||||||
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||||
|
this.context.register(CustomUndertowContainerConfig.class,
|
||||||
|
ServerPropertiesAutoConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
|
this.context.refresh();
|
||||||
|
containerFactory = this.context
|
||||||
|
.getBean(AbstractEmbeddedServletContainerFactory.class);
|
||||||
|
ServerProperties server = this.context.getBean(ServerProperties.class);
|
||||||
|
assertNotNull(server);
|
||||||
|
assertEquals(3000, containerFactory.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customizeTomcatWithCustomizer() throws Exception {
|
public void customizeTomcatWithCustomizer() throws Exception {
|
||||||
containerFactory = mock(TomcatEmbeddedServletContainerFactory.class);
|
containerFactory = mock(TomcatEmbeddedServletContainerFactory.class);
|
||||||
|
|
@ -154,7 +170,7 @@ public class ServerPropertiesAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
protected static class CustomContainerConfig {
|
protected static class CustomJettyContainerConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public EmbeddedServletContainerFactory containerFactory() {
|
public EmbeddedServletContainerFactory containerFactory() {
|
||||||
|
|
@ -170,6 +186,23 @@ public class ServerPropertiesAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class CustomUndertowContainerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedServletContainerFactory containerFactory() {
|
||||||
|
UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
|
||||||
|
factory.setPort(3000);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContainerCustomizerBeanPostProcessor() {
|
||||||
|
return new EmbeddedServletContainerCustomizerBeanPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
protected static class CustomizeConfig {
|
protected static class CustomizeConfig {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@
|
||||||
<thymeleaf-layout-dialect.version>1.2.7</thymeleaf-layout-dialect.version>
|
<thymeleaf-layout-dialect.version>1.2.7</thymeleaf-layout-dialect.version>
|
||||||
<thymeleaf-extras-data-attribute.version>1.3</thymeleaf-extras-data-attribute.version>
|
<thymeleaf-extras-data-attribute.version>1.3</thymeleaf-extras-data-attribute.version>
|
||||||
<tomcat.version>8.0.15</tomcat.version>
|
<tomcat.version>8.0.15</tomcat.version>
|
||||||
|
<undertow.version>1.1.0.Final</undertow.version>
|
||||||
<velocity.version>1.7</velocity.version>
|
<velocity.version>1.7</velocity.version>
|
||||||
<velocity-tools.version>2.0</velocity-tools.version>
|
<velocity-tools.version>2.0</velocity-tools.version>
|
||||||
<wsdl4j.version>1.6.3</wsdl4j.version>
|
<wsdl4j.version>1.6.3</wsdl4j.version>
|
||||||
|
|
@ -289,6 +290,11 @@
|
||||||
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
<artifactId>spring-boot-starter-jta-bitronix</artifactId>
|
||||||
<version>1.2.0.BUILD-SNAPSHOT</version>
|
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-log4j</artifactId>
|
<artifactId>spring-boot-starter-log4j</artifactId>
|
||||||
|
|
@ -534,6 +540,16 @@
|
||||||
<artifactId>metrics-servlets</artifactId>
|
<artifactId>metrics-servlets</artifactId>
|
||||||
<version>${dropwizard-metrics.version}</version>
|
<version>${dropwizard-metrics.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-core</artifactId>
|
||||||
|
<version>${undertow.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-servlet</artifactId>
|
||||||
|
<version>${undertow.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.cache</groupId>
|
<groupId>javax.cache</groupId>
|
||||||
<artifactId>cache-api</artifactId>
|
<artifactId>cache-api</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -158,8 +158,8 @@ for our starter REST application:
|
||||||
|
|
||||||
Spring Boot makes `-D` arguments available as properties accessible from a Spring
|
Spring Boot makes `-D` arguments available as properties accessible from a Spring
|
||||||
`Environment` instance. The `server.port` configuration property is fed to the embedded
|
`Environment` instance. The `server.port` configuration property is fed to the embedded
|
||||||
Tomcat or Jetty instance which then uses it when it starts up. The `$PORT` environment
|
Tomcat, Jetty or Undertow instance which then uses it when it starts up. The `$PORT`
|
||||||
variable is assigned to us by the Heroku PaaS.
|
environment variable is assigned to us by the Heroku PaaS.
|
||||||
|
|
||||||
Heroku by default will use Java 1.6. This is fine as long as your Maven or Gradle build
|
Heroku by default will use Java 1.6. This is fine as long as your Maven or Gradle build
|
||||||
is set to use the same version (Maven users can use the `java.version` property). If you
|
is set to use the same version (Maven users can use the `java.version` property). If you
|
||||||
|
|
|
||||||
|
|
@ -556,6 +556,61 @@ of ways. Or the nuclear option is to add your own `JettyEmbeddedServletContainer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[howto-use-undertow-instead-of-tomcat]]
|
||||||
|
=== Use Undertow instead of Tomcat
|
||||||
|
Using Undertow instead of Tomcat is very similar to <<howto-use-jetty-instead-of-tomcat,
|
||||||
|
using Jetty instead of Tomcat>>. You need to exclude the Tomcat dependencies and include
|
||||||
|
the Undertow starter instead.
|
||||||
|
|
||||||
|
Example in Maven:
|
||||||
|
|
||||||
|
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
|
||||||
|
----
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
</dependency>
|
||||||
|
----
|
||||||
|
|
||||||
|
Example in Gradle:
|
||||||
|
|
||||||
|
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
|
||||||
|
----
|
||||||
|
configurations {
|
||||||
|
compile.exclude module: "spring-boot-starter-tomcat"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}")
|
||||||
|
compile("org.springframework.boot:spring-boot-starter-undertow:{spring-boot-version}")
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
[[howto-configure-undertow]]
|
||||||
|
=== Configure Undertow
|
||||||
|
Generally you can follow the advice from
|
||||||
|
_<<howto-discover-build-in-options-for-external-properties>>_ about
|
||||||
|
`@ConfigurationProperties` (`ServerProperties` and `ServerProperties.Undertow are the
|
||||||
|
main ones here), but also look at
|
||||||
|
`EmbeddedServletContainerCustomizer`. Once you have access to the
|
||||||
|
`UndertowEmbeddedServletContainerFactory` you can use an `UndertowBuilderCustomizer` to
|
||||||
|
modify Undertow's configuration to meet your needs. Or the nuclear option is to add your
|
||||||
|
own `UndertowEmbeddedServletContainerFactory`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[howto-use-tomcat-8]]
|
[[howto-use-tomcat-8]]
|
||||||
=== Use Tomcat 8
|
=== Use Tomcat 8
|
||||||
Tomcat 8 works with Spring Boot, but the default is to use Tomcat 7 (so we can support
|
Tomcat 8 works with Spring Boot, but the default is to use Tomcat 7 (so we can support
|
||||||
|
|
|
||||||
|
|
@ -810,8 +810,8 @@ possible.
|
||||||
[[boot-features-developing-web-applications]]
|
[[boot-features-developing-web-applications]]
|
||||||
== Developing web applications
|
== Developing web applications
|
||||||
Spring Boot is well suited for web application development. You can easily create a
|
Spring Boot is well suited for web application development. You can easily create a
|
||||||
self-contained HTTP server using embedded Tomcat or Jetty. Most web applications will
|
self-contained HTTP server using embedded Tomcat, Jetty, or Undertow. Most web
|
||||||
use the `spring-boot-starter-web` module to get up and running quickly.
|
applications will use the `spring-boot-starter-web` module to get up and running quickly.
|
||||||
|
|
||||||
If you haven't yet developed a Spring Boot web application you can follow the
|
If you haven't yet developed a Spring Boot web application you can follow the
|
||||||
"Hello World!" example in the
|
"Hello World!" example in the
|
||||||
|
|
@ -1093,9 +1093,9 @@ asks for them to be scanned in its `Filter` registration).
|
||||||
|
|
||||||
[[boot-features-embedded-container]]
|
[[boot-features-embedded-container]]
|
||||||
=== Embedded servlet container support
|
=== Embedded servlet container support
|
||||||
Spring Boot includes support for embedded Tomcat and Jetty servers. Most developers will
|
Spring Boot includes support for embedded Tomcat, Jetty, and Undertow servers. Most
|
||||||
simply use the appropriate '`Starter POM`' to obtain a fully configured instance. By
|
developers will simply use the appropriate '`Starter POM`' to obtain a fully configured
|
||||||
default both Tomcat and Jetty will listen for HTTP requests on port `8080`.
|
instance. By default the embedded server will listen for HTTP requests on port `8080`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1121,8 +1121,9 @@ interface.
|
||||||
Under the hood Spring Boot uses a new type of `ApplicationContext` for embedded
|
Under the hood Spring Boot uses a new type of `ApplicationContext` for embedded
|
||||||
servlet container support. The `EmbeddedWebApplicationContext` is a special
|
servlet container support. The `EmbeddedWebApplicationContext` is a special
|
||||||
type of `WebApplicationContext` that bootstraps itself by searching for a single
|
type of `WebApplicationContext` that bootstraps itself by searching for a single
|
||||||
`EmbeddedServletContainerFactory` bean. Usually a `TomcatEmbeddedServletContainerFactory`
|
`EmbeddedServletContainerFactory` bean. Usually a `TomcatEmbeddedServletContainerFactory`,
|
||||||
or `JettyEmbeddedServletContainerFactory` will have been auto-configured.
|
`JettyEmbeddedServletContainerFactory`, or `UndertowEmbeddedServletContainerFactory` will
|
||||||
|
have been auto-configured.
|
||||||
|
|
||||||
NOTE: You usually won't need to be aware of these implementation classes. Most
|
NOTE: You usually won't need to be aware of these implementation classes. Most
|
||||||
applications will be auto-configured and the appropriate `ApplicationContext` and
|
applications will be auto-configured and the appropriate `ApplicationContext` and
|
||||||
|
|
@ -1176,8 +1177,8 @@ methods.
|
||||||
[[boot-features-customizing-configurableembeddedservletcontainerfactory-directly]]
|
[[boot-features-customizing-configurableembeddedservletcontainerfactory-directly]]
|
||||||
===== Customizing ConfigurableEmbeddedServletContainer directly
|
===== Customizing ConfigurableEmbeddedServletContainer directly
|
||||||
If the above customization techniques are too limited, you can register the
|
If the above customization techniques are too limited, you can register the
|
||||||
`TomcatEmbeddedServletContainerFactory` or `JettyEmbeddedServletContainerFactory` bean
|
`TomcatEmbeddedServletContainerFactory`, `JettyEmbeddedServletContainerFactory` or
|
||||||
yourself.
|
`UndertowEmbeddedServletContainerFactory` bean yourself.
|
||||||
|
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
----
|
----
|
||||||
|
|
@ -1208,6 +1209,8 @@ packaged as an executable archive), there are some limitations in the JSP suppor
|
||||||
|
|
||||||
* Jetty does not currently work as an embedded container with JSPs.
|
* Jetty does not currently work as an embedded container with JSPs.
|
||||||
|
|
||||||
|
* Undertow does not support JSPs
|
||||||
|
|
||||||
There is a {github-code}/spring-boot-samples/spring-boot-sample-web-jsp[JSP sample] so
|
There is a {github-code}/spring-boot-samples/spring-boot-sample-web-jsp[JSP sample] so
|
||||||
you can see how to set things up.
|
you can see how to set things up.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,9 @@ swap specific technical facets.
|
||||||
|
|
||||||
|`spring-boot-starter-tomcat`
|
|`spring-boot-starter-tomcat`
|
||||||
|Import Spring Boot's default HTTP engine (Tomcat).
|
|Import Spring Boot's default HTTP engine (Tomcat).
|
||||||
|
|
||||||
|
|`spring-boot-starter-undertow`
|
||||||
|
|Imports the Undertow HTTP engine (to be used as an alternative to Tomcat)
|
||||||
|===
|
|===
|
||||||
|
|
||||||
TIP: For a list of additional community contributed starter POMs, see the
|
TIP: For a list of additional community contributed starter POMs, see the
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@
|
||||||
<module>spring-boot-sample-tomcat-multi-connectors</module>
|
<module>spring-boot-sample-tomcat-multi-connectors</module>
|
||||||
<module>spring-boot-sample-tomcat7-jsp</module>
|
<module>spring-boot-sample-tomcat7-jsp</module>
|
||||||
<module>spring-boot-sample-traditional</module>
|
<module>spring-boot-sample-traditional</module>
|
||||||
|
<module>spring-boot-sample-undertow</module>
|
||||||
|
<module>spring-boot-sample-undertow-ssl</module>
|
||||||
<module>spring-boot-sample-velocity</module>
|
<module>spring-boot-sample-velocity</module>
|
||||||
<module>spring-boot-sample-web-freemarker</module>
|
<module>spring-boot-sample-web-freemarker</module>
|
||||||
<module>spring-boot-sample-web-groovy-templates</module>
|
<module>spring-boot-sample-web-groovy-templates</module>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-samples</artifactId>
|
||||||
|
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-sample-undertow-ssl</artifactId>
|
||||||
|
<name>Spring Boot Undertow SSL Sample</name>
|
||||||
|
<description>Spring Boot Undertow SSL Sample</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SampleUndertowSslApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SpringApplication.run(SampleUndertowSslApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HelloWorldService {
|
||||||
|
|
||||||
|
@Value("${name:World}")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getHelloMessage() {
|
||||||
|
return "Hello " + this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow.web;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import sample.undertow.service.HelloWorldService;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class SampleController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HelloWorldService helloWorldService;
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
@ResponseBody
|
||||||
|
public String helloWorld() {
|
||||||
|
return this.helloWorldService.getHelloMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
server.port = 8443
|
||||||
|
server.ssl.key-store = classpath:sample.jks
|
||||||
|
server.ssl.key-store-password = secret
|
||||||
|
server.ssl.key-password = password
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow;
|
||||||
|
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
|
import org.apache.http.conn.ssl.SSLContextBuilder;
|
||||||
|
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.test.IntegrationTest;
|
||||||
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic integration tests for demo application.
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringApplicationConfiguration(classes = SampleUndertowSslApplication.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@IntegrationTest("server.port:0")
|
||||||
|
@DirtiesContext
|
||||||
|
public class SampleUndertowSslApplicationTests {
|
||||||
|
|
||||||
|
@Value("${local.server.port}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHome() throws Exception {
|
||||||
|
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
|
||||||
|
new SSLContextBuilder().loadTrustMaterial(null,
|
||||||
|
new TrustSelfSignedStrategy()).build());
|
||||||
|
|
||||||
|
HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||||
|
((HttpComponentsClientHttpRequestFactory) testRestTemplate.getRequestFactory())
|
||||||
|
.setHttpClient(httpClient);
|
||||||
|
ResponseEntity<String> entity = testRestTemplate.getForEntity(
|
||||||
|
"https://localhost:" + this.port, String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertEquals("Hello World", entity.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-samples</artifactId>
|
||||||
|
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-sample-undertow</artifactId>
|
||||||
|
<name>Spring Boot Undertow Sample</name>
|
||||||
|
<description>Spring Boot Undertow Sample</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SampleUndertowApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SpringApplication.run(SampleUndertowApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HelloWorldService {
|
||||||
|
|
||||||
|
@Value("${name:World}")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getHelloMessage() {
|
||||||
|
return "Hello " + this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow.web;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import sample.undertow.service.HelloWorldService;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class SampleController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HelloWorldService helloWorldService;
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
@ResponseBody
|
||||||
|
public String helloWorld() {
|
||||||
|
return this.helloWorldService.getHelloMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 sample.undertow;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.test.IntegrationTest;
|
||||||
|
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||||
|
import org.springframework.boot.test.TestRestTemplate;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic integration tests for demo application.
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringApplicationConfiguration(classes = SampleUndertowApplication.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@IntegrationTest("server.port:0")
|
||||||
|
@DirtiesContext
|
||||||
|
public class SampleUndertowApplicationTests {
|
||||||
|
|
||||||
|
@Value("${local.server.port}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHome() throws Exception {
|
||||||
|
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||||
|
"http://localhost:" + this.port, String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertEquals("Hello World", entity.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -56,6 +56,7 @@
|
||||||
<module>spring-boot-starter-test</module>
|
<module>spring-boot-starter-test</module>
|
||||||
<module>spring-boot-starter-thymeleaf</module>
|
<module>spring-boot-starter-thymeleaf</module>
|
||||||
<module>spring-boot-starter-tomcat</module>
|
<module>spring-boot-starter-tomcat</module>
|
||||||
|
<module>spring-boot-starter-undertow</module>
|
||||||
<module>spring-boot-starter-velocity</module>
|
<module>spring-boot-starter-velocity</module>
|
||||||
<module>spring-boot-starter-web</module>
|
<module>spring-boot-starter-web</module>
|
||||||
<module>spring-boot-starter-websocket</module>
|
<module>spring-boot-starter-websocket</module>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starters</artifactId>
|
||||||
|
<version>1.2.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
<name>Spring Boot Undertow Starter</name>
|
||||||
|
<description>Spring Boot Undertow Starter</description>
|
||||||
|
<url>http://projects.spring.io/spring-boot/</url>
|
||||||
|
<organization>
|
||||||
|
<name>Pivotal Software, Inc.</name>
|
||||||
|
<url>http://www.spring.io</url>
|
||||||
|
</organization>
|
||||||
|
<properties>
|
||||||
|
<main.basedir>${basedir}/../..</main.basedir>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-servlet</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
|
|
@ -129,6 +129,11 @@
|
||||||
<artifactId>jetty-util</artifactId>
|
<artifactId>jetty-util</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-servlet</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate-entitymanager</artifactId>
|
<artifactId>hibernate-entitymanager</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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.undertow;
|
||||||
|
|
||||||
|
import io.undertow.Undertow.Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback interface that can be used to customize an Undertow {@link Builder}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see UndertowEmbeddedServletContainerFactory
|
||||||
|
*/
|
||||||
|
public interface UndertowBuilderCustomizer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param builder the {@code Builder} to customize
|
||||||
|
*/
|
||||||
|
void customize(Builder builder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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.undertow;
|
||||||
|
|
||||||
|
import io.undertow.Handlers;
|
||||||
|
import io.undertow.Undertow;
|
||||||
|
import io.undertow.Undertow.Builder;
|
||||||
|
import io.undertow.server.HttpHandler;
|
||||||
|
import io.undertow.server.handlers.PathHandler;
|
||||||
|
import io.undertow.servlet.api.DeploymentManager;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
||||||
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerException;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EmbeddedServletContainer} that can be used to control an embedded Undertow
|
||||||
|
* server. Typically this class should be created using
|
||||||
|
* {@link UndertowEmbeddedServletContainerFactory} and not directly.
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see UndertowEmbeddedServletContainer
|
||||||
|
*/
|
||||||
|
public class UndertowEmbeddedServletContainer implements EmbeddedServletContainer {
|
||||||
|
|
||||||
|
private final DeploymentManager manager;
|
||||||
|
|
||||||
|
private final Builder builder;
|
||||||
|
|
||||||
|
private final String contextPath;
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
private final boolean autoStart;
|
||||||
|
|
||||||
|
private Undertow undertow;
|
||||||
|
|
||||||
|
private boolean started = false;
|
||||||
|
|
||||||
|
public UndertowEmbeddedServletContainer(Builder builder, DeploymentManager manager,
|
||||||
|
String contextPath, int port, boolean autoStart) {
|
||||||
|
this.builder = builder;
|
||||||
|
this.manager = manager;
|
||||||
|
this.contextPath = contextPath;
|
||||||
|
this.port = port;
|
||||||
|
this.autoStart = autoStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void start() throws EmbeddedServletContainerException {
|
||||||
|
if (!this.autoStart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.undertow == null) {
|
||||||
|
try {
|
||||||
|
HttpHandler servletHandler = this.manager.start();
|
||||||
|
if (StringUtils.isEmpty(this.contextPath)) {
|
||||||
|
this.builder.setHandler(servletHandler);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PathHandler pathHandler = Handlers.path().addPrefixPath(
|
||||||
|
this.contextPath, servletHandler);
|
||||||
|
this.builder.setHandler(pathHandler);
|
||||||
|
}
|
||||||
|
this.undertow = this.builder.build();
|
||||||
|
}
|
||||||
|
catch (ServletException ex) {
|
||||||
|
throw new EmbeddedServletContainerException(
|
||||||
|
"Unable to start embdedded Undertow", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.undertow.start();
|
||||||
|
this.started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void stop() throws EmbeddedServletContainerException {
|
||||||
|
if (this.started) {
|
||||||
|
this.started = false;
|
||||||
|
this.undertow.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPort() {
|
||||||
|
return this.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,507 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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.undertow;
|
||||||
|
|
||||||
|
import io.undertow.Undertow;
|
||||||
|
import io.undertow.Undertow.Builder;
|
||||||
|
import io.undertow.UndertowMessages;
|
||||||
|
import io.undertow.server.handlers.resource.ClassPathResourceManager;
|
||||||
|
import io.undertow.server.handlers.resource.FileResourceManager;
|
||||||
|
import io.undertow.server.handlers.resource.Resource;
|
||||||
|
import io.undertow.server.handlers.resource.ResourceChangeListener;
|
||||||
|
import io.undertow.server.handlers.resource.ResourceManager;
|
||||||
|
import io.undertow.server.handlers.resource.URLResource;
|
||||||
|
import io.undertow.servlet.api.DeploymentInfo;
|
||||||
|
import io.undertow.servlet.api.DeploymentManager;
|
||||||
|
import io.undertow.servlet.api.InstanceFactory;
|
||||||
|
import io.undertow.servlet.api.InstanceHandle;
|
||||||
|
import io.undertow.servlet.api.ListenerInfo;
|
||||||
|
import io.undertow.servlet.api.MimeMapping;
|
||||||
|
import io.undertow.servlet.api.ServletStackTraces;
|
||||||
|
import io.undertow.servlet.handlers.DefaultServlet;
|
||||||
|
import io.undertow.servlet.util.ImmediateInstanceHandle;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.net.ssl.KeyManager;
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import javax.servlet.ServletContextEvent;
|
||||||
|
import javax.servlet.ServletContextListener;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.EmbeddedServletContainer;
|
||||||
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.ErrorPage;
|
||||||
|
import org.springframework.boot.context.embedded.MimeMappings.Mapping;
|
||||||
|
import org.springframework.boot.context.embedded.ServletContextInitializer;
|
||||||
|
import org.springframework.boot.context.embedded.Ssl;
|
||||||
|
import org.springframework.boot.context.embedded.Ssl.ClientAuth;
|
||||||
|
import org.springframework.context.ResourceLoaderAware;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import org.springframework.util.SocketUtils;
|
||||||
|
|
||||||
|
import static io.undertow.servlet.Servlets.defaultContainer;
|
||||||
|
import static io.undertow.servlet.Servlets.deployment;
|
||||||
|
import static io.undertow.servlet.Servlets.servlet;
|
||||||
|
import static org.xnio.Options.SSL_CLIENT_AUTH_MODE;
|
||||||
|
import static org.xnio.SslClientAuthMode.NOT_REQUESTED;
|
||||||
|
import static org.xnio.SslClientAuthMode.REQUESTED;
|
||||||
|
import static org.xnio.SslClientAuthMode.REQUIRED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EmbeddedServletContainerFactory} that can be used to create
|
||||||
|
* {@link UndertowEmbeddedServletContainer}s.
|
||||||
|
* <p>
|
||||||
|
* Unless explicitly configured otherwise, the factory will create containers that listen
|
||||||
|
* for HTTP requests on port 8080.
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 1.2.0
|
||||||
|
* @see UndertowEmbeddedServletContainer
|
||||||
|
*/
|
||||||
|
public class UndertowEmbeddedServletContainerFactory extends
|
||||||
|
AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
|
||||||
|
|
||||||
|
private List<UndertowBuilderCustomizer> undertowBuilderCustomizers = new ArrayList<UndertowBuilderCustomizer>();
|
||||||
|
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
private Integer bufferSize;
|
||||||
|
|
||||||
|
private Integer buffersPerRegion;
|
||||||
|
|
||||||
|
private Integer ioThreads;
|
||||||
|
|
||||||
|
private Integer workerThreads;
|
||||||
|
|
||||||
|
private Boolean directBuffers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link UndertowEmbeddedServletContainerFactory} instance.
|
||||||
|
*/
|
||||||
|
public UndertowEmbeddedServletContainerFactory() {
|
||||||
|
super();
|
||||||
|
setRegisterJspServlet(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link UndertowEmbeddedServletContainerFactory} that listens for
|
||||||
|
* requests using the specified port.
|
||||||
|
* @param port the port to listen on
|
||||||
|
*/
|
||||||
|
public UndertowEmbeddedServletContainerFactory(int port) {
|
||||||
|
super(port);
|
||||||
|
setRegisterJspServlet(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link UndertowEmbeddedServletContainerFactory} with the specified
|
||||||
|
* context path and port.
|
||||||
|
* @param contextPath root the context path
|
||||||
|
* @param port the port to listen on
|
||||||
|
*/
|
||||||
|
public UndertowEmbeddedServletContainerFactory(String contextPath, int port) {
|
||||||
|
super(contextPath, port);
|
||||||
|
setRegisterJspServlet(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set {@link UndertowBuilderCustomizer}s that should be applied to the Undertow
|
||||||
|
* {@link Builder}. Calling this method will replace any existing customizers.
|
||||||
|
* @param undertowBuilderCustomizers the customizers to set
|
||||||
|
*/
|
||||||
|
public void setUndertowBuilderCustomizers(
|
||||||
|
Collection<? extends UndertowBuilderCustomizer> undertowBuilderCustomizers) {
|
||||||
|
Assert.notNull(undertowBuilderCustomizers,
|
||||||
|
"undertowBuilderCustomizers must not be null");
|
||||||
|
this.undertowBuilderCustomizers = new ArrayList<UndertowBuilderCustomizer>(
|
||||||
|
undertowBuilderCustomizers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a mutable collection of the {@link UndertowBuilderCustomizer}s that will be
|
||||||
|
* applied to the Undertow {@link Builder} .
|
||||||
|
* @return the customizers that will be applied
|
||||||
|
*/
|
||||||
|
public Collection<UndertowBuilderCustomizer> getUndertowBuilderCustomizers() {
|
||||||
|
return this.undertowBuilderCustomizers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add {@link UndertowBuilderCustomizer}s that should be used to customize the
|
||||||
|
* Undertow {@link Builder}.
|
||||||
|
* @param undertowBuilderCustomizers the customizers to add
|
||||||
|
*/
|
||||||
|
public void addUndertowBuilderCustomizers(
|
||||||
|
UndertowBuilderCustomizer... undertowBuilderCustomizers) {
|
||||||
|
Assert.notNull(undertowBuilderCustomizers,
|
||||||
|
"undertowBuilderCustomizers must not be null");
|
||||||
|
this.undertowBuilderCustomizers.addAll(Arrays.asList(undertowBuilderCustomizers));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EmbeddedServletContainer getEmbeddedServletContainer(
|
||||||
|
ServletContextInitializer... initializers) {
|
||||||
|
DeploymentManager manager = createDeploymentManager(initializers);
|
||||||
|
|
||||||
|
int port = getPort();
|
||||||
|
if (port == 0) {
|
||||||
|
port = SocketUtils.findAvailableTcpPort(40000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder builder = createBuilder(port);
|
||||||
|
|
||||||
|
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
|
||||||
|
port, port >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder createBuilder(int port) {
|
||||||
|
Builder builder = Undertow.builder();
|
||||||
|
if (this.bufferSize != null) {
|
||||||
|
builder.setBufferSize(this.bufferSize);
|
||||||
|
}
|
||||||
|
if (this.buffersPerRegion != null) {
|
||||||
|
builder.setBuffersPerRegion(this.buffersPerRegion);
|
||||||
|
}
|
||||||
|
if (this.ioThreads != null) {
|
||||||
|
builder.setIoThreads(this.ioThreads);
|
||||||
|
}
|
||||||
|
if (this.workerThreads != null) {
|
||||||
|
builder.setWorkerThreads(this.workerThreads);
|
||||||
|
}
|
||||||
|
if (this.directBuffers != null) {
|
||||||
|
builder.setDirectBuffers(this.directBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getSsl() == null) {
|
||||||
|
builder.addHttpListener(port, "0.0.0.0");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
configureSsl(port, builder);
|
||||||
|
}
|
||||||
|
for (UndertowBuilderCustomizer customizer : this.undertowBuilderCustomizers) {
|
||||||
|
customizer.customize(builder);
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureSsl(int port, Builder builder) {
|
||||||
|
try {
|
||||||
|
Ssl ssl = getSsl();
|
||||||
|
SSLContext sslContext = SSLContext.getInstance(ssl.getProtocol());
|
||||||
|
sslContext.init(getKeyManagers(), getTrustManagers(), null);
|
||||||
|
builder.addHttpsListener(port, "0.0.0.0", sslContext);
|
||||||
|
if (ssl.getClientAuth() == ClientAuth.NEED) {
|
||||||
|
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, REQUIRED);
|
||||||
|
}
|
||||||
|
else if (ssl.getClientAuth() == ClientAuth.WANT) {
|
||||||
|
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, REQUESTED);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder.setSocketOption(SSL_CLIENT_AUTH_MODE, NOT_REQUESTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
catch (KeyManagementException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private KeyManager[] getKeyManagers() {
|
||||||
|
try {
|
||||||
|
Ssl ssl = getSsl();
|
||||||
|
|
||||||
|
String keyStoreType = ssl.getKeyStoreType();
|
||||||
|
if (keyStoreType == null) {
|
||||||
|
keyStoreType = "JKS";
|
||||||
|
}
|
||||||
|
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||||
|
URL url = ResourceUtils.getURL(ssl.getKeyStore());
|
||||||
|
keyStore.load(url.openStream(), ssl.getKeyStorePassword().toCharArray());
|
||||||
|
|
||||||
|
// Get key manager to provide client credentials.
|
||||||
|
KeyManagerFactory keyManagerFactory = KeyManagerFactory
|
||||||
|
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||||
|
char[] keyPassword = ssl.getKeyPassword() != null ? ssl.getKeyPassword()
|
||||||
|
.toCharArray() : ssl.getKeyStorePassword().toCharArray();
|
||||||
|
keyManagerFactory.init(keyStore, keyPassword);
|
||||||
|
return keyManagerFactory.getKeyManagers();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrustManager[] getTrustManagers() {
|
||||||
|
try {
|
||||||
|
Ssl ssl = getSsl();
|
||||||
|
|
||||||
|
String trustStoreType = ssl.getTrustStoreType();
|
||||||
|
if (trustStoreType == null) {
|
||||||
|
trustStoreType = "JKS";
|
||||||
|
}
|
||||||
|
String trustStore = ssl.getTrustStore();
|
||||||
|
if (trustStore == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
KeyStore trustedKeyStore = KeyStore.getInstance(trustStoreType);
|
||||||
|
URL url = ResourceUtils.getURL(trustStore);
|
||||||
|
trustedKeyStore.load(url.openStream(), ssl.getTrustStorePassword()
|
||||||
|
.toCharArray());
|
||||||
|
|
||||||
|
TrustManagerFactory trustManagerFactory = TrustManagerFactory
|
||||||
|
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
trustManagerFactory.init(trustedKeyStore);
|
||||||
|
return trustManagerFactory.getTrustManagers();
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeploymentManager createDeploymentManager(
|
||||||
|
ServletContextInitializer... initializers) {
|
||||||
|
DeploymentInfo servletBuilder = deployment();
|
||||||
|
|
||||||
|
servletBuilder.addListener(new ListenerInfo(
|
||||||
|
UndertowSpringServletContextListener.class,
|
||||||
|
new UndertowSpringServletContextListenerFactory(
|
||||||
|
new UndertowSpringServletContextListener(
|
||||||
|
mergeInitializers(initializers)))));
|
||||||
|
|
||||||
|
if (this.resourceLoader != null) {
|
||||||
|
servletBuilder.setClassLoader(this.resourceLoader.getClassLoader());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
servletBuilder.setClassLoader(getClass().getClassLoader());
|
||||||
|
}
|
||||||
|
servletBuilder.setContextPath(getContextPath());
|
||||||
|
servletBuilder.setDeploymentName("spring-boot");
|
||||||
|
if (isRegisterDefaultServlet()) {
|
||||||
|
servletBuilder.addServlet(servlet("default", DefaultServlet.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
configureErrorPages(servletBuilder);
|
||||||
|
servletBuilder.setServletStackTraces(ServletStackTraces.NONE);
|
||||||
|
|
||||||
|
File root = getValidDocumentRoot();
|
||||||
|
if (root != null && root.isDirectory()) {
|
||||||
|
servletBuilder.setResourceManager(new FileResourceManager(root, 0));
|
||||||
|
}
|
||||||
|
else if (root != null && root.isFile()) {
|
||||||
|
servletBuilder.setResourceManager(new JarResourcemanager(root));
|
||||||
|
}
|
||||||
|
else if (this.resourceLoader != null) {
|
||||||
|
servletBuilder.setResourceManager(new ClassPathResourceManager(
|
||||||
|
this.resourceLoader.getClassLoader(), ""));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
servletBuilder.setResourceManager(new ClassPathResourceManager(getClass()
|
||||||
|
.getClassLoader(), ""));
|
||||||
|
}
|
||||||
|
for (Mapping mimeMapping : getMimeMappings()) {
|
||||||
|
servletBuilder.addMimeMapping(new MimeMapping(mimeMapping.getExtension(),
|
||||||
|
mimeMapping.getMimeType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DeploymentManager manager = defaultContainer().addDeployment(servletBuilder);
|
||||||
|
|
||||||
|
manager.deploy();
|
||||||
|
|
||||||
|
manager.getDeployment().getSessionManager()
|
||||||
|
.setDefaultSessionTimeout(getSessionTimeout());
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureErrorPages(DeploymentInfo servletBuilder) {
|
||||||
|
for (ErrorPage errorPage : getErrorPages()) {
|
||||||
|
if (errorPage.getStatus() != null) {
|
||||||
|
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage(
|
||||||
|
errorPage.getPath(), errorPage.getStatusCode());
|
||||||
|
servletBuilder.addErrorPage(undertowErrorpage);
|
||||||
|
}
|
||||||
|
else if (errorPage.getException() != null) {
|
||||||
|
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage(
|
||||||
|
errorPage.getPath(), errorPage.getException());
|
||||||
|
servletBuilder.addErrorPage(undertowErrorpage);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
io.undertow.servlet.api.ErrorPage undertowErrorpage = new io.undertow.servlet.api.ErrorPage(
|
||||||
|
errorPage.getPath());
|
||||||
|
servletBuilder.addErrorPage(undertowErrorpage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method called to create the {@link UndertowEmbeddedServletContainer}.
|
||||||
|
* Subclasses can override this method to return a different
|
||||||
|
* {@link UndertowEmbeddedServletContainer} or apply additional processing to the
|
||||||
|
* {@link Builder} and {@link DeploymentManager} used to bootstrap Undertow
|
||||||
|
*
|
||||||
|
* @param builder the builder
|
||||||
|
* @param manager the deployment manager
|
||||||
|
* @param port the port that Undertow should listen on
|
||||||
|
* @return a new {@link UndertowEmbeddedServletContainer} instance
|
||||||
|
*/
|
||||||
|
protected UndertowEmbeddedServletContainer getUndertowEmbeddedServletContainer(
|
||||||
|
Builder builder, DeploymentManager manager, int port) {
|
||||||
|
return new UndertowEmbeddedServletContainer(builder, manager, getContextPath(),
|
||||||
|
port, port >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBufferSize(Integer bufferSize) {
|
||||||
|
this.bufferSize = bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBuffersPerRegion(Integer buffersPerRegion) {
|
||||||
|
this.buffersPerRegion = buffersPerRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIoThreads(Integer ioThreads) {
|
||||||
|
this.ioThreads = ioThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorkerThreads(Integer workerThreads) {
|
||||||
|
this.workerThreads = workerThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectBuffers(Boolean directBuffers) {
|
||||||
|
this.directBuffers = directBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRegisterJspServlet(boolean registerJspServlet) {
|
||||||
|
Assert.isTrue(!registerJspServlet, "Undertow does not support JSPs");
|
||||||
|
super.setRegisterJspServlet(registerJspServlet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class JarResourcemanager implements ResourceManager {
|
||||||
|
private final String jarPath;
|
||||||
|
|
||||||
|
public JarResourcemanager(File jarFile) {
|
||||||
|
this(jarFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarResourcemanager(String jarPath) {
|
||||||
|
this.jarPath = jarPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
// no code
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Resource getResource(String path) throws IOException {
|
||||||
|
URL url = new URL("jar:file:" + this.jarPath + "!" + path);
|
||||||
|
URLResource resource = new URLResource(url, url.openConnection(), path);
|
||||||
|
if (resource.getContentLength() < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isResourceChangeListenerSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerResourceChangeListener(ResourceChangeListener listener) {
|
||||||
|
throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeResourceChangeListener(ResourceChangeListener listener) {
|
||||||
|
throw UndertowMessages.MESSAGES.resourceChangeListenerNotSupported();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UndertowSpringServletContextListenerFactory implements
|
||||||
|
InstanceFactory<UndertowSpringServletContextListener> {
|
||||||
|
|
||||||
|
private final UndertowSpringServletContextListener listener;
|
||||||
|
|
||||||
|
public UndertowSpringServletContextListenerFactory(
|
||||||
|
UndertowSpringServletContextListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceHandle<UndertowSpringServletContextListener> createInstance()
|
||||||
|
throws InstantiationException {
|
||||||
|
return new ImmediateInstanceHandle<UndertowSpringServletContextListener>(
|
||||||
|
this.listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UndertowSpringServletContextListener implements
|
||||||
|
ServletContextListener {
|
||||||
|
private final ServletContextInitializer[] initializers;
|
||||||
|
|
||||||
|
public UndertowSpringServletContextListener(
|
||||||
|
ServletContextInitializer... initializers) {
|
||||||
|
this.initializers = initializers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextInitialized(ServletContextEvent event) {
|
||||||
|
try {
|
||||||
|
for (ServletContextInitializer initializer : this.initializers) {
|
||||||
|
initializer.onStartup(event.getServletContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ServletException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
|
// no code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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 Undertow {@link org.springframework.boot.context.embedded.EmbeddedServletContainer EmbeddedServletContainers}.
|
||||||
|
*
|
||||||
|
* @see org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory
|
||||||
|
*/
|
||||||
|
package org.springframework.boot.context.embedded.undertow;
|
||||||
|
|
||||||
|
|
@ -24,6 +24,7 @@ import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
|
||||||
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
@ -48,6 +49,7 @@ import static org.junit.Assert.assertThat;
|
||||||
* {@link EmbeddedServletContainer}s running Spring MVC.
|
* {@link EmbeddedServletContainer}s running Spring MVC.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Ivan Sopov
|
||||||
*/
|
*/
|
||||||
public class EmbeddedServletContainerMvcIntegrationTests {
|
public class EmbeddedServletContainerMvcIntegrationTests {
|
||||||
|
|
||||||
|
|
@ -76,6 +78,13 @@ public class EmbeddedServletContainerMvcIntegrationTests {
|
||||||
doTest(this.context, "/hello");
|
doTest(this.context, "/hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void undertow() throws Exception {
|
||||||
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
|
UndertowConfig.class);
|
||||||
|
doTest(this.context, "/hello");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void advancedConfig() throws Exception {
|
public void advancedConfig() throws Exception {
|
||||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
|
||||||
|
|
@ -118,6 +127,15 @@ public class EmbeddedServletContainerMvcIntegrationTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(Config.class)
|
||||||
|
public static class UndertowConfig {
|
||||||
|
@Bean
|
||||||
|
public EmbeddedServletContainerFactory containerFactory() {
|
||||||
|
return new UndertowEmbeddedServletContainerFactory(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
public static class Config {
|
public static class Config {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2014 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.undertow;
|
||||||
|
|
||||||
|
import io.undertow.Undertow.Builder;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
|
||||||
|
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactoryTests;
|
||||||
|
import org.springframework.boot.context.embedded.ErrorPage;
|
||||||
|
import org.springframework.boot.context.embedded.ExampleServlet;
|
||||||
|
import org.springframework.boot.context.embedded.ServletRegistrationBean;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link UndertowEmbeddedServletContainerFactory} and
|
||||||
|
* {@link UndertowEmbeddedServletContainer} .
|
||||||
|
*
|
||||||
|
* @author Ivan Sopov
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class UndertowEmbeddedServletContainerFactoryTests extends
|
||||||
|
AbstractEmbeddedServletContainerFactoryTests {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected UndertowEmbeddedServletContainerFactory getFactory() {
|
||||||
|
return new UndertowEmbeddedServletContainerFactory(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void errorPage404() throws Exception {
|
||||||
|
AbstractEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/hello"));
|
||||||
|
this.container = factory.getEmbeddedServletContainer(new ServletRegistrationBean(
|
||||||
|
new ExampleServlet(), "/hello"));
|
||||||
|
this.container.start();
|
||||||
|
assertThat(getResponse(getLocalUrl("/hello")), equalTo("Hello World"));
|
||||||
|
assertThat(getResponse(getLocalUrl("/not-found")), equalTo("Hello World"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setNullUndertowBuilderCustomizersThrows() {
|
||||||
|
UndertowEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("undertowBuilderCustomizers must not be null");
|
||||||
|
factory.setUndertowBuilderCustomizers(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addNullContextCustomizersThrows() {
|
||||||
|
UndertowEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("undertowBuilderCustomizers must not be null");
|
||||||
|
factory.addUndertowBuilderCustomizers((UndertowBuilderCustomizer[]) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void builderCustomizers() throws Exception {
|
||||||
|
UndertowEmbeddedServletContainerFactory factory = getFactory();
|
||||||
|
UndertowBuilderCustomizer[] customizers = new UndertowBuilderCustomizer[4];
|
||||||
|
for (int i = 0; i < customizers.length; i++) {
|
||||||
|
customizers[i] = mock(UndertowBuilderCustomizer.class);
|
||||||
|
}
|
||||||
|
factory.setUndertowBuilderCustomizers(Arrays.asList(customizers[0],
|
||||||
|
customizers[1]));
|
||||||
|
factory.addUndertowBuilderCustomizers(customizers[2], customizers[3]);
|
||||||
|
this.container = factory.getEmbeddedServletContainer();
|
||||||
|
InOrder ordered = inOrder((Object[]) customizers);
|
||||||
|
for (UndertowBuilderCustomizer customizer : customizers) {
|
||||||
|
ordered.verify(customizer).customize((Builder) anyObject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue