javax.cache
cache-api
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizer.java
new file mode 100644
index 0000000000..b136df8eea
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizer.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.embedded.ConfigurableReactiveWebServer;
+import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
+import org.springframework.boot.context.embedded.ReactiveWebServerCustomizer;
+import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
+import org.springframework.core.Ordered;
+
+/**
+ * Customizer used by an {@link ReactiveWebServerFactory} when an
+ * {@link EmbeddedServletContainerCustomizerBeanPostProcessor} is active.
+ *
+ * @author Brian Clozel
+ */
+public class DefaultReactiveWebServerCustomizer
+ implements ReactiveWebServerCustomizer, Ordered {
+
+ private final ServerProperties serverProperties;
+
+ public DefaultReactiveWebServerCustomizer(ServerProperties serverProperties) {
+ this.serverProperties = serverProperties;
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public void customize(ConfigurableReactiveWebServer server) {
+ if (this.serverProperties.getPort() != null) {
+ server.setPort(this.serverProperties.getPort());
+ }
+ if (this.serverProperties.getAddress() != null) {
+ server.setAddress(this.serverProperties.getAddress());
+ }
+ if (this.serverProperties.getSsl() != null) {
+ server.setSsl(this.serverProperties.getSsl());
+ }
+ if (this.serverProperties.getCompression() != null) {
+ server.setCompression(this.serverProperties.getCompression());
+ }
+
+ }
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfiguration.java
new file mode 100644
index 0000000000..e96826b07f
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfiguration.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.boot.autoconfigure.AutoConfigureOrder;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.embedded.ReactiveWebServerCustomizerBeanPostProcessor;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.Ordered;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for a reactive web server.
+ *
+ * @author Brian Clozel
+ */
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
+@Configuration
+@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
+@EnableConfigurationProperties(ServerProperties.class)
+@Import({ReactiveWebServerAutoConfiguration.BeanPostProcessorsRegistrar.class,
+ ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration.class})
+public class ReactiveWebServerAutoConfiguration {
+
+ @ConditionalOnMissingBean
+ @Bean
+ public DefaultReactiveWebServerCustomizer defaultReactiveWebServerCustomizer(
+ ServerProperties serverProperties) {
+ return new DefaultReactiveWebServerCustomizer(serverProperties);
+ }
+
+ /**
+ * Registers a {@link ReactiveWebServerCustomizerBeanPostProcessor}. Registered
+ * via {@link ImportBeanDefinitionRegistrar} for early registration.
+ */
+ public static class BeanPostProcessorsRegistrar
+ implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
+
+ private ConfigurableListableBeanFactory beanFactory;
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ if (beanFactory instanceof ConfigurableListableBeanFactory) {
+ this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
+ }
+ }
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+ if (this.beanFactory == null) {
+ return;
+ }
+ if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(
+ ReactiveWebServerCustomizerBeanPostProcessor.class, true, false))) {
+ registry.registerBeanDefinition(
+ "reactiveWebServerCustomizerBeanPostProcessor",
+ new RootBeanDefinition(ReactiveWebServerCustomizerBeanPostProcessor.class));
+
+ }
+ }
+
+ }
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerConfiguration.java
new file mode 100644
index 0000000000..b90fe7d8ef
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerConfiguration.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import reactor.ipc.netty.http.server.HttpServer;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
+import org.springframework.boot.context.embedded.reactor.ReactorNettyReactiveWebServerFactory;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Configuration classes for reactive web servers
+ * Those should be {@code @Import} in a regular auto-configuration class
+ * to guarantee their order of execution.
+ *
+ * @author Brian Clozel
+ */
+abstract class ReactiveWebServerConfiguration {
+
+ @ConditionalOnMissingBean(ReactiveWebServerFactory.class)
+ @ConditionalOnClass({HttpServer.class})
+ static class ReactorNettyAutoConfiguration {
+ @Bean
+ public ReactorNettyReactiveWebServerFactory reactorNettyReactiveWebServerFactory() {
+ return new ReactorNettyReactiveWebServerFactory();
+ }
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizerTests.java
new file mode 100644
index 0000000000..5f12ef78ab
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/DefaultReactiveWebServerCustomizerTests.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import java.net.InetAddress;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.embedded.ConfigurableReactiveWebServer;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link DefaultReactiveWebServerCustomizer}.
+ *
+ * @author Brian Clozel
+ */
+public class DefaultReactiveWebServerCustomizerTests {
+
+ private final ServerProperties properties = new ServerProperties();
+
+ private DefaultReactiveWebServerCustomizer customizer;
+
+
+ @Before
+ public void setup() throws Exception {
+ this.customizer = new DefaultReactiveWebServerCustomizer(this.properties);
+ }
+
+ @Test
+ public void testCustomizeServerPort() throws Exception {
+ ConfigurableReactiveWebServer factory = mock(ConfigurableReactiveWebServer.class);
+ this.properties.setPort(9000);
+ this.customizer.customize(factory);
+ verify(factory).setPort(9000);
+ }
+
+ @Test
+ public void testCustomizeServerAddress() throws Exception {
+ ConfigurableReactiveWebServer factory = mock(ConfigurableReactiveWebServer.class);
+ InetAddress address = mock(InetAddress.class);
+ this.properties.setAddress(address);
+ this.customizer.customize(factory);
+ verify(factory).setAddress(address);
+ }
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/MockReactiveWebServerFactory.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/MockReactiveWebServerFactory.java
new file mode 100644
index 0000000000..1e3f63cd80
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/MockReactiveWebServerFactory.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import java.util.Map;
+
+import org.springframework.boot.context.embedded.AbstractReactiveWebServerFactory;
+import org.springframework.boot.context.embedded.EmbeddedWebServer;
+import org.springframework.boot.context.embedded.EmbeddedWebServerException;
+import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
+import org.springframework.http.server.reactive.HttpHandler;
+
+import static org.mockito.Mockito.spy;
+
+/**
+ * Mock {@link ReactiveWebServerFactory}.
+ *
+ * @author Brian Clozel
+ */
+public class MockReactiveWebServerFactory extends AbstractReactiveWebServerFactory {
+
+ private MockReactiveWebServer webServer;
+
+ @Override
+ public EmbeddedWebServer getReactiveHttpServer(HttpHandler httpHandler) {
+ this.webServer = spy(new MockReactiveWebServer(httpHandler, getPort()));
+ return this.webServer;
+ }
+
+ @Override
+ public EmbeddedWebServer getReactiveHttpServer(Map handlerMap) {
+ this.webServer = spy(new MockReactiveWebServer(handlerMap, getPort()));
+ return this.webServer;
+ }
+
+ public MockReactiveWebServer getWebServer() {
+ return this.webServer;
+ }
+
+ public static class MockReactiveWebServer implements EmbeddedWebServer {
+
+ private final int port;
+
+ private HttpHandler httpHandler;
+
+ private Map httpHandlerMap;
+
+ public MockReactiveWebServer(HttpHandler httpHandler, int port) {
+ this.httpHandler = httpHandler;
+ this.port = port;
+ }
+
+ public MockReactiveWebServer(Map httpHandlerMap, int port) {
+ this.httpHandlerMap = httpHandlerMap;
+ this.port = port;
+ }
+
+ public HttpHandler getHttpHandler() {
+ return this.httpHandler;
+ }
+
+ public Map getHttpHandlerMap() {
+ return this.httpHandlerMap;
+ }
+
+ @Override
+ public void start() throws EmbeddedWebServerException {
+
+ }
+
+ @Override
+ public void stop() throws EmbeddedWebServerException {
+
+ }
+
+ @Override
+ public int getPort() {
+ return this.port;
+ }
+
+ }
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfigurationTests.java
new file mode 100644
index 0000000000..9062b9e6d0
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webflux/ReactiveWebServerAutoConfigurationTests.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012-2017 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.autoconfigure.webflux;
+
+import org.hamcrest.Matchers;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+import org.springframework.boot.context.embedded.ReactiveWebApplicationContext;
+import org.springframework.boot.context.embedded.ReactiveWebServerCustomizer;
+import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
+import org.springframework.context.ApplicationContextException;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.server.reactive.HttpHandler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link ReactiveWebServerAutoConfiguration}.
+ *
+ * @author Brian Clozel
+ */
+public class ReactiveWebServerAutoConfigurationTests {
+
+ private ReactiveWebApplicationContext context;
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void createFromConfigClass() {
+ this.context = new ReactiveWebApplicationContext(BaseConfiguration.class);
+
+ assertThat(this.context.getBeansOfType(ReactiveWebServerFactory.class)).hasSize(1);
+ assertThat(this.context.getBeansOfType(ReactiveWebServerCustomizer.class)).hasSize(1);
+ assertThat(this.context.getBeansOfType(DefaultReactiveWebServerCustomizer.class)).hasSize(1);
+ }
+
+ @Test
+ public void missingHttpHandler() {
+ this.thrown.expect(ApplicationContextException.class);
+ this.thrown.expectMessage(Matchers.containsString("missing HttpHandler bean"));
+ this.context = new ReactiveWebApplicationContext(MissingHttpHandlerConfiguration.class);
+ }
+
+ @Test
+ public void multipleHttpHandler() {
+ this.thrown.expect(ApplicationContextException.class);
+ this.thrown.expectMessage(Matchers
+ .containsString("multiple HttpHandler beans : httpHandler,additionalHttpHandler"));
+ this.context = new ReactiveWebApplicationContext(BaseConfiguration.class, TooManyHttpHandlers.class);
+ }
+
+ @Test
+ public void customizeReactiveWebServer() {
+ this.context = new ReactiveWebApplicationContext(BaseConfiguration.class,
+ ReactiveWebServerCustomization.class);
+ MockReactiveWebServerFactory factory = this.context.getBean(MockReactiveWebServerFactory.class);
+ assertThat(factory.getPort()).isEqualTo(9000);
+ }
+
+ @Configuration
+ @Import({MockWebServerAutoConfiguration.class, ReactiveWebServerAutoConfiguration.class})
+ protected static class BaseConfiguration {
+
+ @Bean
+ public HttpHandler httpHandler() {
+ return Mockito.mock(HttpHandler.class);
+ }
+ }
+
+ @Configuration
+ @Import({MockWebServerAutoConfiguration.class, ReactiveWebServerAutoConfiguration.class})
+ protected static class MissingHttpHandlerConfiguration {
+
+ }
+
+ @Configuration
+ protected static class TooManyHttpHandlers {
+
+ @Bean
+ public HttpHandler additionalHttpHandler() {
+ return Mockito.mock(HttpHandler.class);
+ }
+ }
+
+ @Configuration
+ protected static class ReactiveWebServerCustomization {
+
+ @Bean
+ public ReactiveWebServerCustomizer reactiveWebServerCustomizer() {
+ return (server) -> server.setPort(9000);
+ }
+ }
+
+ @Configuration
+ public static class MockWebServerAutoConfiguration {
+
+ @Bean
+ public MockReactiveWebServerFactory mockReactiveWebServerFactory() {
+ return new MockReactiveWebServerFactory();
+ }
+ }
+}
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index 34ef7182fa..e53e99dfff 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -69,6 +69,11 @@
json-simple
true
+