Skip to content

Commit

Permalink
Add support for using Undertow as an embedded container
Browse files Browse the repository at this point in the history
  • Loading branch information
isopov authored and wilkinsona committed Nov 18, 2014
1 parent 21115f2 commit c501b88
Show file tree
Hide file tree
Showing 27 changed files with 1,215 additions and 7 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
.classpath
.project
.settings
.metadata
bin
build
lib/
Expand All @@ -28,4 +29,4 @@ overridedb.*
*.iws
.idea
*.jar
.DS_Store
.DS_Store
5 changes: 5 additions & 0 deletions spring-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@
<artifactId>jetty-webapp</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.boot.autoconfigure.web;

import io.undertow.Undertow;

import javax.servlet.Servlet;

import org.apache.catalina.startup.Tomcat;
Expand All @@ -37,6 +39,7 @@
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
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.Configuration;
import org.springframework.context.annotation.Import;
Expand Down Expand Up @@ -87,6 +90,22 @@ public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory
}

}

/**
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
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.NestedConfigurationProperty;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -71,13 +72,19 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
private String servletPath = "/";

private final Tomcat tomcat = new Tomcat();

private final Undertow undertow = new Undertow();

private final Map<String, String> contextParameters = new HashMap<String, String>();

public Tomcat getTomcat() {
return this.tomcat;
}

public Undertow getUndertow() {
return this.undertow;
}

public String getContextPath() {
return this.contextPath;
}
Expand Down Expand Up @@ -179,7 +186,10 @@ public void customize(ConfigurableEmbeddedServletContainer container) {
getTomcat()
.customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
}

if (container instanceof UndertowEmbeddedServletContainerFactory) {
getUndertow().customizeUndertow(
(UndertowEmbeddedServletContainerFactory) container);
}
container.addInitializers(new InitParameterConfiguringServletContextInitializer(
getContextParameters()));
}
Expand Down Expand Up @@ -210,6 +220,62 @@ public String getPath(String path) {
return prefix + path;
}

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(bufferSize);
factory.setBuffersPerRegion(buffersPerRegion);
factory.setIoThreads(ioThreads);
factory.setWorkerThreads(workerThreads);
factory.setDirectBuffers(directBuffers);
}
}

public static class Tomcat {

private String accessLogPattern;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

package org.springframework.boot.autoconfigure.web;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.MultipartConfigElement;

import org.junit.After;
Expand All @@ -25,10 +29,16 @@
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
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.Configuration;
import org.springframework.context.annotation.Import;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
Expand Down Expand Up @@ -71,10 +81,11 @@ public void close() {
}

@Test
public void containerWithNothing() {
public void containerWithNothing() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
ContainerWithNothing.class, BaseConfiguration.class);
DispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);
verify404();
assertNotNull(servlet.getMultipartResolver());
assertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)
.size(), equalTo(1));
Expand Down Expand Up @@ -112,6 +123,32 @@ WebController controller() {
}
}

@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
public void containerWithNoMultipartTomcatConfiguration() {
this.context = new AnnotationConfigEmbeddedWebApplicationContext(
Expand Down Expand Up @@ -148,6 +185,16 @@ public void containerWithAutomatedMultipartTomcatConfiguration() throws Exceptio
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
public void containerWithMultipartConfigDisabled() {

Expand Down Expand Up @@ -178,6 +225,16 @@ public void containerWithCustomMulipartResolver() throws Exception {
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() {
RestTemplate restTemplate = new RestTemplate();
assertEquals("Hello", restTemplate.getForObject("http://localhost:"
Expand Down Expand Up @@ -256,6 +313,27 @@ WebController webController() {

}

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

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
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.context.ApplicationContextException;
import org.springframework.context.annotation.Bean;
Expand Down Expand Up @@ -97,9 +98,9 @@ public void tomcatProperties() throws Exception {
}

@Test
public void customizeWithContainerFactory() throws Exception {
public void customizeWithJettyContainerFactory() throws Exception {
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
this.context.register(CustomContainerConfig.class,
this.context.register(CustomJettyContainerConfig.class,
ServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
Expand All @@ -111,6 +112,22 @@ public void customizeWithContainerFactory() throws Exception {
// factory should take precedence...
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
public void customizeTomcatWithCustomizer() throws Exception {
Expand Down Expand Up @@ -154,7 +171,7 @@ public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContai
}

@Configuration
protected static class CustomContainerConfig {
protected static class CustomJettyContainerConfig {

@Bean
public EmbeddedServletContainerFactory containerFactory() {
Expand All @@ -169,6 +186,26 @@ public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContai
}

}

@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
protected static class CustomizeConfig {
Expand Down
Loading

0 comments on commit c501b88

Please sign in to comment.