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 } |