Author: kkolinko
Date: Wed Feb  2 02:45:46 2011
New Revision: 1066310

URL: http://svn.apache.org/viewvc?rev=1066310&view=rev
Log:
Fix http://issues.apache.org/bugzilla/show_bug.cgi?id=50673
Improve Catalina shutdown when running as a service. Do not call System.exit().

Modified:
    tomcat/trunk/java/org/apache/catalina/core/StandardServer.java
    tomcat/trunk/java/org/apache/catalina/startup/Catalina.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardServer.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardServer.java?rev=1066310&r1=1066309&r2=1066310&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardServer.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardServer.java Wed Feb  2 
02:45:46 2011
@@ -151,12 +151,22 @@ public final class StandardServer extend
      */
     protected PropertyChangeSupport support = new PropertyChangeSupport(this);
 
-    private boolean stopAwait = false;
+    private volatile boolean stopAwait = false;
     
     private Catalina catalina = null;
 
     private ClassLoader parentClassLoader = null;
 
+    /**
+     * Thread that currently is inside our await() method.
+     */
+    private volatile Thread awaitThread = null;
+
+    /**
+     * Server socket that is used to wait for the shutdown command.
+     */
+    private volatile ServerSocket awaitSocket = null;
+
     // ------------------------------------------------------------- Properties
 
 
