001 /* 002 * Copyright (c) 2007-2015 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.util; 022 023 import java.util.Comparator; 024 import java.util.Queue; 025 import java.util.concurrent.PriorityBlockingQueue; 026 027 import org.slf4j.Logger; 028 import org.slf4j.LoggerFactory; 029 030 /** 031 * ShutdownUtil is a private helper class for registering dependent shutdown hooks to maintain internal state 032 * information reliably when a jvm is shutting down. 033 * <p/> 034 * This api is not intended for public use. 035 */ 036 public class ShutdownUtil 037 { 038 private static final Logger LOG = LoggerFactory.getLogger( ShutdownUtil.class ); 039 040 public static abstract class Hook 041 { 042 public enum Priority 043 { 044 FIRST, WORK_PARENT, WORK_CHILD, SERVICE_CONSUMER, SERVICE_PROVIDER, LAST 045 } 046 047 public abstract Priority priority(); 048 049 public abstract void execute(); 050 } 051 052 private static Queue<Hook> queue = new PriorityBlockingQueue<Hook>( 20, new Comparator<Hook>() 053 { 054 @Override 055 public int compare( Hook lhs, Hook rhs ) 056 { 057 if( lhs == rhs ) 058 return 0; 059 060 if( lhs == null ) 061 return -1; 062 else if( rhs == null ) 063 return 1; 064 065 return lhs.priority().compareTo( rhs.priority() ); 066 } 067 } 068 ); 069 070 private static Thread shutdownHook; 071 072 public static void addHook( Hook hook ) 073 { 074 if( hook == null ) 075 throw new IllegalArgumentException( "hook may not be null" ); 076 077 registerShutdownHook(); 078 079 queue.add( hook ); 080 } 081 082 public static boolean removeHook( Hook hook ) 083 { 084 return queue.remove( hook ); 085 } 086 087 public static synchronized void registerShutdownHook() 088 { 089 if( shutdownHook != null ) 090 return; 091 092 shutdownHook = new Thread( "cascading shutdown hooks" ) 093 { 094 @Override 095 public void run() 096 { 097 // These are not threads, so each one will be run in priority order 098 // blocking until the previous is complete 099 while( !queue.isEmpty() ) 100 { 101 Hook hook = null; 102 103 try 104 { 105 hook = queue.poll(); 106 107 // may get removed while shutdown is executing 108 if( hook == null ) 109 continue; 110 111 hook.execute(); 112 } 113 catch( Exception exception ) 114 { 115 LOG.error( "failed executing hook: {}, with exception: {}", hook, exception ); 116 } 117 } 118 } 119 }; 120 121 Runtime.getRuntime().addShutdownHook( shutdownHook ); 122 } 123 124 public static void deregisterShutdownHook() 125 { 126 Runtime.getRuntime().removeShutdownHook( shutdownHook ); 127 } 128 }