From 328bbaf17fa684b998b6b12db5539b2baeb7d6c4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 3 May 2017 17:06:42 +0100 Subject: [PATCH] Update port file writer to support reactive servers Closes gh-8531 --- .../system/EmbeddedServerPortFileWriter.java | 27 +++++++--- .../GenericReactiveWebApplicationContext.java | 12 +++++ .../ReactiveWebApplicationContext.java | 12 +++++ .../EmbeddedServerPortFileWriterTests.java | 54 +++++++++++++++---- 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/system/EmbeddedServerPortFileWriter.java b/spring-boot/src/main/java/org/springframework/boot/system/EmbeddedServerPortFileWriter.java index 498b6e96c87..386e88776ed 100644 --- a/spring-boot/src/main/java/org/springframework/boot/system/EmbeddedServerPortFileWriter.java +++ b/spring-boot/src/main/java/org/springframework/boot/system/EmbeddedServerPortFileWriter.java @@ -21,12 +21,14 @@ import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; -import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; +import org.springframework.web.context.ConfigurableWebApplicationContext; /** * An {@link ApplicationListener} that saves embedded server port and management port into @@ -40,7 +42,7 @@ import org.springframework.util.StringUtils; * @since 1.4.0 */ public class EmbeddedServerPortFileWriter - implements ApplicationListener { + implements ApplicationListener { private static final String DEFAULT_FILE_NAME = "application.port"; @@ -84,7 +86,7 @@ public class EmbeddedServerPortFileWriter } @Override - public void onApplicationEvent(ServletWebServerInitializedEvent event) { + public void onApplicationEvent(WebServerInitializedEvent event) { File portFile = getPortFile(event.getApplicationContext()); try { String port = String.valueOf(event.getWebServer().getPort()); @@ -100,12 +102,12 @@ public class EmbeddedServerPortFileWriter /** * Return the actual port file that should be written for the given application * context. The default implementation builds a file from the source file and the - * application context namespace. + * application context namespace if available. * @param applicationContext the source application context * @return the file that should be written */ - protected File getPortFile(ServletWebServerApplicationContext applicationContext) { - String contextName = applicationContext.getNamespace(); + protected File getPortFile(ApplicationContext applicationContext) { + String contextName = getContextName(applicationContext); if (StringUtils.isEmpty(contextName)) { return this.file; } @@ -124,6 +126,17 @@ public class EmbeddedServerPortFileWriter return new File(this.file.getParentFile(), name); } + private String getContextName(ApplicationContext applicationContext) { + if (applicationContext instanceof ConfigurableWebApplicationContext) { + return ((ConfigurableWebApplicationContext) applicationContext) + .getNamespace(); + } + if (applicationContext instanceof ReactiveWebApplicationContext) { + return ((ReactiveWebApplicationContext) applicationContext).getNamespace(); + } + return null; + } + private boolean isUpperCase(String name) { for (int i = 0; i < name.length(); i++) { if (Character.isLetter(name.charAt(i)) diff --git a/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/GenericReactiveWebApplicationContext.java b/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/GenericReactiveWebApplicationContext.java index a70578aaf7b..90536727f76 100644 --- a/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/GenericReactiveWebApplicationContext.java +++ b/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/GenericReactiveWebApplicationContext.java @@ -28,6 +28,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext public class GenericReactiveWebApplicationContext extends AnnotationConfigApplicationContext implements ReactiveWebApplicationContext { + private String namespace; + public GenericReactiveWebApplicationContext() { super(); } @@ -36,4 +38,14 @@ public class GenericReactiveWebApplicationContext extends super(annotatedClasses); } + @Override + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + @Override + public String getNamespace() { + return this.namespace; + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebApplicationContext.java b/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebApplicationContext.java index b4d526ec3db..402d64d02d4 100644 --- a/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebApplicationContext.java +++ b/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebApplicationContext.java @@ -26,4 +26,16 @@ import org.springframework.context.ApplicationContext; */ public interface ReactiveWebApplicationContext extends ApplicationContext { + /** + * Set the namespace for this reactive web application context. + * @param namespace the namespace for the context + */ + void setNamespace(String namespace); + + /** + * Return the namespace for this reactive web application context, if any. + * @return the namespace or {@code null} + */ + String getNamespace(); + } diff --git a/spring-boot/src/test/java/org/springframework/boot/system/EmbeddedServerPortFileWriterTests.java b/spring-boot/src/test/java/org/springframework/boot/system/EmbeddedServerPortFileWriterTests.java index ef76a8c0e45..3fef768112a 100644 --- a/spring-boot/src/test/java/org/springframework/boot/system/EmbeddedServerPortFileWriterTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/system/EmbeddedServerPortFileWriterTests.java @@ -20,13 +20,20 @@ import java.io.File; import java.io.FileReader; import java.util.HashSet; import java.util.Set; +import java.util.function.BiFunction; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.boot.web.context.WebServerInitializedEvent; +import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; +import org.springframework.boot.web.reactive.context.ReactiveWebServerInitializedEvent; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent; @@ -44,10 +51,44 @@ import static org.mockito.Mockito.mock; * @author Phillip Webb * @author Andy Wilkinson */ +@RunWith(Parameterized.class) public class EmbeddedServerPortFileWriterTests { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Parameters(name = "{0}") + public static Object[] parameters() { + BiFunction servletEvent = ( + String name, Integer port) -> { + ServletWebServerApplicationContext applicationContext = mock( + ServletWebServerApplicationContext.class); + given(applicationContext.getNamespace()).willReturn(name); + WebServer source = mock(WebServer.class); + given(source.getPort()).willReturn(port); + ServletWebServerInitializedEvent event = new ServletWebServerInitializedEvent( + applicationContext, source); + return event; + }; + BiFunction reactiveEvent = ( + String name, Integer port) -> { + ReactiveWebServerApplicationContext applicationContext = mock( + ReactiveWebServerApplicationContext.class); + given(applicationContext.getNamespace()).willReturn(name); + WebServer source = mock(WebServer.class); + given(source.getPort()).willReturn(port); + return new ReactiveWebServerInitializedEvent(source, applicationContext); + }; + return new Object[] { new Object[] { "Servlet", servletEvent }, + new Object[] { "Reactive", reactiveEvent } }; + } + + private final BiFunction eventFactory; + + public EmbeddedServerPortFileWriterTests(String name, + BiFunction eventFactory) { + this.eventFactory = eventFactory; + } @Before @After @@ -117,15 +158,8 @@ public class EmbeddedServerPortFileWriterTests { assertThat(collectFileNames(file.getParentFile())).contains(managementFile); } - private ServletWebServerInitializedEvent mockEvent(String name, int port) { - ServletWebServerApplicationContext applicationContext = mock( - ServletWebServerApplicationContext.class); - WebServer source = mock(WebServer.class); - given(applicationContext.getNamespace()).willReturn(name); - given(source.getPort()).willReturn(port); - ServletWebServerInitializedEvent event = new ServletWebServerInitializedEvent( - applicationContext, source); - return event; + private WebServerInitializedEvent mockEvent(String name, int port) { + return this.eventFactory.apply(name, port); } private Set collectFileNames(File directory) {