From: markt true, the default
+ * binds the port on {@link #init()} and unbinds it on {@link #destroy()}.
+ * If set to false the port is bound on {@link #start()} and
+ * unbound on {@link #stop()}.
+ */
+ private boolean bindOnInit = true;
+ public boolean getBindOnInit() { return bindOnInit; }
+ public void setBindOnInit(boolean b) { this.bindOnInit = b; }
+ private BindState bindState = BindState.UNBOUND;
+
+ /**
* Keepalive timeout, if lesser or equal to 0 then soTimeout will be used.
*/
private int keepAliveTimeout = -1;
@@ -503,8 +513,34 @@ public abstract class AbstractEndpoint {
}
- public abstract void init() throws Exception;
- public abstract void start() throws Exception;
+ // ------------------------------------------------------- Lifecycle methods
+
+ /*
+ * NOTE: There is no maintenance of state or checking for valid transitions
+ * within this class other than ensuring that bind/unbind are called in the
+ * right place. It is expected that the calling code will maintain state and
+ * prevent invalid state transitions.
+ */
+
+ public abstract void bind() throws Exception;
+ public abstract void unbind() throws Exception;
+ public abstract void startInternal() throws Exception;
+ public abstract void stopInternal() throws Exception;
+
+ public final void init() throws Exception {
+ if (bindOnInit) {
+ bind();
+ bindState = BindState.BOUND_ON_INIT;
+ }
+ }
+
+ public final void start() throws Exception {
+ if (bindState == BindState.UNBOUND) {
+ bind();
+ bindState = BindState.BOUND_ON_START;
+ }
+ startInternal();
+ }
/**
* Pause the endpoint, which will stop it accepting new connections.
@@ -532,8 +568,21 @@ public abstract class AbstractEndpoint {
}
}
- public abstract void stop() throws Exception;
- public abstract void destroy() throws Exception;
+ public final void stop() throws Exception {
+ stopInternal();
+ if (bindState == BindState.BOUND_ON_START) {
+ unbind();
+ bindState = BindState.UNBOUND;
+ }
+ }
+
+ public final void destroy() throws Exception {
+ if (bindState == BindState.BOUND_ON_INIT) {
+ unbind();
+ bindState = BindState.UNBOUND;
+ }
+ }
+
public String adjustRelativePath(String path, String relativeTo) {
String newPath = path;
diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java
index 994cc886b..393b44eb2 100644
--- a/java/org/apache/tomcat/util/net/AprEndpoint.java
+++ b/java/org/apache/tomcat/util/net/AprEndpoint.java
@@ -365,11 +365,7 @@ public class AprEndpoint extends AbstractEndpoint {
* Initialize the endpoint.
*/
@Override
- public void init()
- throws Exception {
-
- if (initialized)
- return;
+ public void bind() throws Exception {
// Create the root APR memory pool
try {
@@ -518,9 +514,6 @@ public class AprEndpoint extends AbstractEndpoint {
// For now, sendfile is not supported with SSL
useSendfile = false;
}
-
- initialized = true;
-
}
@@ -528,12 +521,8 @@ public class AprEndpoint extends AbstractEndpoint {
* Start the APR endpoint, creating acceptor, poller and sendfile threads.
*/
@Override
- public void start()
- throws Exception {
- // Initialize socket if not done before
- if (!initialized) {
- init();
- }
+ public void startInternal() throws Exception {
+
if (!running) {
running = true;
paused = false;
@@ -602,7 +591,7 @@ public class AprEndpoint extends AbstractEndpoint {
* Stop the endpoint. This will cause all processing threads to stop.
*/
@Override
- public void stop() {
+ public void stopInternal() {
if (!paused) {
pause();
}
@@ -665,7 +654,7 @@ public class AprEndpoint extends AbstractEndpoint {
* Deallocate APR memory pools, and close server socket.
*/
@Override
- public void destroy() throws Exception {
+ public void unbind() throws Exception {
if (running) {
stop();
}
@@ -691,8 +680,6 @@ public class AprEndpoint extends AbstractEndpoint {
}
handler.recycle();
-
- initialized = false;
}
diff --git a/java/org/apache/tomcat/util/net/JIoEndpoint.java b/java/org/apache/tomcat/util/net/JIoEndpoint.java
index 1ca3c923b..38893e613 100644
--- a/java/org/apache/tomcat/util/net/JIoEndpoint.java
+++ b/java/org/apache/tomcat/util/net/JIoEndpoint.java
@@ -324,12 +324,8 @@ public class JIoEndpoint extends AbstractEndpoint {
// -------------------- Public methods --------------------
@Override
- public void init()
- throws Exception {
+ public void bind() throws Exception {
- if (initialized)
- return;
-
// Initialize thread count defaults for acceptor
if (acceptorThreadCount == 0) {
acceptorThreadCount = 1;
@@ -365,15 +361,11 @@ public class JIoEndpoint extends AbstractEndpoint {
}
}
- initialized = true;
}
@Override
- public void start() throws Exception {
- // Initialize socket if not done before
- if (!initialized) {
- init();
- }
+ public void startInternal() throws Exception {
+
if (!running) {
running = true;
paused = false;
@@ -402,7 +394,7 @@ public class JIoEndpoint extends AbstractEndpoint {
}
@Override
- public void stop() {
+ public void stopInternal() {
if (!paused) {
pause();
}
@@ -417,7 +409,7 @@ public class JIoEndpoint extends AbstractEndpoint {
* Deallocate APR memory pools, and close server socket.
*/
@Override
- public void destroy() throws Exception {
+ public void unbind() throws Exception {
if (running) {
stop();
}
@@ -431,7 +423,6 @@ public class JIoEndpoint extends AbstractEndpoint {
serverSocket = null;
}
handler.recycle();
- initialized = false ;
}
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index 11d557ae8..c48101ec7 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -455,11 +455,7 @@ public class NioEndpoint extends AbstractEndpoint {
* Initialize the endpoint.
*/
@Override
- public void init()
- throws Exception {
-
- if (initialized)
- return;
+ public void bind() throws Exception {
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
@@ -545,8 +541,6 @@ public class NioEndpoint extends AbstractEndpoint {
if (oomParachute>0) reclaimParachute(true);
selectorPool.open();
- initialized = true;
-
}
public KeyManager[] wrap(KeyManager[] managers) {
@@ -567,12 +561,8 @@ public class NioEndpoint extends AbstractEndpoint {
* Start the NIO endpoint, creating acceptor, poller threads.
*/
@Override
- public void start()
- throws Exception {
- // Initialize socket if not done before
- if (!initialized) {
- init();
- }
+ public void startInternal() throws Exception {
+
if (!running) {
running = true;
paused = false;
@@ -607,7 +597,7 @@ public class NioEndpoint extends AbstractEndpoint {
* Stop the endpoint. This will cause all processing threads to stop.
*/
@Override
- public void stop() {
+ public void stopInternal() {
if (!paused) {
pause();
}
@@ -634,7 +624,7 @@ public class NioEndpoint extends AbstractEndpoint {
* Deallocate NIO memory pools, and close server socket.
*/
@Override
- public void destroy() throws Exception {
+ public void unbind() throws Exception {
if (log.isDebugEnabled()) {
log.debug("Destroy initiated for "+new InetSocketAddress(getAddress(),getPort()));
}
@@ -646,7 +636,6 @@ public class NioEndpoint extends AbstractEndpoint {
serverSock.close();
serverSock = null;
sslContext = null;
- initialized = false;
releaseCaches();
selectorPool.close();
if (log.isDebugEnabled()) {
diff --git a/test/org/apache/tomcat/util/net/TestXxxEndpoint.java b/test/org/apache/tomcat/util/net/TestXxxEndpoint.java
index ab3c59503..d09632b1e 100644
--- a/test/org/apache/tomcat/util/net/TestXxxEndpoint.java
+++ b/test/org/apache/tomcat/util/net/TestXxxEndpoint.java
@@ -20,6 +20,7 @@ package org.apache.tomcat.util.net;
import java.io.File;
import java.net.ServerSocket;
+import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
@@ -29,7 +30,7 @@ import org.apache.catalina.startup.TomcatBaseTest;
*/
public class TestXxxEndpoint extends TomcatBaseTest {
- public void disbaletestStartStop() throws Exception {
+ public void testStartStopBindOnInit() throws Exception {
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
@@ -39,13 +40,52 @@ public class TestXxxEndpoint extends TomcatBaseTest {
tomcat.start();
tomcat.getConnector().stop();
- // This will throw an exception if the socket is not released
- ServerSocket socket = new ServerSocket(port);
- socket.close();
+ // This will should throw an Exception
+ Exception e = null;
+ ServerSocket s = null;
+ try {
+ s = new ServerSocket(port);
+ } catch (Exception e1) {
+ e = e1;
+ } finally {
+ if (s != null) {
+ try {
+ s.close();
+ } catch (Exception e2) { /* Ignore */ }
+ }
+ }
+ assertNotNull(e);
tomcat.getConnector().start();
}
-
- public void testDummy() throws Exception {
- // NO-OP
+
+ public void testStartStopBindOnStart() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+ Connector c = tomcat.getConnector();
+ c.setProperty("bindOnInit", "false");
+
+ File appDir = new File(getBuildDirectory(), "webapps/examples");
+ tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
+
+ int port = getPort();
+
+ tomcat.start();
+
+ tomcat.getConnector().stop();
+ // This should not throw an Exception
+ Exception e = null;
+ ServerSocket s = null;
+ try {
+ s = new ServerSocket(port);
+ } catch (Exception e1) {
+ e = e1;
+ } finally {
+ if (s != null) {
+ try {
+ s.close();
+ } catch (Exception e2) { /* Ignore */ }
+ }
+ }
+ assertNull(e);
+ tomcat.getConnector().start();
}
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 957e0df71..4dbeeb14f 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -130,6 +130,16 @@
Connector.init() and released on
+ Connector.destroy() as per the current behaviour but this
+ can be changed so that the socket is bound on
+ Connector.start() and released on
+ Connector.stop(). This fix also includes further Lifecycle
+ refactoring for Connectors and associated components. (markt)
+
Controls when the socket used by the connector is bound. By default it
+ is bound when the connector is initiated and unbund when the connector is
+ destroyed. If set to false, the socket will be bound when the
+ connector is started and unbound when it is stopped.
The value is a comma separated list of MIME types for which HTTP compression may be used.