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 }