Mercurial Hosting > luan
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 801:6a21393191c1 | 802:3428c60d7cfc |
|---|---|
| 1 // | |
| 2 // ======================================================================== | |
| 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. | |
| 4 // ------------------------------------------------------------------------ | |
| 5 // All rights reserved. This program and the accompanying materials | |
| 6 // are made available under the terms of the Eclipse Public License v1.0 | |
| 7 // and Apache License v2.0 which accompanies this distribution. | |
| 8 // | |
| 9 // The Eclipse Public License is available at | |
| 10 // http://www.eclipse.org/legal/epl-v10.html | |
| 11 // | |
| 12 // The Apache License v2.0 is available at | |
| 13 // http://www.opensource.org/licenses/apache2.0.php | |
| 14 // | |
| 15 // You may elect to redistribute this code under either of these licenses. | |
| 16 // ======================================================================== | |
| 17 // | |
| 18 | |
| 19 package org.eclipse.jetty.server; | |
| 20 | |
| 21 import java.io.IOException; | |
| 22 import java.io.InputStreamReader; | |
| 23 import java.io.LineNumberReader; | |
| 24 import java.io.OutputStream; | |
| 25 import java.net.InetAddress; | |
| 26 import java.net.ServerSocket; | |
| 27 import java.net.Socket; | |
| 28 import java.util.Properties; | |
| 29 | |
| 30 import org.eclipse.jetty.util.StringUtil; | |
| 31 import org.eclipse.jetty.util.thread.ShutdownThread; | |
| 32 | |
| 33 /** | |
| 34 * Shutdown/Stop Monitor thread. | |
| 35 * <p> | |
| 36 * 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 | |
| 37 * by the STOP.KEY system parameter (defaults to "eclipse") for admin requests. | |
| 38 * <p> | |
| 39 * If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout. | |
| 40 * <p> | |
| 41 * Commands "stop" and "status" are currently supported. | |
| 42 */ | |
| 43 public class ShutdownMonitor | |
| 44 { | |
| 45 // Implementation of safe lazy init, using Initialization on Demand Holder technique. | |
| 46 static class Holder | |
| 47 { | |
| 48 static ShutdownMonitor instance = new ShutdownMonitor(); | |
| 49 } | |
| 50 | |
| 51 public static ShutdownMonitor getInstance() | |
| 52 { | |
| 53 return Holder.instance; | |
| 54 } | |
| 55 | |
| 56 /** | |
| 57 * ShutdownMonitorThread | |
| 58 * | |
| 59 * Thread for listening to STOP.PORT for command to stop Jetty. | |
| 60 * If ShowndownMonitor.exitVm is true, then Sytem.exit will also be | |
| 61 * called after the stop. | |
| 62 * | |
| 63 */ | |
| 64 public class ShutdownMonitorThread extends Thread | |
| 65 { | |
| 66 | |
| 67 public ShutdownMonitorThread () | |
| 68 { | |
| 69 setDaemon(true); | |
| 70 setName("ShutdownMonitor"); | |
| 71 } | |
| 72 | |
| 73 @Override | |
| 74 public void run() | |
| 75 { | |
| 76 if (serverSocket == null) | |
| 77 { | |
| 78 return; | |
| 79 } | |
| 80 | |
| 81 while (serverSocket != null) | |
| 82 { | |
| 83 Socket socket = null; | |
| 84 try | |
| 85 { | |
| 86 socket = serverSocket.accept(); | |
| 87 | |
| 88 LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream())); | |
| 89 String receivedKey = lin.readLine(); | |
| 90 if (!key.equals(receivedKey)) | |
| 91 { | |
| 92 System.err.println("Ignoring command with incorrect key"); | |
| 93 continue; | |
| 94 } | |
| 95 | |
| 96 OutputStream out = socket.getOutputStream(); | |
| 97 | |
| 98 String cmd = lin.readLine(); | |
| 99 debug("command=%s",cmd); | |
| 100 if ("stop".equals(cmd)) | |
| 101 { | |
| 102 // Graceful Shutdown | |
| 103 debug("Issuing graceful shutdown.."); | |
| 104 ShutdownThread.getInstance().run(); | |
| 105 | |
| 106 // Reply to client | |
| 107 debug("Informing client that we are stopped."); | |
| 108 out.write("Stopped\r\n".getBytes(StringUtil.__UTF8)); | |
| 109 out.flush(); | |
| 110 | |
| 111 // Shutdown Monitor | |
| 112 debug("Shutting down monitor"); | |
| 113 close(socket); | |
| 114 socket = null; | |
| 115 close(serverSocket); | |
| 116 serverSocket = null; | |
| 117 | |
| 118 if (exitVm) | |
| 119 { | |
| 120 // Kill JVM | |
| 121 debug("Killing JVM"); | |
| 122 System.exit(0); | |
| 123 } | |
| 124 } | |
| 125 else if ("status".equals(cmd)) | |
| 126 { | |
| 127 // Reply to client | |
| 128 out.write("OK\r\n".getBytes(StringUtil.__UTF8)); | |
| 129 out.flush(); | |
| 130 } | |
| 131 } | |
| 132 catch (Exception e) | |
| 133 { | |
| 134 debug(e); | |
| 135 System.err.println(e.toString()); | |
| 136 } | |
| 137 finally | |
| 138 { | |
| 139 close(socket); | |
| 140 socket = null; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 public void start() | |
| 146 { | |
| 147 if (isAlive()) | |
| 148 { | |
| 149 System.err.printf("ShutdownMonitorThread already started"); | |
| 150 return; // cannot start it again | |
| 151 } | |
| 152 | |
| 153 startListenSocket(); | |
| 154 | |
| 155 if (serverSocket == null) | |
| 156 { | |
| 157 return; | |
| 158 } | |
| 159 if (DEBUG) | |
| 160 System.err.println("Starting ShutdownMonitorThread"); | |
| 161 super.start(); | |
| 162 } | |
| 163 | |
| 164 private void startListenSocket() | |
| 165 { | |
| 166 if (port < 0) | |
| 167 { | |
| 168 if (DEBUG) | |
| 169 System.err.println("ShutdownMonitor not in use (port < 0): " + port); | |
| 170 return; | |
| 171 } | |
| 172 | |
| 173 try | |
| 174 { | |
| 175 serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1")); | |
| 176 if (port == 0) | |
| 177 { | |
| 178 // server assigned port in use | |
| 179 port = serverSocket.getLocalPort(); | |
| 180 System.out.printf("STOP.PORT=%d%n",port); | |
| 181 } | |
| 182 | |
| 183 if (key == null) | |
| 184 { | |
| 185 // create random key | |
| 186 key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36); | |
| 187 System.out.printf("STOP.KEY=%s%n",key); | |
| 188 } | |
| 189 } | |
| 190 catch (Exception e) | |
| 191 { | |
| 192 debug(e); | |
| 193 System.err.println("Error binding monitor port " + port + ": " + e.toString()); | |
| 194 serverSocket = null; | |
| 195 } | |
| 196 finally | |
| 197 { | |
| 198 // establish the port and key that are in use | |
| 199 debug("STOP.PORT=%d",port); | |
| 200 debug("STOP.KEY=%s",key); | |
| 201 debug("%s",serverSocket); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 } | |
| 206 | |
| 207 private boolean DEBUG; | |
| 208 private int port; | |
| 209 private String key; | |
| 210 private boolean exitVm; | |
| 211 private ServerSocket serverSocket; | |
| 212 private ShutdownMonitorThread thread; | |
| 213 | |
| 214 | |
| 215 | |
| 216 /** | |
| 217 * Create a ShutdownMonitor using configuration from the System properties. | |
| 218 * <p> | |
| 219 * <code>STOP.PORT</code> = the port to listen on (empty, null, or values less than 0 disable the stop ability)<br> | |
| 220 * <code>STOP.KEY</code> = the magic key/passphrase to allow the stop (defaults to "eclipse")<br> | |
| 221 * <p> | |
| 222 * Note: server socket will only listen on localhost, and a successful stop will issue a System.exit() call. | |
| 223 */ | |
| 224 private ShutdownMonitor() | |
| 225 { | |
| 226 Properties props = System.getProperties(); | |
| 227 | |
| 228 this.DEBUG = props.containsKey("DEBUG"); | |
| 229 | |
| 230 // Use values passed thru via /jetty-start/ | |
| 231 this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1")); | |
| 232 this.key = props.getProperty("STOP.KEY",null); | |
| 233 this.exitVm = true; | |
| 234 } | |
| 235 | |
| 236 private void close(ServerSocket server) | |
| 237 { | |
| 238 if (server == null) | |
| 239 { | |
| 240 return; | |
| 241 } | |
| 242 | |
| 243 try | |
| 244 { | |
| 245 server.close(); | |
| 246 } | |
| 247 catch (IOException ignore) | |
| 248 { | |
| 249 /* ignore */ | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 private void close(Socket socket) | |
| 254 { | |
| 255 if (socket == null) | |
| 256 { | |
| 257 return; | |
| 258 } | |
| 259 | |
| 260 try | |
| 261 { | |
| 262 socket.close(); | |
| 263 } | |
| 264 catch (IOException ignore) | |
| 265 { | |
| 266 /* ignore */ | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 private void debug(String format, Object... args) | |
| 271 { | |
| 272 if (DEBUG) | |
| 273 { | |
| 274 System.err.printf("[ShutdownMonitor] " + format + "%n",args); | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 private void debug(Throwable t) | |
| 279 { | |
| 280 if (DEBUG) | |
| 281 { | |
| 282 t.printStackTrace(System.err); | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 public String getKey() | |
| 287 { | |
| 288 return key; | |
| 289 } | |
| 290 | |
| 291 public int getPort() | |
| 292 { | |
| 293 return port; | |
| 294 } | |
| 295 | |
| 296 public ServerSocket getServerSocket() | |
| 297 { | |
| 298 return serverSocket; | |
| 299 } | |
| 300 | |
| 301 public boolean isExitVm() | |
| 302 { | |
| 303 return exitVm; | |
| 304 } | |
| 305 | |
| 306 | |
| 307 public void setDebug(boolean flag) | |
| 308 { | |
| 309 this.DEBUG = flag; | |
| 310 } | |
| 311 | |
| 312 public void setExitVm(boolean exitVm) | |
| 313 { | |
| 314 synchronized (this) | |
| 315 { | |
| 316 if (thread != null && thread.isAlive()) | |
| 317 { | |
| 318 throw new IllegalStateException("ShutdownMonitorThread already started"); | |
| 319 } | |
| 320 this.exitVm = exitVm; | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 public void setKey(String key) | |
| 325 { | |
| 326 synchronized (this) | |
| 327 { | |
| 328 if (thread != null && thread.isAlive()) | |
| 329 { | |
| 330 throw new IllegalStateException("ShutdownMonitorThread already started"); | |
| 331 } | |
| 332 this.key = key; | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 public void setPort(int port) | |
| 337 { | |
| 338 synchronized (this) | |
| 339 { | |
| 340 if (thread != null && thread.isAlive()) | |
| 341 { | |
| 342 throw new IllegalStateException("ShutdownMonitorThread already started"); | |
| 343 } | |
| 344 this.port = port; | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 protected void start() throws Exception | |
| 349 { | |
| 350 ShutdownMonitorThread t = null; | |
| 351 synchronized (this) | |
| 352 { | |
| 353 if (thread != null && thread.isAlive()) | |
| 354 { | |
| 355 System.err.printf("ShutdownMonitorThread already started"); | |
| 356 return; // cannot start it again | |
| 357 } | |
| 358 | |
| 359 thread = new ShutdownMonitorThread(); | |
| 360 t = thread; | |
| 361 } | |
| 362 | |
| 363 if (t != null) | |
| 364 t.start(); | |
| 365 } | |
| 366 | |
| 367 | |
| 368 protected boolean isAlive () | |
| 369 { | |
| 370 boolean result = false; | |
| 371 synchronized (this) | |
| 372 { | |
| 373 result = (thread != null && thread.isAlive()); | |
| 374 } | |
| 375 return result; | |
| 376 } | |
| 377 | |
| 378 | |
| 379 @Override | |
| 380 public String toString() | |
| 381 { | |
| 382 return String.format("%s[port=%d]",this.getClass().getName(),port); | |
| 383 } | |
| 384 } |
