From 9b6b663cc7e3ab7a6e4768aee31bb4f2721b78ff Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 21 Jul 2017 22:03:44 +0100 Subject: [PATCH] Throw a PortInUseException when Netty start fails with a BindException Closes gh-8737 --- .../boot/web/embedded/netty/NettyWebServer.java | 13 +++++++++++-- .../AbstractReactiveWebServerFactoryTests.java | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java b/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java index 896f5dd289..6ad516eee4 100644 --- a/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java +++ b/spring-boot/src/main/java/org/springframework/boot/web/embedded/netty/NettyWebServer.java @@ -17,6 +17,8 @@ package org.springframework.boot.web.embedded.netty; import java.net.BindException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -24,6 +26,7 @@ import reactor.ipc.netty.http.HttpResources; import reactor.ipc.netty.http.server.HttpServer; import reactor.ipc.netty.tcp.BlockingNettyContext; +import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServerException; import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; @@ -35,6 +38,7 @@ import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter; * * @author Brian Clozel * @author Madhura Bhave + * @author Andy Wilkinson * @since 2.0.0 */ public class NettyWebServer implements WebServer { @@ -61,7 +65,11 @@ public class NettyWebServer implements WebServer { } catch (Exception ex) { if (findBindException(ex) != null) { - // throw new PortInUseException(); + SocketAddress address = this.reactorServer.options().getAddress(); + if (address instanceof InetSocketAddress) { + throw new PortInUseException( + ((InetSocketAddress) address).getPort()); + } } throw new WebServerException("Unable to start Netty", ex); } @@ -100,7 +108,8 @@ public class NettyWebServer implements WebServer { if (this.nettyContext != null) { this.nettyContext.shutdown(); // temporary fix for gh-9146 - this.nettyContext.getContext().onClose().doOnSuccess(aVoid -> HttpResources.reset()).block(); + this.nettyContext.getContext().onClose() + .doOnSuccess(aVoid -> HttpResources.reset()).block(); this.nettyContext = null; } } diff --git a/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index b3ba0d4cb1..fc39695dd6 100644 --- a/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -25,6 +25,7 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import org.springframework.boot.testsupport.rule.OutputCapture; +import org.springframework.boot.web.server.PortInUseException; import org.springframework.boot.web.server.WebServer; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -37,6 +38,7 @@ import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.equalTo; /** * Base for testing classes that extends {@link AbstractReactiveWebServerFactory}. @@ -102,6 +104,19 @@ public abstract class AbstractReactiveWebServerFactoryTests { assertThat(this.webServer.getPort()).isEqualTo(specificPort); } + @Test + public void portInUseExceptionIsThrownWhenPortIsAlreadyInUse() throws Exception { + AbstractReactiveWebServerFactory factory = getFactory(); + factory.setPort(0); + this.webServer = factory.getWebServer(new EchoHandler()); + this.webServer.start(); + factory.setPort(this.webServer.getPort()); + this.thrown.expect(PortInUseException.class); + this.thrown.expectMessage( + equalTo("Port " + this.webServer.getPort() + " is already in use")); + factory.getWebServer(new EchoHandler()).start(); + } + protected WebClient getWebClient() { return WebClient.create("http://localhost:" + this.webServer.getPort()); }