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 * https://opensource.org/licenses/BSD-3-Clause 8 */ 9 package jdk.internal.org.jline.utils; 10 11 import java.util.ArrayList; 12 import java.util.List; 13 import java.util.Objects; 14 15 /** 16 * Manages the JLine shutdown-hook thread and tasks to execute on shutdown. 17 * 18 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> 19 * @since 2.7 20 */ 21 public final class ShutdownHooks 22 { 23 private static final List<Task> tasks = new ArrayList<>(); 24 25 private static Thread hook; 26 add(final T task)27 public static synchronized <T extends Task> T add(final T task) { 28 Objects.requireNonNull(task); 29 30 // Install the hook thread if needed 31 if (hook == null) { 32 hook = addHook(new Thread("JLine Shutdown Hook") 33 { 34 @Override 35 public void run() { 36 runTasks(); 37 } 38 }); 39 } 40 41 // Track the task 42 Log.debug("Adding shutdown-hook task: ", task); 43 tasks.add(task); 44 45 return task; 46 } 47 runTasks()48 private static synchronized void runTasks() { 49 Log.debug("Running all shutdown-hook tasks"); 50 51 // Iterate through copy of tasks list 52 for (Task task : tasks.toArray(new Task[tasks.size()])) { 53 Log.debug("Running task: ", task); 54 try { 55 task.run(); 56 } 57 catch (Throwable e) { 58 Log.warn("Task failed", e); 59 } 60 } 61 62 tasks.clear(); 63 } 64 addHook(final Thread thread)65 private static Thread addHook(final Thread thread) { 66 Log.debug("Registering shutdown-hook: ", thread); 67 Runtime.getRuntime().addShutdownHook(thread); 68 return thread; 69 } 70 remove(final Task task)71 public static synchronized void remove(final Task task) { 72 Objects.requireNonNull(task); 73 74 // ignore if hook never installed 75 if (hook == null) { 76 return; 77 } 78 79 // Drop the task 80 tasks.remove(task); 81 82 // If there are no more tasks, then remove the hook thread 83 if (tasks.isEmpty()) { 84 removeHook(hook); 85 hook = null; 86 } 87 } 88 removeHook(final Thread thread)89 private static void removeHook(final Thread thread) { 90 Log.debug("Removing shutdown-hook: ", thread); 91 92 try { 93 Runtime.getRuntime().removeShutdownHook(thread); 94 } 95 catch (IllegalStateException e) { 96 // The VM is shutting down, not a big deal; ignore 97 } 98 } 99 100 /** 101 * Essentially a {@link Runnable} which allows running to throw an exception. 102 */ 103 public interface Task 104 { run()105 void run() throws Exception; 106 } 107 } 108