Mercurial Hosting > luan
diff src/org/eclipse/jetty/server/ShutdownMonitor.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/eclipse/jetty/server/ShutdownMonitor.java Wed Sep 07 21:15:48 2016 -0600 @@ -0,0 +1,384 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Properties; + +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.thread.ShutdownThread; + +/** + * Shutdown/Stop Monitor thread. + * <p> + * 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 + * by the STOP.KEY system parameter (defaults to "eclipse") for admin requests. + * <p> + * If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout. + * <p> + * Commands "stop" and "status" are currently supported. + */ +public class ShutdownMonitor +{ + // Implementation of safe lazy init, using Initialization on Demand Holder technique. + static class Holder + { + static ShutdownMonitor instance = new ShutdownMonitor(); + } + + public static ShutdownMonitor getInstance() + { + return Holder.instance; + } + + /** + * ShutdownMonitorThread + * + * Thread for listening to STOP.PORT for command to stop Jetty. + * If ShowndownMonitor.exitVm is true, then Sytem.exit will also be + * called after the stop. + * + */ + public class ShutdownMonitorThread extends Thread + { + + public ShutdownMonitorThread () + { + setDaemon(true); + setName("ShutdownMonitor"); + } + + @Override + public void run() + { + if (serverSocket == null) + { + return; + } + + while (serverSocket != null) + { + Socket socket = null; + try + { + socket = serverSocket.accept(); + + LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream())); + String receivedKey = lin.readLine(); + if (!key.equals(receivedKey)) + { + System.err.println("Ignoring command with incorrect key"); + continue; + } + + OutputStream out = socket.getOutputStream(); + + String cmd = lin.readLine(); + debug("command=%s",cmd); + if ("stop".equals(cmd)) + { + // Graceful Shutdown + debug("Issuing graceful shutdown.."); + ShutdownThread.getInstance().run(); + + // Reply to client + debug("Informing client that we are stopped."); + out.write("Stopped\r\n".getBytes(StringUtil.__UTF8)); + out.flush(); + + // Shutdown Monitor + debug("Shutting down monitor"); + close(socket); + socket = null; + close(serverSocket); + serverSocket = null; + + if (exitVm) + { + // Kill JVM + debug("Killing JVM"); + System.exit(0); + } + } + else if ("status".equals(cmd)) + { + // Reply to client + out.write("OK\r\n".getBytes(StringUtil.__UTF8)); + out.flush(); + } + } + catch (Exception e) + { + debug(e); + System.err.println(e.toString()); + } + finally + { + close(socket); + socket = null; + } + } + } + + public void start() + { + if (isAlive()) + { + System.err.printf("ShutdownMonitorThread already started"); + return; // cannot start it again + } + + startListenSocket(); + + if (serverSocket == null) + { + return; + } + if (DEBUG) + System.err.println("Starting ShutdownMonitorThread"); + super.start(); + } + + private void startListenSocket() + { + if (port < 0) + { + if (DEBUG) + System.err.println("ShutdownMonitor not in use (port < 0): " + port); + return; + } + + try + { + serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1")); + if (port == 0) + { + // server assigned port in use + port = serverSocket.getLocalPort(); + System.out.printf("STOP.PORT=%d%n",port); + } + + if (key == null) + { + // create random key + key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36); + System.out.printf("STOP.KEY=%s%n",key); + } + } + catch (Exception e) + { + debug(e); + System.err.println("Error binding monitor port " + port + ": " + e.toString()); + serverSocket = null; + } + finally + { + // establish the port and key that are in use + debug("STOP.PORT=%d",port); + debug("STOP.KEY=%s",key); + debug("%s",serverSocket); + } + } + + } + + private boolean DEBUG; + private int port; + private String key; + private boolean exitVm; + private ServerSocket serverSocket; + private ShutdownMonitorThread thread; + + + + /** + * 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() + { + Properties props = System.getProperties(); + + this.DEBUG = props.containsKey("DEBUG"); + + // Use values passed thru via /jetty-start/ + this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1")); + this.key = props.getProperty("STOP.KEY",null); + this.exitVm = true; + } + + private void close(ServerSocket server) + { + if (server == null) + { + return; + } + + try + { + server.close(); + } + catch (IOException ignore) + { + /* ignore */ + } + } + + private void close(Socket socket) + { + 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) + { + 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; + } + + + public void setDebug(boolean flag) + { + this.DEBUG = flag; + } + + public void setExitVm(boolean exitVm) + { + synchronized (this) + { + if (thread != null && thread.isAlive()) + { + throw new IllegalStateException("ShutdownMonitorThread already started"); + } + this.exitVm = exitVm; + } + } + + public void setKey(String key) + { + synchronized (this) + { + if (thread != null && thread.isAlive()) + { + throw new IllegalStateException("ShutdownMonitorThread already started"); + } + this.key = key; + } + } + + public void setPort(int port) + { + synchronized (this) + { + if (thread != null && thread.isAlive()) + { + throw new IllegalStateException("ShutdownMonitorThread already started"); + } + this.port = port; + } + } + + protected void start() throws Exception + { + ShutdownMonitorThread t = null; + synchronized (this) + { + if (thread != null && thread.isAlive()) + { + System.err.printf("ShutdownMonitorThread already started"); + return; // cannot start it again + } + + thread = new ShutdownMonitorThread(); + t = thread; + } + + if (t != null) + t.start(); + } + + + protected boolean isAlive () + { + boolean result = false; + synchronized (this) + { + result = (thread != null && thread.isAlive()); + } + return result; + } + + + @Override + public String toString() + { + return String.format("%s[port=%d]",this.getClass().getName(),port); + } +}