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