1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
35
36
37
38
39
40
41
42
43 public class ShutdownMonitor extends Thread
44 {
45
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 private boolean DEBUG;
57 private int port;
58 private String key;
59 private boolean exitVm;
60 private ServerSocket serverSocket;
61
62
63
64
65
66
67
68
69
70 private ShutdownMonitor()
71 {
72 Properties props = System.getProperties();
73
74 this.DEBUG = props.containsKey("DEBUG");
75
76
77 this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
78 this.key = props.getProperty("STOP.KEY","eclipse");
79 this.exitVm = true;
80 }
81
82 private void close(ServerSocket server)
83 {
84 if (server == null)
85 {
86 return;
87 }
88
89 try
90 {
91 server.close();
92 }
93 catch (IOException ignore)
94 {
95
96 }
97 }
98
99 private void close(Socket socket)
100 {
101 if (socket == null)
102 {
103 return;
104 }
105
106 try
107 {
108 socket.close();
109 }
110 catch (IOException ignore)
111 {
112
113 }
114 }
115
116 private void debug(String format, Object... args)
117 {
118 if (DEBUG)
119 {
120 System.err.printf("[ShutdownMonitor] " + format + "%n",args);
121 }
122 }
123
124 private void debug(Throwable t)
125 {
126 if (DEBUG)
127 {
128 t.printStackTrace(System.err);
129 }
130 }
131
132 public String getKey()
133 {
134 return key;
135 }
136
137 public int getPort()
138 {
139 return port;
140 }
141
142 public ServerSocket getServerSocket()
143 {
144 return serverSocket;
145 }
146
147 public boolean isExitVm()
148 {
149 return exitVm;
150 }
151
152 @Override
153 public void run()
154 {
155 if (serverSocket == null)
156 {
157 return;
158 }
159
160 while (true)
161 {
162 Socket socket = null;
163 try
164 {
165 socket = serverSocket.accept();
166
167 LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
168 String key = lin.readLine();
169 if (!this.key.equals(key))
170 {
171 System.err.println("Ignoring command with incorrect key");
172 continue;
173 }
174
175 OutputStream out = socket.getOutputStream();
176
177 String cmd = lin.readLine();
178 debug("command=%s",cmd);
179 if ("stop".equals(cmd))
180 {
181
182 debug("Issuing graceful shutdown..");
183 ShutdownThread.getInstance().run();
184
185
186 debug("Informing client that we are stopped.");
187 out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
188 out.flush();
189
190
191 debug("Shutting down monitor");
192 close(socket);
193 close(serverSocket);
194
195 if (exitVm)
196 {
197
198 debug("Killing JVM");
199 System.exit(0);
200 }
201 }
202 else if ("status".equals(cmd))
203 {
204
205 out.write("OK\r\n".getBytes(StringUtil.__UTF8));
206 out.flush();
207 }
208 }
209 catch (Exception e)
210 {
211 debug(e);
212 System.err.println(e.toString());
213 }
214 finally
215 {
216 close(socket);
217 socket = null;
218 }
219 }
220 }
221
222 public void setDebug(boolean flag)
223 {
224 this.DEBUG = flag;
225 }
226
227 public void setExitVm(boolean exitVm)
228 {
229 if (isAlive())
230 {
231 throw new IllegalStateException("ShutdownMonitor already started");
232 }
233 this.exitVm = exitVm;
234 }
235
236 public void setKey(String key)
237 {
238 if (isAlive())
239 {
240 throw new IllegalStateException("ShutdownMonitor already started");
241 }
242 this.key = key;
243 }
244
245 public void setPort(int port)
246 {
247 if (isAlive())
248 {
249 throw new IllegalStateException("ShutdownMonitor already started");
250 }
251 this.port = port;
252 }
253
254 public void start()
255 {
256 if (isAlive())
257 {
258 System.err.printf("ShutdownMonitor already started");
259 return;
260 }
261 startListenSocket();
262 if (serverSocket == null)
263 {
264 return;
265 }
266
267 super.start();
268 }
269
270 private void startListenSocket()
271 {
272 if (this.port < 0)
273 {
274 if (DEBUG)
275 System.err.println("ShutdownMonitor not in use (port < 0): " + port);
276 return;
277 }
278
279 try
280 {
281 setDaemon(true);
282 setName("ShutdownMonitor");
283
284 this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
285 if (this.port == 0)
286 {
287
288 this.port = serverSocket.getLocalPort();
289 System.out.printf("STOP.PORT=%d%n",this.port);
290 }
291
292 if (this.key == null)
293 {
294
295 this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
296 System.out.printf("STOP.KEY=%s%n",this.key);
297 }
298 }
299 catch (Exception e)
300 {
301 debug(e);
302 System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
303 }
304 finally
305 {
306
307 debug("STOP.PORT=%d",this.port);
308 debug("STOP.KEY=%s",this.key);
309 debug("%s",serverSocket);
310 }
311 }
312
313 @Override
314 public String toString()
315 {
316 return String.format("%s[port=%d]",this.getClass().getName(),port);
317 }
318 }