content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.bookkeeper.common.util;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import lombok.extern.slf4j.Slf4j;
  
  /**
   * Forked from <a href="https://github.com/apache/pulsar">Pulsar</a>.
   */
  @Slf4j
  public class ShutdownUtil {
      private static final Method log4j2ShutdownMethod;
  
      static {
          // use reflection to find org.apache.logging.log4j.LogManager.shutdown method
          Method shutdownMethod = null;
          try {
              shutdownMethod = Class.forName("org.apache.logging.log4j.LogManager")
                      .getMethod("shutdown");
          } catch (ClassNotFoundException | NoSuchMethodException e) {
              // ignore when Log4j2 isn't found, log at debug level
              log.debug("Cannot find org.apache.logging.log4j.LogManager.shutdown method", e);
          }
          log4j2ShutdownMethod = shutdownMethod;
      }
  
      /**
       * Triggers an immediate forceful shutdown of the current process.
       *
       * @param status Termination status. By convention, a nonzero status code indicates abnormal termination.
       * @see Runtime#halt(int)
       */
      public static void triggerImmediateForcefulShutdown(int status) {
          triggerImmediateForcefulShutdown(status, true);
      }
      public static void triggerImmediateForcefulShutdown(int status, boolean logging) {
          try {
              if (status != 0 && logging) {
                  log.warn("Triggering immediate shutdown of current process with status {}", status,
                          new Exception("Stacktrace for immediate shutdown"));
              }
              shutdownLogging();
          } finally {
              Runtime.getRuntime().halt(status);
          }
      }
  
      private static void shutdownLogging() {
          // flush log buffers and shutdown log4j2 logging to prevent log truncation
          if (log4j2ShutdownMethod != null) {
              try {
                  // use reflection to call org.apache.logging.log4j.LogManager.shutdown()
                  log4j2ShutdownMethod.invoke(null);
              } catch (IllegalAccessException | InvocationTargetException e) {
                  log.error("Unable to call org.apache.logging.log4j.LogManager.shutdown using reflection.", e);
              }
          }
      }
  
      /**
       * Triggers an immediate forceful shutdown of the current process using 1 as the status code.
       *
       * @see Runtime#halt(int)
       */
      public static void triggerImmediateForcefulShutdown() {
          triggerImmediateForcefulShutdown(1);
      }
  }