1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.daemon.support;
19
20 import org.apache.commons.daemon.DaemonContext;
21 import org.apache.commons.daemon.DaemonController;
22 import org.apache.commons.daemon.DaemonInitException;
23
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.util.Objects;
27
28
29
30
31 public final class DaemonLoader
32 {
33
34
35 private static Controller controller;
36 private static Object daemon;
37
38 private static Method init;
39 private static Method start;
40 private static Method stop;
41 private static Method destroy;
42 private static Method signal;
43
44
45
46
47 public static void version()
48 {
49 System.err.println("java version \"" +
50 System.getProperty("java.version") + "\"");
51 System.err.println(System.getProperty("java.runtime.name") +
52 " (build " +
53 System.getProperty("java.runtime.version") + ")");
54 System.err.println(System.getProperty("java.vm.name") +
55 " (build " +
56 System.getProperty("java.vm.version") +
57 ", " + System.getProperty("java.vm.info") + ")");
58 System.err.println("commons daemon version \"" +
59 System.getProperty("commons.daemon.version") + "\"");
60 System.err.println("commons daemon process (id: " +
61 System.getProperty("commons.daemon.process.id") +
62 ", parent: " +
63 System.getProperty("commons.daemon.process.parent") + ")");
64 }
65
66
67
68
69
70
71
72 public static boolean check(final String className)
73 {
74 try {
75
76 Objects.requireNonNull(className, "className");
77
78 final ClassLoader cl = DaemonLoader.class.getClassLoader();
79 if (cl == null) {
80 System.err.println("Cannot retrieve ClassLoader instance");
81 return false;
82 }
83
84
85 final Class<?> c = cl.loadClass(className);
86
87
88 if (c == null) {
89 throw new ClassNotFoundException(className);
90 }
91
92
93 c.getConstructor().newInstance();
94
95 } catch (final Throwable t) {
96
97
98
99 t.printStackTrace(System.err);
100 return false;
101 }
102
103
104 return true;
105 }
106
107
108
109
110
111
112 public static boolean signal()
113 {
114 try {
115 if (signal != null) {
116 signal.invoke(daemon);
117 return true;
118 }
119 System.out.println("Daemon doesn't support signaling");
120 } catch (final Throwable ex) {
121 System.err.println("Cannot send signal: " + ex);
122 ex.printStackTrace(System.err);
123 }
124 return false;
125 }
126
127
128
129
130
131
132
133
134 public static boolean load(final String className, String[] args)
135 {
136 try {
137
138
139 if (args == null) {
140 args = new String[0];
141 }
142
143
144 Objects.requireNonNull(className, "className");
145
146
147 final ClassLoader cl = DaemonLoader.class.getClassLoader();
148 if (cl == null) {
149 System.err.println("Cannot retrieve ClassLoader instance");
150 return false;
151 }
152 final Class<?> c;
153 if (className.charAt(0) == '@') {
154
155
156
157 c = DaemonWrapper.class;
158 final String[] a = new String[args.length + 2];
159 a[0] = "-start";
160 a[1] = className.substring(1);
161 System.arraycopy(args, 0, a, 2, args.length);
162 args = a;
163 }
164 else {
165 c = cl.loadClass(className);
166 }
167
168 if (c == null) {
169 throw new ClassNotFoundException(className);
170 }
171
172 boolean isdaemon = false;
173
174 try {
175 final Class<?> dclass = cl.loadClass("org.apache.commons.daemon.Daemon");
176 isdaemon = dclass.isAssignableFrom(c);
177 }
178 catch (final Exception ignored) {
179
180 }
181
182
183 final Class<?>[] myclass = new Class[1];
184 if (isdaemon) {
185 myclass[0] = DaemonContext.class;
186 }
187 else {
188 myclass[0] = args.getClass();
189 }
190
191 init = c.getMethod("init", myclass);
192 start = c.getMethod("start");
193 stop = c.getMethod("stop");
194 destroy = c.getMethod("destroy");
195
196 try {
197 signal = c.getMethod("signal");
198 } catch (final NoSuchMethodException ignored) {
199
200 }
201
202
203 daemon = c.getConstructor().newInstance();
204
205 if (isdaemon) {
206
207 controller = new Controller();
208
209
210 controller.setAvailable(false);
211
212
213 final Context context = new Context();
214 context.setArguments(args);
215 context.setController(controller);
216
217
218 final Object[] arg = new Object[1];
219 arg[0] = context;
220 init.invoke(daemon, arg);
221 }
222 else {
223 final Object[] arg = new Object[1];
224 arg[0] = args;
225 init.invoke(daemon, arg);
226 }
227
228 }
229 catch (final InvocationTargetException e) {
230 final Throwable thrown = e.getTargetException();
231
232 if (thrown instanceof DaemonInitException) {
233 failed(((DaemonInitException) thrown).getMessageWithCause());
234 }
235 else {
236 thrown.printStackTrace(System.err);
237 }
238 return false;
239 }
240 catch (final Throwable t) {
241
242
243 t.printStackTrace(System.err);
244 return false;
245 }
246
247 return true;
248 }
249
250
251
252
253
254
255 public static boolean start()
256 {
257 try {
258
259 start.invoke(daemon);
260
261 if (controller != null) {
262 controller.setAvailable(true);
263 }
264 } catch (final Throwable t) {
265
266
267 t.printStackTrace(System.err);
268 return false;
269 }
270 return true;
271 }
272
273
274
275
276
277
278 public static boolean stop()
279 {
280 try {
281
282 if (controller != null) {
283 controller.setAvailable(false);
284 }
285
286 stop.invoke(daemon);
287 }
288 catch (final Throwable t) {
289
290
291 t.printStackTrace(System.err);
292 return false;
293 }
294 return true;
295 }
296
297
298
299
300
301
302 public static boolean destroy()
303 {
304 try {
305
306 destroy.invoke(daemon);
307 daemon = null;
308 controller = null;
309 } catch (final Throwable t) {
310
311
312 t.printStackTrace(System.err);
313 return false;
314 }
315 return true;
316 }
317
318 private static native void shutdown(boolean reload);
319 private static native void failed(String message);
320
321
322
323
324 public static class Controller
325 implements DaemonController
326 {
327
328 private boolean available;
329
330 private Controller()
331 {
332 setAvailable(false);
333 }
334
335 private boolean isAvailable()
336 {
337 synchronized (this) {
338 return this.available;
339 }
340 }
341
342 private void setAvailable(final boolean available)
343 {
344 synchronized (this) {
345 this.available = available;
346 }
347 }
348
349 @Override
350 public void shutdown()
351 throws IllegalStateException
352 {
353 synchronized (this) {
354 if (!isAvailable()) {
355 throw new IllegalStateException();
356 }
357 setAvailable(false);
358 DaemonLoader.shutdown(false);
359 }
360 }
361
362 @Override
363 public void reload()
364 throws IllegalStateException
365 {
366 synchronized (this) {
367 if (!isAvailable()) {
368 throw new IllegalStateException();
369 }
370 setAvailable(false);
371 DaemonLoader.shutdown(true);
372 }
373 }
374
375 @Override
376 public void fail()
377 {
378 fail(null, null);
379 }
380
381 @Override
382 public void fail(final String message)
383 {
384 fail(message, null);
385 }
386
387 @Override
388 public void fail(final Exception exception)
389 {
390 fail(null, exception);
391 }
392
393 @Override
394 public void fail(final String message, final Exception exception)
395 {
396 synchronized (this) {
397 setAvailable(false);
398 String msg = message;
399 if (exception != null) {
400 if (msg != null) {
401 msg = msg + ": " + exception.toString();
402 }
403 else {
404 msg = exception.toString();
405 }
406 }
407 failed(msg);
408 }
409 }
410
411 }
412
413
414
415
416 public static class Context
417 implements DaemonContext
418 {
419
420 private DaemonController daemonController;
421
422 private String[] args;
423
424 @Override
425 public DaemonController getController()
426 {
427 return daemonController;
428 }
429
430
431
432
433
434
435 public void setController(final DaemonController controller)
436 {
437 this.daemonController = controller;
438 }
439
440 @Override
441 public String[] getArguments()
442 {
443 return args;
444 }
445
446
447
448
449
450
451 public void setArguments(final String[] args)
452 {
453 this.args = args;
454 }
455
456 }
457 }