Skip to content

Commit c420249

Browse files
committed
Detect startup failures in additional Tomcat connectors
Previously, only the state of the primary connector was checked when verifying that the embedded Tomcat instance has started successfully. This commit updates the verification logic to examine all of the service's connectors, thereby also detecting startup failures of any additional connectors the have been configured. A check on the primary connector's state has been removed from initialize as, at this stage, its state will always be NEW. Fixes gh-1591
1 parent cf22e28 commit c420249

File tree

2 files changed

+86
-6
lines changed

2 files changed

+86
-6
lines changed

spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,6 @@ private synchronized void initialize() throws EmbeddedServletContainerException
9090
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
9191
// blocking non-daemon to stop immediate shutdown
9292
startDaemonAwaitThread();
93-
94-
if (LifecycleState.FAILED.equals(this.tomcat.getConnector().getState())) {
95-
this.tomcat.stop();
96-
throw new IllegalStateException("Tomcat connector in failed state");
97-
}
9893
}
9994
catch (Exception ex) {
10095
throw new EmbeddedServletContainerException(
@@ -151,13 +146,24 @@ public void start() throws EmbeddedServletContainerException {
151146
if (connector != null && this.autoStart) {
152147
startConnector(connector);
153148
}
149+
154150
// Ensure process isn't left running if it actually failed to start
155-
if (LifecycleState.FAILED.equals(this.tomcat.getConnector().getState())) {
151+
152+
if (connectorsHaveFailedToStart()) {
156153
stopSilently();
157154
throw new IllegalStateException("Tomcat connector in failed state");
158155
}
159156
}
160157

158+
private boolean connectorsHaveFailedToStart() {
159+
for (Connector connector : this.tomcat.getService().findConnectors()) {
160+
if (LifecycleState.FAILED.equals(connector.getState())) {
161+
return true;
162+
}
163+
}
164+
return false;
165+
}
166+
161167
private void stopSilently() {
162168
try {
163169
this.tomcat.stop();

spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package org.springframework.boot.context.embedded.tomcat;
1818

19+
import java.io.IOException;
20+
import java.net.InetSocketAddress;
21+
import java.net.ServerSocket;
22+
import java.net.UnknownHostException;
1923
import java.util.Arrays;
2024
import java.util.Map;
2125
import java.util.concurrent.TimeUnit;
@@ -39,6 +43,7 @@
3943
import static org.junit.Assert.assertEquals;
4044
import static org.junit.Assert.assertFalse;
4145
import static org.junit.Assert.assertThat;
46+
import static org.junit.Assert.fail;
4247
import static org.mockito.BDDMockito.given;
4348
import static org.mockito.Matchers.any;
4449
import static org.mockito.Matchers.anyObject;
@@ -248,6 +253,63 @@ public void sslCiphersConfiguration() throws Exception {
248253
assertThat(jsseProtocol.getCiphers(), equalTo("ALPHA,BRAVO,CHARLIE"));
249254
}
250255

256+
@Test
257+
public void primaryConnectorPortClashThrowsIllegalStateException()
258+
throws InterruptedException, UnknownHostException, IOException {
259+
final int port = SocketUtils.findAvailableTcpPort(40000);
260+
261+
doWithBlockedPort(port, new Runnable() {
262+
263+
@Override
264+
public void run() {
265+
TomcatEmbeddedServletContainerFactory factory = getFactory();
266+
factory.setPort(port);
267+
268+
try {
269+
TomcatEmbeddedServletContainerFactoryTests.this.container = factory
270+
.getEmbeddedServletContainer();
271+
TomcatEmbeddedServletContainerFactoryTests.this.container.start();
272+
fail();
273+
}
274+
catch (IllegalStateException ex) {
275+
276+
}
277+
}
278+
279+
});
280+
281+
}
282+
283+
@Test
284+
public void additionalConnectorPortClashThrowsIllegalStateException()
285+
throws InterruptedException, UnknownHostException, IOException {
286+
final int port = SocketUtils.findAvailableTcpPort(40000);
287+
288+
doWithBlockedPort(port, new Runnable() {
289+
290+
@Override
291+
public void run() {
292+
TomcatEmbeddedServletContainerFactory factory = getFactory();
293+
Connector connector = new Connector(
294+
"org.apache.coyote.http11.Http11NioProtocol");
295+
connector.setPort(port);
296+
factory.addAdditionalTomcatConnectors(connector);
297+
298+
try {
299+
TomcatEmbeddedServletContainerFactoryTests.this.container = factory
300+
.getEmbeddedServletContainer();
301+
TomcatEmbeddedServletContainerFactoryTests.this.container.start();
302+
fail();
303+
}
304+
catch (IllegalStateException ex) {
305+
306+
}
307+
}
308+
309+
});
310+
311+
}
312+
251313
private void assertTimeout(TomcatEmbeddedServletContainerFactory factory, int expected) {
252314
Tomcat tomcat = getTomcat(factory);
253315
Context context = (Context) tomcat.getHost().findChildren()[0];
@@ -259,4 +321,16 @@ private Tomcat getTomcat(TomcatEmbeddedServletContainerFactory factory) {
259321
return ((TomcatEmbeddedServletContainer) this.container).getTomcat();
260322
}
261323

324+
private void doWithBlockedPort(final int port, Runnable action) throws IOException {
325+
ServerSocket serverSocket = new ServerSocket();
326+
serverSocket.bind(new InetSocketAddress(port));
327+
328+
try {
329+
action.run();
330+
}
331+
finally {
332+
serverSocket.close();
333+
}
334+
}
335+
262336
}

0 commit comments

Comments
 (0)