@@ -358,6 +368,24 @@ public final class StandardServer extend
 
     public void stopAwait() {
         stopAwait=true;
+        Thread t = awaitThread;
+        if (t != null) {
+            ServerSocket s = awaitSocket;
+            if (s != null) {
+                awaitSocket = null;
+                try {
+                    s.close();
+                } catch (IOException e) {
+                    // Ignored
+                }
+            }
+            t.interrupt();
+            try {
+                t.join(1000);
+            } catch (InterruptedException e) {
+                // Ignored
+            }
+        }
     }
 
     /**
@@ -373,94 +401,117 @@ public final class StandardServer extend
             return;
         }
         if( port==-1 ) {
-            while( true ) {
-                try {
-                    Thread.sleep( 10000 );
-                } catch( InterruptedException ex ) {
+            try {
+                awaitThread = Thread.currentThread();
+                while(!stopAwait) {
+                    try {
+                        Thread.sleep( 10000 );
+                    } catch( InterruptedException ex ) {
+                    }
                 }
-                if( stopAwait ) return;
+            } finally {
+                awaitThread = null;
             }
+            return;
         }
-        
+
         // Set up a server socket to wait on
-        ServerSocket serverSocket = null;
         try {
-            serverSocket =
-                new ServerSocket(port, 1,
-                                 InetAddress.getByName(address));
+            awaitSocket = new ServerSocket(port, 1,
+                    InetAddress.getByName(address));
         } catch (IOException e) {
             log.error("StandardServer.await: create[" + address
                                + ":" + port
                                + "]: ", e);
-            System.exit(1);
+            return;
         }
 
-        // Loop waiting for a connection and a valid command
-        while (true) {
+        try {
+            awaitThread = Thread.currentThread();
 
-            // Wait for the next connection
-            Socket socket = null;
-            InputStream stream = null;
-            try {
-                socket = serverSocket.accept();
-                socket.setSoTimeout(10 * 1000);  // Ten seconds
-                stream = socket.getInputStream();
-            } catch (AccessControlException ace) {
-                log.warn("StandardServer.accept security exception: "
-                                   + ace.getMessage(), ace);
-                continue;
-            } catch (IOException e) {
-                log.error("StandardServer.await: accept: ", e);
-                System.exit(1);
-            }
-
-            // Read a set of characters from the socket
-            StringBuilder command = new StringBuilder();
-            int expected = 1024; // Cut off to avoid DoS attack
-            while (expected < shutdown.length()) {
-                if (random == null)
-                    random = new Random();
-                expected += (random.nextInt() % 1024);
-            }
-            while (expected > 0) {
-                int ch = -1;
+            // Loop waiting for a connection and a valid command
+            while (!stopAwait) {
+                ServerSocket serverSocket = awaitSocket;
+                if (serverSocket == null) {
+                    break;
+                }
+    
+                // Wait for the next connection
+                Socket socket = null;
+                StringBuilder command = new StringBuilder();
                 try {
-                    ch = stream.read();
-                } catch (IOException e) {
-                    log.warn("StandardServer.await: read: ", e);
-                    ch = -1;
+                    InputStream stream;
+                    try {
+                        socket = serverSocket.accept();
+                        socket.setSoTimeout(10 * 1000);  // Ten seconds
+                        stream = socket.getInputStream();
+                    } catch (AccessControlException ace) {
+                        log.warn("StandardServer.accept security exception: "
+                                + ace.getMessage(), ace);
+                        continue;
+                    } catch (IOException e) {
+                        if (stopAwait) {
+                            // Wait was aborted with socket.close()
+                            break;
+                        }
+                        log.error("StandardServer.await: accept: ", e);
+                        break;
+                    }
+
+                    // Read a set of characters from the socket
+                    int expected = 1024; // Cut off to avoid DoS attack
+                    while (expected < shutdown.length()) {
+                        if (random == null)
+                            random = new Random();
+                        expected += (random.nextInt() % 1024);
+                    }
+                    while (expected > 0) {
+                        int ch = -1;
+                        try {
+                            ch = stream.read();
+                        } catch (IOException e) {
+                            log.warn("StandardServer.await: read: ", e);
+                            ch = -1;
+                        }
+                        if (ch < 32)  // Control character or EOF terminates 
loop
+                            break;
+                        command.append((char) ch);
+                        expected--;
+                    }
+                } finally {
+                    // Close the socket now that we are done with it
+                    try {
+                        if (socket != null) {
+                            socket.close();
+                        }
+                    } catch (IOException e) {
+                        // Ignore
+                    }
                 }
-                if (ch < 32)  // Control character or EOF terminates loop
+
+                // Match against our command string
+                boolean match = command.toString().equals(shutdown);
+                if (match) {
+                    log.info(sm.getString("standardServer.shutdownViaPort"));
                     break;
-                command.append((char) ch);
-                expected--;
-            }
+                } else
+                    log.warn("StandardServer.await: Invalid command '"
+                            + command.toString() + "' received");
+            }
+        } finally {
+            ServerSocket serverSocket = awaitSocket;
+            awaitThread = null;
+            awaitSocket = null;
 
-            // Close the socket now that we are done with it
-            try {
-                socket.close();
-            } catch (IOException e) {
-                // Ignore
+            // Close the server socket and return
+            if (serverSocket != null) {
+                try {
+                    serverSocket.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
             }
-
-            // Match against our command string
-            boolean match = command.toString().equals(shutdown);
-            if (match) {
-                log.info(sm.getString("standardServer.shutdownViaPort"));
-                break;
-            } else
-                log.warn("StandardServer.await: Invalid command '" +
-                                   command.toString() + "' received");
-
         }
-
-        // Close the server socket and return
-        try {
-            serverSocket.close();
-        } catch (IOException e) {
-            // Ignore
-        }
-
     }
 
 
@@ -693,7 +744,7 @@ public final class StandardServer extend
             services[i].stop();
         }
 
-        if (port == -1)
+        if (awaitThread != null)
             stopAwait();
 
     }

Modified: tomcat/trunk/java/org/apache/catalina/startup/Catalina.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Catalina.java?rev=1066310&r1=1066309&r2=1066310&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/Catalina.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/Catalina.java Wed Feb  2 
02:45:46 2011
@@ -33,6 +33,7 @@ import java.util.logging.LogManager;
 import org.apache.catalina.Container;
 import org.apache.catalina.Globals;
 import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleState;
 import org.apache.catalina.Server;
 import org.apache.catalina.core.StandardServer;
 import org.apache.catalina.security.SecurityConfig;
@@ -420,7 +421,8 @@ public class Catalina {
             arguments(arguments);
         }
 
-        if( getServer() == null ) {
+        Server s = getServer();
+        if( s == null ) {
             // Create and execute our Digester
             Digester digester = createStopDigester();
             
digester.setClassLoader(Thread.currentThread().getContextClassLoader());
@@ -439,15 +441,19 @@ public class Catalina {
             }
         } else {
             // Server object already present. Must be running as a service
-            // Shutdown hook will take care of clean-up
-            System.exit(0);
+            try {
+                s.stop();
+            } catch (LifecycleException e) {
+                log.error("Catalina.stop: ", e);
+            }
+            return;
         }
 
         // Stop the existing server
+        s = getServer();
         try {
-            if (getServer().getPort()>0) {
-                Socket socket = new Socket(getServer().getAddress(),
-                        getServer().getPort());
+            if (s.getPort()>0) {
+                Socket socket = new Socket(s.getAddress(), s.getPort());
                 OutputStream stream = socket.getOutputStream();
                 String shutdown = getServer().getShutdown();
                 for (int i = 0; i < shutdown.length(); i++)
@@ -678,7 +684,14 @@ public class Catalina {
 
         // Shut down the server
         try {
-            getServer().stop();
+            Server s = getServer();
+            LifecycleState state = s.getState();
+            if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
+                    && LifecycleState.DESTROYED.compareTo(state) >= 0) {
+                // Nothing to do. stop() was already called
+            } else {
+                s.stop();
+            }
         } catch (LifecycleException e) {
             log.error("Catalina.stop", e);
         }

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1066310&r1=1066309&r2=1066310&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed Feb  2 02:45:46 2011
@@ -109,9 +109,13 @@
         created on demand. (markt)
       </fix>
       <fix>
-        <bug>50683</bug>: Ensure annotations are scanned when upackWars is set
-        to <code>false</code> in the Host where a web application is deployed.
-        (markt)
+        <bug>50673</bug>: Improve Catalina shutdown when running as a service.
+        Do not call System.exit(). (kkolinko)
+      </fix>
+      <fix>
+        <bug>50683</bug>: Ensure annotations are scanned when
+        <code>unpackWARs</code> is set to <code>false</code> in the Host
+        where a web application is deployed. (markt)
       </fix>
       <fix>
         Improve HTTP specification compliance in support of



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to