    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      }