1 /*
   2  * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import java.util.*;
  28 
  29 /*
  30  * Class to track and run user level shutdown hooks registered through
  31  * <tt>{@link Runtime#addShutdownHook Runtime.addShutdownHook}</tt>.
  32  *
  33  * @see java.lang.Runtime#addShutdownHook
  34  * @see java.lang.Runtime#removeShutdownHook
  35  */
  36 
  37 class ApplicationShutdownHooks {
  38     /* The set of registered hooks */
  39     private static IdentityHashMap<Thread, Thread> hooks;
  40     static {
  41         try {
  42             Shutdown.add(1 /* shutdown hook invocation order */,
  43                 false /* not registered if shutdown in progress */,
  44                 new Runnable() {
  45                     public void run() {
  46                         runHooks();
  47                     }
  48                 }
  49             );
  50             hooks = new IdentityHashMap<>();
  51         } catch (IllegalStateException e) {
  52             // application shutdown hooks cannot be added if
  53             // shutdown is in progress.
  54             hooks = null;
  55         }
  56     }
  57 
  58 
  59     private ApplicationShutdownHooks() {}
  60 
  61     /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
  62      * but does not do any security checks.
  63      */
  64     static synchronized void add(Thread hook) {
  65         if(hooks == null)
  66             throw new IllegalStateException("Shutdown in progress");
  67 
  68         if (hook.isAlive())
  69             throw new IllegalArgumentException("Hook already running");
  70 
  71         if (hooks.containsKey(hook))
  72             throw new IllegalArgumentException("Hook previously registered");
  73 
  74         hooks.put(hook, hook);
  75     }
  76 
  77     /* Remove a previously-registered hook.  Like the add method, this method
  78      * does not do any security checks.
  79      */
  80     static synchronized boolean remove(Thread hook) {
  81         if(hooks == null)
  82             throw new IllegalStateException("Shutdown in progress");
  83 
  84         if (hook == null)
  85             throw new NullPointerException();
  86 
  87         return hooks.remove(hook) != null;
  88     }
  89 
  90     /* Iterates over all application hooks creating a new thread for each
  91      * to run in. Hooks are run concurrently and this method waits for
  92      * them to finish.
  93      */
  94     static void runHooks() {
  95         Collection<Thread> threads;
  96         synchronized(ApplicationShutdownHooks.class) {
  97             threads = hooks.keySet();
  98             hooks = null;
  99         }
 100 
 101         for (Thread hook : threads) {
 102             hook.start();
 103         }
 104         for (Thread hook : threads) {
 105             try {
 106                 hook.join();
 107             } catch (InterruptedException x) { }
 108         }
 109     }
 110 }