1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.daemon;
19
20 import java.io.*;
21 import java.net.*;
22 import java.text.SimpleDateFormat;
23 import java.util.Date;
24 import java.util.Enumeration;
25 import java.util.Vector;
26 import org.apache.commons.daemon.Daemon;
27 import org.apache.commons.daemon.DaemonController;
28 import org.apache.commons.daemon.DaemonContext;
29
30
31
32
33 public class SimpleDaemon implements Daemon, Runnable, DaemonUserSignal {
34
35 private ServerSocket server=null;
36 private Thread thread=null;
37 private DaemonController controller=null;
38 private volatile boolean stopping=false;
39 private String directory=null;
40 private Vector handlers=null;
41 private boolean softReloadSignalled;
42
43 public SimpleDaemon() {
44 super();
45 System.err.println("SimpleDaemon: instance "+this.hashCode()+
46 " created");
47 this.handlers=new Vector();
48 }
49
50 protected void finalize() {
51 System.err.println("SimpleDaemon: instance "+this.hashCode()+
52 " garbage collected");
53 }
54
55
56
57
58 public void init(DaemonContext context)
59 throws Exception {
60 System.err.println("SimpleDaemon: instance "+this.hashCode()+
61 " init");
62
63 int port=1200;
64
65 String[] a = context.getArguments();
66
67 if (a.length>0) port=Integer.parseInt(a[0]);
68 if (a.length>1) this.directory=a[1];
69 else this.directory="/tmp";
70
71
72 System.err.println("SimpleDaemon: loading on port "+port);
73
74
75 this.controller=context.getController();
76 this.server=new ServerSocket(port);
77 this.thread=new Thread(this);
78 }
79
80 public void start() {
81
82 System.err.println("SimpleDaemon: starting");
83
84
85 this.thread.start();
86 }
87
88 public void stop()
89 throws IOException, InterruptedException {
90
91 System.err.println("SimpleDaemon: stopping");
92
93
94 this.stopping=true;
95 this.server.close();
96
97
98 this.thread.join(5000);
99 System.err.println("SimpleDaemon: stopped");
100 }
101
102 public void destroy() {
103 System.err.println("SimpleDaemon: instance "+this.hashCode()+
104 " destroy");
105 }
106
107 public void run() {
108 int number=0;
109
110 System.err.println("SimpleDaemon: started acceptor loop");
111 try {
112 while(!this.stopping) {
113 checkForReload();
114 Socket socket=this.server.accept();
115 checkForReload();
116
117 Handler handler=new Handler(socket,this,this.controller);
118 handler.setConnectionNumber(number++);
119 handler.setDirectoryName(this.directory);
120 new Thread(handler).start();
121 }
122 } catch (IOException e) {
123
124
125 if (!this.stopping) e.printStackTrace(System.err);
126 }
127
128
129 Enumeration openhandlers=this.handlers.elements();
130 while (openhandlers.hasMoreElements()) {
131 Handler handler=(Handler)openhandlers.nextElement();
132 System.err.println("SimpleDaemon: dropping connection "+
133 handler.getConnectionNumber());
134 handler.close();
135 }
136
137 System.err.println("SimpleDaemon: exiting acceptor loop");
138 }
139
140 public void signal() {
141
142
143
144 this.softReloadSignalled = true;
145 }
146
147 private void checkForReload() {
148 if (this.softReloadSignalled) {
149 System.err.println("SimpleDaemon: picked up reload, waiting for connections to finish...");
150 while (! this.handlers.isEmpty()) {}
151 System.err.println("SimpleDaemon: all connections have finished, pretending to reload");
152 this.softReloadSignalled = false;
153 }
154 }
155
156 protected void addHandler(Handler handler) {
157 synchronized (handler) {
158 this.handlers.add(handler);
159 }
160 }
161
162 protected void removeHandler(Handler handler) {
163 synchronized (handler) {
164 this.handlers.remove(handler);
165 }
166 }
167
168 public static class Handler implements Runnable {
169
170 private DaemonController controller=null;
171 private SimpleDaemon parent=null;
172 private String directory=null;
173 private Socket socket=null;
174 private int number=0;
175
176 public Handler(Socket s, SimpleDaemon p, DaemonController c) {
177 super();
178 this.socket=s;
179 this.parent=p;
180 this.controller=c;
181 }
182
183 public void run() {
184 this.parent.addHandler(this);
185 System.err.println("SimpleDaemon: connection "+this.number+
186 " opened from "+this.socket.getInetAddress());
187 try {
188 InputStream in=this.socket.getInputStream();
189 OutputStream out=this.socket.getOutputStream();
190 handle(in,out);
191 this.socket.close();
192 } catch (IOException e) {
193 e.printStackTrace(System.err);
194 }
195 System.err.println("SimpleDaemon: connection "+this.number+
196 " closed");
197 this.parent.removeHandler(this);
198 }
199
200 public void close() {
201 try {
202 this.socket.close();
203 } catch (IOException e) {
204 e.printStackTrace(System.err);
205 }
206 }
207
208 public void setConnectionNumber(int number) {
209 this.number=number;
210 }
211
212 public int getConnectionNumber() {
213 return(this.number);
214 }
215
216 public void setDirectoryName(String directory) {
217 this.directory=directory;
218 }
219
220 public String getDirectoryName() {
221 return(this.directory);
222 }
223
224 public void log(String name)
225 throws IOException {
226 OutputStream file=new FileOutputStream(name,true);
227 PrintStream out=new PrintStream(file);
228 SimpleDateFormat fmt=new SimpleDateFormat();
229
230 out.println(fmt.format(new Date()));
231 out.close();
232 file.close();
233 }
234
235 public void handle(InputStream in, OutputStream os) {
236 PrintStream out=new PrintStream(os);
237
238 while(true) {
239 try {
240
241
242 if (in.available()==0) {
243 out.println();
244 out.println("Please select one of the following:");
245 out.println(" 1) Shutdown");
246 out.println(" 2) Reload");
247 out.println(" 3) Create a file");
248 out.println(" 4) Disconnect");
249 out.println(" 5) Soft reload");
250 out.print("Your choice: ");
251 }
252
253
254 int x=in.read();
255
256 switch (x) {
257
258 case -1:
259 return;
260
261
262 case '1':
263 out.println("Attempting a shutdown...");
264 try {
265 this.controller.shutdown();
266 } catch (IllegalStateException e) {
267 out.println();
268 out.println("Can't shutdown now");
269 e.printStackTrace(out);
270 }
271 break;
272
273
274 case '2':
275 out.println("Attempting a reload...");
276 try {
277 this.controller.reload();
278 } catch (IllegalStateException e) {
279 out.println();
280 out.println("Can't reload now");
281 e.printStackTrace(out);
282 }
283 break;
284
285
286 case '3':
287 String name=this.getDirectoryName()+
288 "/SimpleDaemon."+
289 this.getConnectionNumber()+
290 ".tmp";
291 try {
292 this.log(name);
293 out.println("File '"+name+"' created");
294 } catch (IOException e) {
295 e.printStackTrace(out);
296 }
297 break;
298
299
300 case '4':
301 out.println("Disconnecting...");
302 return;
303 case '5':
304 out.println("Reloading configuration...");
305 this.parent.signal();
306 return;
307
308
309 case '\r':
310 case '\n':
311 break;
312
313
314 default:
315 out.println("Unknown option '"+(char)x+"'");
316 break;
317
318 }
319
320
321 } catch (IOException e) {
322 System.err.println("SimpleDaemon: IOException in "+
323 "connection "+
324 this.getConnectionNumber());
325 return;
326 }
327 }
328 }
329 }
330 }