1 /* |
|
2 * Copyright (c) 2002-2016, the original author or authors. |
|
3 * |
|
4 * This software is distributable under the BSD license. See the terms of the |
|
5 * BSD license in the documentation provided with this software. |
|
6 * |
|
7 * http://www.opensource.org/licenses/bsd-license.php |
|
8 */ |
|
9 package jdk.internal.jline.internal; |
|
10 |
|
11 import java.util.ArrayList; |
|
12 import java.util.List; |
|
13 |
|
14 import static jdk.internal.jline.internal.Preconditions.checkNotNull; |
|
15 |
|
16 /** |
|
17 * Manages the JLine shutdown-hook thread and tasks to execute on shutdown. |
|
18 * |
|
19 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> |
|
20 * @since 2.7 |
|
21 */ |
|
22 public class ShutdownHooks |
|
23 { |
|
24 public static final String JLINE_SHUTDOWNHOOK = "jline.shutdownhook"; |
|
25 |
|
26 private static final boolean enabled = Configuration.getBoolean(JLINE_SHUTDOWNHOOK, true); |
|
27 |
|
28 private static final List<Task> tasks = new ArrayList<Task>(); |
|
29 |
|
30 private static Thread hook; |
|
31 |
|
32 public static synchronized <T extends Task> T add(final T task) { |
|
33 checkNotNull(task); |
|
34 |
|
35 // If not enabled ignore |
|
36 if (!enabled) { |
|
37 Log.debug("Shutdown-hook is disabled; not installing: ", task); |
|
38 return task; |
|
39 } |
|
40 |
|
41 // Install the hook thread if needed |
|
42 if (hook == null) { |
|
43 hook = addHook(new Thread("JLine Shutdown Hook") |
|
44 { |
|
45 @Override |
|
46 public void run() { |
|
47 runTasks(); |
|
48 } |
|
49 }); |
|
50 } |
|
51 |
|
52 // Track the task |
|
53 Log.debug("Adding shutdown-hook task: ", task); |
|
54 tasks.add(task); |
|
55 |
|
56 return task; |
|
57 } |
|
58 |
|
59 private static synchronized void runTasks() { |
|
60 Log.debug("Running all shutdown-hook tasks"); |
|
61 |
|
62 // Iterate through copy of tasks list |
|
63 for (Task task : tasks.toArray(new Task[tasks.size()])) { |
|
64 Log.debug("Running task: ", task); |
|
65 try { |
|
66 task.run(); |
|
67 } |
|
68 catch (Throwable e) { |
|
69 Log.warn("Task failed", e); |
|
70 } |
|
71 } |
|
72 |
|
73 tasks.clear(); |
|
74 } |
|
75 |
|
76 private static Thread addHook(final Thread thread) { |
|
77 Log.debug("Registering shutdown-hook: ", thread); |
|
78 try { |
|
79 Runtime.getRuntime().addShutdownHook(thread); |
|
80 } |
|
81 catch (AbstractMethodError e) { |
|
82 // JDK 1.3+ only method. Bummer. |
|
83 Log.debug("Failed to register shutdown-hook", e); |
|
84 } |
|
85 return thread; |
|
86 } |
|
87 |
|
88 public static synchronized void remove(final Task task) { |
|
89 checkNotNull(task); |
|
90 |
|
91 // ignore if not enabled or hook never installed |
|
92 if (!enabled || hook == null) { |
|
93 return; |
|
94 } |
|
95 |
|
96 // Drop the task |
|
97 tasks.remove(task); |
|
98 |
|
99 // If there are no more tasks, then remove the hook thread |
|
100 if (tasks.isEmpty()) { |
|
101 removeHook(hook); |
|
102 hook = null; |
|
103 } |
|
104 } |
|
105 |
|
106 private static void removeHook(final Thread thread) { |
|
107 Log.debug("Removing shutdown-hook: ", thread); |
|
108 |
|
109 try { |
|
110 Runtime.getRuntime().removeShutdownHook(thread); |
|
111 } |
|
112 catch (AbstractMethodError e) { |
|
113 // JDK 1.3+ only method. Bummer. |
|
114 Log.debug("Failed to remove shutdown-hook", e); |
|
115 } |
|
116 catch (IllegalStateException e) { |
|
117 // The VM is shutting down, not a big deal; ignore |
|
118 } |
|
119 } |
|
120 |
|
121 /** |
|
122 * Essentially a {@link Runnable} which allows running to throw an exception. |
|
123 */ |
|
124 public static interface Task |
|
125 { |
|
126 void run() throws Exception; |
|
127 } |
|
128 } |
|