Merge remote-tracking branch 'origin/jetty-7' into jetty-8

This commit is contained in:
Jan Bartel 2012-12-21 14:00:13 +11:00
commit 191040b736
2 changed files with 173 additions and 91 deletions

View File

@ -264,7 +264,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);

View File

@ -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,90 +42,74 @@ 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
public String toString()
{
return String.format("%s[port=%d]",this.getClass().getName(),port);
} }
private void debug(Throwable t) private void close(Socket socket)
{ {
if (DEBUG) if (socket == null)
{ {
t.printStackTrace(System.err); return;
}
try
{
socket.close();
}
catch (IOException ignore)
{
/* ignore */
} }
} }
@ -137,9 +121,42 @@ public class ShutdownMonitor extends Thread
} }
} }
private void debug(Throwable t)
{
if (DEBUG)
{
t.printStackTrace(System.err);
}
}
public String getKey()
{
return key;
}
public int getPort()
{
return port;
}
public ServerSocket getServerSocket()
{
return serverSocket;
}
public boolean isExitVm()
{
return exitVm;
}
@Override @Override
public void run() public void run()
{ {
if (serverSocket == null)
{
return;
}
while (true) while (true)
{ {
Socket socket = null; Socket socket = null;
@ -169,15 +186,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 +219,99 @@ 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())
{ {
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();
if (serverSocket == null)
{
return;
}
super.start();
}
private void startListenSocket()
{
if (this.port < 0)
{
System.out.println("ShutdownMonitor not in use (port < 0): " + port);
return; return;
} }
try try
{ {
socket.close(); setDaemon(true);
setName("ShutdownMonitor");
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
if (this.port == 0)
{
// server assigned port in use
this.port = serverSocket.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
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 */
}
} }
} }