diff options
author | Jan Bartel | 2014-08-01 02:43:04 +0000 |
---|---|---|
committer | Jan Bartel | 2014-08-01 02:44:30 +0000 |
commit | 75c92bf76ae8e9be26a341fac1c01201ec706973 (patch) | |
tree | 1f523cb0cef181b38a9116484777b09b7c42fe0f /jetty-server | |
parent | f970ffc0acbdd536280367b052e5955c20b1057c (diff) | |
download | org.eclipse.jetty.project-75c92bf76ae8e9be26a341fac1c01201ec706973.tar.gz org.eclipse.jetty.project-75c92bf76ae8e9be26a341fac1c01201ec706973.tar.xz org.eclipse.jetty.project-75c92bf76ae8e9be26a341fac1c01201ec706973.zip |
438500 Odd NoClassDef errors when shutting down the jetty-maven-plugin via the stop goal
Diffstat (limited to 'jetty-server')
3 files changed, 301 insertions, 31 deletions
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index ce4bdd9097..38cea332fb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.server; -import java.awt.geom.PathIterator; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.InetAddress; @@ -54,7 +53,6 @@ import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.URIUtil; -import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; @@ -145,7 +143,8 @@ public class Server extends HandlerWrapper implements Attributes { return _stopAtShutdown; } - + + /* ------------------------------------------------------------ */ /** * Set a graceful stop time. @@ -313,11 +312,16 @@ public class Server extends HandlerWrapper implements Attributes @Override protected void doStart() throws Exception { + //If the Server should be stopped when the jvm exits, register + //with the shutdown handler thread. if (getStopAtShutdown()) - { ShutdownThread.register(this); - } + //Register the Server with the handler thread for receiving + //remote stop commands + ShutdownMonitor.register(this); + + //Start a thread waiting to receive "stop" commands. ShutdownMonitor.getInstance().start(); // initialize LOG.info("jetty-" + getVersion()); @@ -455,6 +459,11 @@ public class Server extends HandlerWrapper implements Attributes if (getStopAtShutdown()) ShutdownThread.deregister(this); + + //Unregister the Server with the handler thread for receiving + //remote stop commands as we are stopped already + ShutdownMonitor.deregister(this); + mex.ifExceptionThrow(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java index 38b866574d..861c019888 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java @@ -26,8 +26,15 @@ import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; import java.util.Properties; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import org.eclipse.jetty.util.component.Destroyable; +import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.ShutdownThread; /** @@ -42,6 +49,8 @@ import org.eclipse.jetty.util.thread.ShutdownThread; */ public class ShutdownMonitor { + private final Set<LifeCycle> _lifeCycles = new CopyOnWriteArraySet<LifeCycle>(); + // Implementation of safe lazy init, using Initialization on Demand Holder technique. static class Holder { @@ -52,6 +61,26 @@ public class ShutdownMonitor { return Holder.instance; } + + /* ------------------------------------------------------------ */ + public static synchronized void register(LifeCycle... lifeCycles) + { + getInstance()._lifeCycles.addAll(Arrays.asList(lifeCycles)); + } + + + /* ------------------------------------------------------------ */ + public static synchronized void deregister(LifeCycle lifeCycle) + { + getInstance()._lifeCycles.remove(lifeCycle); + } + + /* ------------------------------------------------------------ */ + public static synchronized boolean isRegistered(LifeCycle lifeCycle) + { + return getInstance()._lifeCycles.contains(lifeCycle); + } + /** * ShutdownMonitorRunnable @@ -95,30 +124,64 @@ public class ShutdownMonitor String cmd = lin.readLine(); debug("command=%s",cmd); - if ("stop".equals(cmd)) + if ("stop".equalsIgnoreCase(cmd)) //historic, for backward compatibility { - // Graceful Shutdown - debug("Issuing graceful shutdown.."); - ShutdownThread.getInstance().run(); - - //Stop accepting any more - close(serverSocket); - serverSocket = null; + //Stop the lifecycles, only if they are registered with the ShutdownThread, only destroying if vm is exiting + debug("Issuing stop..."); - //Shutdown input from client - shutdownInput(socket); + for (LifeCycle l:_lifeCycles) + { + try + { + if (l.isStarted() && ShutdownThread.isRegistered(l)) + { + l.stop(); + } + + if ((l instanceof Destroyable) && exitVm) + ((Destroyable)l).destroy(); + } + catch (Exception e) + { + debug(e); + } + } + + //Stop accepting any more commands + stopInput(socket); // Reply to client debug("Informing client that we are stopped."); - out.write("Stopped\r\n".getBytes(StandardCharsets.UTF_8)); - out.flush(); + informClient(out, "Stopped\r\n"); + + //Stop the output and close the monitor socket + stopOutput(socket); - // Shutdown Monitor - socket.shutdownOutput(); - close(socket); - socket = null; - debug("Shutting down monitor"); + if (exitVm) + { + // Kill JVM + debug("Killing JVM"); + System.exit(0); + } + } + else if ("forcestop".equalsIgnoreCase(cmd)) + { + debug("Issuing force stop..."); + + //Ensure that objects are stopped, destroyed only if vm is forcibly exiting + stopLifeCycles(exitVm); + + //Stop accepting any more commands + stopInput(socket); + + // Reply to client + debug("Informing client that we are stopped."); + informClient(out, "Stopped\r\n"); + //Stop the output and close the monitor socket + stopOutput(socket); + + //Honour any pre-setup config to stop the jvm when this command is given if (exitVm) { // Kill JVM @@ -126,11 +189,34 @@ public class ShutdownMonitor System.exit(0); } } - else if ("status".equals(cmd)) + else if ("stopexit".equalsIgnoreCase(cmd)) + { + debug("Issuing stop and exit..."); + //Make sure that objects registered with the shutdown thread will be stopped + stopLifeCycles(true); + + //Stop accepting any more input + stopInput(socket); + + // Reply to client + debug("Informing client that we are stopped."); + informClient(out, "Stopped\r\n"); + + //Stop the output and close the monitor socket + stopOutput(socket); + + debug("Killing JVM"); + System.exit(0); + } + else if ("exit".equalsIgnoreCase(cmd)) + { + debug("Killing JVM"); + System.exit(0); + } + else if ("status".equalsIgnoreCase(cmd)) { // Reply to client - out.write("OK\r\n".getBytes(StandardCharsets.UTF_8)); - out.flush(); + informClient(out, "OK\r\n"); } } catch (Exception e) @@ -146,6 +232,57 @@ public class ShutdownMonitor } } + public void stopInput (Socket socket) + { + //Stop accepting any more input + close(serverSocket); + serverSocket = null; + //Shutdown input from client + shutdownInput(socket); + } + + public void stopOutput (Socket socket) throws IOException + { + socket.shutdownOutput(); + close(socket); + socket = null; + debug("Shutting down monitor"); + serverSocket = null; + } + + public void informClient (OutputStream out, String message) throws IOException + { + out.write(message.getBytes(StandardCharsets.UTF_8)); + out.flush(); + } + + /** + * Stop the registered lifecycles, optionally + * calling destroy on them. + * + * @param destroy + */ + public void stopLifeCycles (boolean destroy) + { + for (LifeCycle l:_lifeCycles) + { + try + { + if (l.isStarted()) + { + l.stop(); + } + + if ((l instanceof Destroyable) && destroy) + ((Destroyable)l).destroy(); + } + catch (Exception e) + { + debug(e); + } + } + } + public void startListenSocket() { if (port < 0) @@ -309,6 +446,9 @@ public class ShutdownMonitor this.DEBUG = flag; } + /** + * @param exitVm + */ public void setExitVm(boolean exitVm) { synchronized (this) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java index 0b02ee1b8a..0f523967bb 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java @@ -28,6 +28,7 @@ import java.net.InetAddress; import java.net.Socket; import java.util.concurrent.TimeUnit; +import org.eclipse.jetty.util.thread.ShutdownThread; import org.junit.Test; /** @@ -35,8 +36,34 @@ import org.junit.Test; */ public class ShutdownMonitorTest { + public class TestableServer extends Server + { + boolean destroyed = false; + boolean stopped = false; + @Override + protected void doStop() throws Exception + { + stopped = true; + super.doStop(); + } + @Override + public void destroy() + { + destroyed = true; + super.destroy(); + } + @Override + protected void doStart() throws Exception + { + stopped = false; + destroyed = false; + super.doStart(); + } + } + + @Test - public void testShutdown() throws Exception + public void testShutdownMonitor() throws Exception { // test port and key assignment ShutdownMonitor.getInstance().setPort(0); @@ -48,7 +75,7 @@ public class ShutdownMonitorTest // try starting a 2nd time (should be ignored) ShutdownMonitor.getInstance().start(); - stop(port,key,true); + stop("stop", port,key,true); assertTrue(!ShutdownMonitor.getInstance().isAlive()); // should be able to change port and key because it is stopped @@ -60,19 +87,113 @@ public class ShutdownMonitorTest port = ShutdownMonitor.getInstance().getPort(); assertTrue(ShutdownMonitor.getInstance().isAlive()); - stop(port,key,true); + stop("stop", port,key,true); + assertTrue(!ShutdownMonitor.getInstance().isAlive()); + } + + + @Test + public void testForceStopCommand() throws Exception + { + //create a testable Server with stop(), destroy() overridden to instrument + //start server + //call "forcestop" and check that server stopped but not destroyed + // test port and key assignment + System.setProperty("DEBUG", "true"); + ShutdownMonitor.getInstance().setPort(0); + TestableServer server = new TestableServer(); + server.start(); + + //shouldn't be registered for shutdown on jvm + assertTrue(!ShutdownThread.isRegistered(server)); + assertTrue(ShutdownMonitor.isRegistered(server)); + + String key = ShutdownMonitor.getInstance().getKey(); + int port = ShutdownMonitor.getInstance().getPort(); + + stop("forcestop", port,key,true); + + assertTrue(!ShutdownMonitor.getInstance().isAlive()); + assertTrue(server.stopped); + assertTrue(!server.destroyed); + assertTrue(!ShutdownThread.isRegistered(server)); + assertTrue(!ShutdownMonitor.isRegistered(server)); + } + + @Test + public void testOldStopCommandWithStopOnShutdownTrue() throws Exception + { + + //create a testable Server with stop(), destroy() overridden to instrument + //call server.setStopAtShudown(true); + //start server + //call "stop" and check that server stopped but not destroyed + + //stop server + + //call server.setStopAtShutdown(false); + //start server + //call "stop" and check that the server is not stopped and not destroyed + System.setProperty("DEBUG", "true"); + ShutdownMonitor.getInstance().setExitVm(false); + + ShutdownMonitor.getInstance().setPort(0); + TestableServer server = new TestableServer(); + server.setStopAtShutdown(true); + server.start(); + + //should be registered for shutdown on exit + assertTrue(ShutdownThread.isRegistered(server)); + assertTrue(ShutdownMonitor.isRegistered(server)); + + String key = ShutdownMonitor.getInstance().getKey(); + int port = ShutdownMonitor.getInstance().getPort(); + + stop("stop", port, key, true); + assertTrue(!ShutdownMonitor.getInstance().isAlive()); + assertTrue(server.stopped); + assertTrue(!server.destroyed); + assertTrue(!ShutdownThread.isRegistered(server)); + assertTrue(!ShutdownMonitor.isRegistered(server)); + } + + @Test + public void testOldStopCommandWithStopOnShutdownFalse() throws Exception + { + //change so stopatshutdown is false, so stop does nothing in this case (as exitVm is false otherwise we couldn't run test) + ShutdownMonitor.getInstance().setExitVm(false); + System.setProperty("DEBUG", "true"); + ShutdownMonitor.getInstance().setPort(0); + TestableServer server = new TestableServer(); + server.setStopAtShutdown(false); + server.start(); + + assertTrue(!ShutdownThread.isRegistered(server)); + assertTrue(ShutdownMonitor.isRegistered(server)); + + String key = ShutdownMonitor.getInstance().getKey(); + int port = ShutdownMonitor.getInstance().getPort(); + + stop ("stop", port, key, true); assertTrue(!ShutdownMonitor.getInstance().isAlive()); + assertTrue(!server.stopped); + assertTrue(!server.destroyed); + assertTrue(!ShutdownThread.isRegistered(server)); + assertTrue(ShutdownMonitor.isRegistered(server)); } + + + - public void stop(int port, String key, boolean check) throws Exception + public void stop(String command, int port, String key, boolean check) throws Exception { - System.out.printf("Attempting stop to localhost:%d (%b)%n",port,check); + System.out.printf("Attempting to send "+command+" to localhost:%d (%b)%n",port,check); try (Socket s = new Socket(InetAddress.getByName("127.0.0.1"),port)) { // send stop command try (OutputStream out = s.getOutputStream()) { - out.write((key + "\r\nstop\r\n").getBytes()); + out.write((key + "\r\n"+command+"\r\n").getBytes()); out.flush(); if (check) |