Bug 391623 - Add option to --stop to wait for target jetty to stop
* Reworked ShutdownMonitor to better support multiple servers + jetty-maven-plugin requirements.
This commit is contained in:
parent
7202631515
commit
b65973afdd
|
@ -263,7 +263,7 @@ public class Server extends HandlerWrapper implements Attributes
|
||||||
{
|
{
|
||||||
if (getStopAtShutdown()) {
|
if (getStopAtShutdown()) {
|
||||||
ShutdownThread.register(this);
|
ShutdownThread.register(this);
|
||||||
ShutdownMonitor.getInstance(); // initialize
|
ShutdownMonitor.getInstance().start(); // initialize
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.info("jetty-"+__version);
|
LOG.info("jetty-"+__version);
|
||||||
|
|
|
@ -33,8 +33,8 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
/**
|
/**
|
||||||
* Shutdown/Stop Monitor thread.
|
* Shutdown/Stop Monitor thread.
|
||||||
* <p>
|
* <p>
|
||||||
* This thread listens on the port specified by the STOP.PORT system parameter (defaults to -1 for not listening) for
|
* This thread listens on the port specified by the STOP.PORT system parameter (defaults to -1 for not listening) for request authenticated with the key given
|
||||||
* request authenticated with the key given by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
|
* by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
|
||||||
* <p>
|
* <p>
|
||||||
* If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout.
|
* If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -42,83 +42,83 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
*/
|
*/
|
||||||
public class ShutdownMonitor extends Thread
|
public class ShutdownMonitor extends Thread
|
||||||
{
|
{
|
||||||
private static final ShutdownMonitor INSTANCE = new ShutdownMonitor();
|
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
||||||
|
static class Holder
|
||||||
|
{
|
||||||
|
static ShutdownMonitor instance = new ShutdownMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
public static ShutdownMonitor getInstance()
|
public static ShutdownMonitor getInstance()
|
||||||
{
|
{
|
||||||
return INSTANCE;
|
return Holder.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final boolean DEBUG;
|
|
||||||
private final int port;
|
|
||||||
private final String key;
|
|
||||||
private final ServerSocket serverSocket;
|
|
||||||
|
|
||||||
|
private boolean DEBUG;
|
||||||
|
private int port;
|
||||||
|
private String key;
|
||||||
|
private boolean exitVm;
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a ShutdownMonitor using configuration from the System properties.
|
||||||
|
* <p>
|
||||||
|
* <code>STOP.PORT</code> = the port to listen on (empty, null, or values less than 0 disable the stop ability)<br>
|
||||||
|
* <code>STOP.KEY</code> = the magic key/passphrase to allow the stop (defaults to "eclipse")<br>
|
||||||
|
* <p>
|
||||||
|
* Note: server socket will only listen on localhost, and a successful stop will issue a System.exit() call.
|
||||||
|
*/
|
||||||
private ShutdownMonitor()
|
private ShutdownMonitor()
|
||||||
{
|
{
|
||||||
Properties props = System.getProperties();
|
Properties props = System.getProperties();
|
||||||
|
|
||||||
// Use the same debug option as /jetty-start/
|
|
||||||
this.DEBUG = props.containsKey("DEBUG");
|
this.DEBUG = props.containsKey("DEBUG");
|
||||||
|
|
||||||
// Use values passed thru /jetty-start/
|
|
||||||
int stopPort = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
|
||||||
String stopKey = props.getProperty("STOP.KEY",null);
|
|
||||||
|
|
||||||
ServerSocket sock = null;
|
// Use values passed thru via /jetty-start/
|
||||||
|
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
||||||
|
this.key = props.getProperty("STOP.KEY","eclipse");
|
||||||
|
this.exitVm = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void close(ServerSocket server)
|
||||||
|
{
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (stopPort < 0)
|
server.close();
|
||||||
{
|
|
||||||
System.out.println("ShutdownMonitor not in use");
|
|
||||||
sock = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDaemon(true);
|
|
||||||
setName("ShutdownMonitor");
|
|
||||||
|
|
||||||
sock = new ServerSocket(stopPort,1,InetAddress.getByName("127.0.0.1"));
|
|
||||||
if (stopPort == 0)
|
|
||||||
{
|
|
||||||
// server assigned port in use
|
|
||||||
stopPort = sock.getLocalPort();
|
|
||||||
System.out.printf("STOP.PORT=%d%n",stopPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopKey == null)
|
|
||||||
{
|
|
||||||
// create random key
|
|
||||||
stopKey = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
|
||||||
System.out.printf("STOP.KEY=%s%n",stopKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (IOException ignore)
|
||||||
{
|
{
|
||||||
debug(e);
|
/* ignore */
|
||||||
System.err.println("Error binding monitor port " + stopPort + ": " + e.toString());
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
// establish the port and key that are in use
|
|
||||||
this.port = stopPort;
|
|
||||||
this.key = stopKey;
|
|
||||||
|
|
||||||
this.serverSocket = sock;
|
|
||||||
debug("STOP.PORT=%d", port);
|
|
||||||
debug("STOP.KEY=%s", key);
|
|
||||||
debug("%s", serverSocket);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void close(Socket socket)
|
||||||
public String toString()
|
|
||||||
{
|
{
|
||||||
return String.format("%s[port=%d]",this.getClass().getName(),port);
|
if (socket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void debug(String format, Object... args)
|
||||||
|
{
|
||||||
|
if (DEBUG)
|
||||||
|
{
|
||||||
|
System.err.printf("[ShutdownMonitor] " + format + "%n",args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void debug(Throwable t)
|
private void debug(Throwable t)
|
||||||
|
@ -129,12 +129,24 @@ public class ShutdownMonitor extends Thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void debug(String format, Object... args)
|
public String getKey()
|
||||||
{
|
{
|
||||||
if (DEBUG)
|
return key;
|
||||||
{
|
}
|
||||||
System.err.printf("[ShutdownMonitor] " + format + "%n",args);
|
|
||||||
}
|
public int getPort()
|
||||||
|
{
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerSocket getServerSocket()
|
||||||
|
{
|
||||||
|
return serverSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExitVm()
|
||||||
|
{
|
||||||
|
return exitVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -169,15 +181,18 @@ public class ShutdownMonitor extends Thread
|
||||||
debug("Informing client that we are stopped.");
|
debug("Informing client that we are stopped.");
|
||||||
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
||||||
// Shutdown Monitor
|
// Shutdown Monitor
|
||||||
debug("Shutting down monitor");
|
debug("Shutting down monitor");
|
||||||
close(socket);
|
close(socket);
|
||||||
close(serverSocket);
|
close(serverSocket);
|
||||||
|
|
||||||
// Kill JVM
|
if (exitVm)
|
||||||
debug("Killing JVM");
|
{
|
||||||
System.exit(0);
|
// Kill JVM
|
||||||
|
debug("Killing JVM");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ("status".equals(cmd))
|
else if ("status".equals(cmd))
|
||||||
{
|
{
|
||||||
|
@ -199,37 +214,98 @@ public class ShutdownMonitor extends Thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close(Socket socket)
|
public void setDebug(boolean flag)
|
||||||
{
|
{
|
||||||
if (socket == null)
|
this.DEBUG = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExitVm(boolean exitVm)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
{
|
{
|
||||||
return;
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
}
|
}
|
||||||
|
this.exitVm = exitVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(String key)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
|
}
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(int port)
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitor already started");
|
||||||
|
}
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
System.out.printf("ShutdownMonitor already started");
|
||||||
|
return; // cannot start it again
|
||||||
|
}
|
||||||
|
startListenSocket();
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListenSocket()
|
||||||
|
{
|
||||||
|
ServerSocket sock = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
socket.close();
|
if (this.port < 0)
|
||||||
|
{
|
||||||
|
System.out.println("ShutdownMonitor not in use (port < 0): " + port);
|
||||||
|
sock = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDaemon(true);
|
||||||
|
setName("ShutdownMonitor");
|
||||||
|
|
||||||
|
sock = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
|
||||||
|
if (this.port == 0)
|
||||||
|
{
|
||||||
|
// server assigned port in use
|
||||||
|
this.port = sock.getLocalPort();
|
||||||
|
System.out.printf("STOP.PORT=%d%n",this.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.key == null)
|
||||||
|
{
|
||||||
|
// create random key
|
||||||
|
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
||||||
|
System.out.printf("STOP.KEY=%s%n",this.key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException ignore)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
/* ignore */
|
debug(e);
|
||||||
|
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// establish the port and key that are in use
|
||||||
|
this.serverSocket = sock;
|
||||||
|
debug("STOP.PORT=%d",this.port);
|
||||||
|
debug("STOP.KEY=%s",this.key);
|
||||||
|
debug("%s",serverSocket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void close(ServerSocket server)
|
|
||||||
{
|
|
||||||
if (server == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
@Override
|
||||||
{
|
public String toString()
|
||||||
server.close();
|
{
|
||||||
}
|
return String.format("%s[port=%d]",this.getClass().getName(),port);
|
||||||
catch (IOException ignore)
|
|
||||||
{
|
|
||||||
/* ignore */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue