001 /* 002 * Copyright (c) 2007-2014 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.PriorityQueue; 025 026 import org.slf4j.Logger; 027 import org.slf4j.LoggerFactory; 028 029 /** 030 * ShutdownUtil is a private helper class for registering dependent shutdown hooks to maintain internal state 031 * information reliably when a jvm is shutting down. 032 * <p/> 033 * This api is not intended for public use. 034 */ 035 public class ShutdownUtil 036 { 037 private static final Logger LOG = LoggerFactory.getLogger( ShutdownUtil.class ); 038 039 public static abstract class Hook 040 { 041 public enum Priority 042 { 043 FIRST, WORK_PARENT, WORK_CHILD, SERVICE_CONSUMER, SERVICE_PROVIDER, LAST 044 } 045 046 public abstract Priority priority(); 047 048 public abstract void execute(); 049 } 050 051 private static PriorityQueue<Hook> queue = new PriorityQueue<Hook>( 20, new Comparator<Hook>() 052 { 053 @Override 054 public int compare( Hook lhs, Hook rhs ) 055 { 056 if( lhs == rhs ) 057 return 0; 058 059 if( lhs == null ) 060 return -1; 061 else if( rhs == null ) 062 return 1; 063 064 return lhs.priority().compareTo( rhs.priority() ); 065 } 066 } 067 ); 068 069 private static Thread shutdownHook; 070 071 public static void addHook( Hook hook ) 072 { 073 if( hook == null ) 074 throw new IllegalArgumentException( "hook may not be null" ); 075 076 registerShutdownHook(); 077 078 queue.add( hook ); 079 } 080 081 public static boolean removeHook( Hook hook ) 082 { 083 return queue.remove( hook ); 084 } 085 086 public static synchronized void registerShutdownHook() 087 { 088 if( shutdownHook != null ) 089 return; 090 091 shutdownHook = new Thread( "cascading shutdown hooks" ) 092 { 093 @Override 094 public void run() 095 { 096 // These are not threads, so each one will be run in priority order 097 // blocking until the previous is complete 098 while( !queue.isEmpty() ) 099 { 100 Hook hook = null; 101 102 try 103 { 104 hook = queue.poll(); 105 106 hook.execute(); 107 } 108 catch( Exception exception ) 109 { 110 LOG.error( "failed executing hook: {}, with exception: {}", hook, exception ); 111 } 112 } 113 } 114 }; 115 116 Runtime.getRuntime().addShutdownHook( shutdownHook ); 117 } 118 119 public static void deregisterShutdownHook() 120 { 121 Runtime.getRuntime().removeShutdownHook( shutdownHook ); 122 } 123 }