View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2022, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.model.processor;
15  
16  import ch.qos.logback.core.Context;
17  import ch.qos.logback.core.CoreConstants;
18  import ch.qos.logback.core.hook.DefaultShutdownHook;
19  import ch.qos.logback.core.hook.ShutdownHook;
20  import ch.qos.logback.core.hook.ShutdownHookBase;
21  import ch.qos.logback.core.model.Model;
22  import ch.qos.logback.core.model.ShutdownHookModel;
23  import ch.qos.logback.core.util.DynamicClassLoadingException;
24  import ch.qos.logback.core.util.IncompatibleClassException;
25  import ch.qos.logback.core.util.OptionHelper;
26  
27  public class ShutdownHookModelHandler extends ModelHandlerBase {
28  
29      static final String OLD_SHUTDOWN_HOOK_CLASSNAME = "ch.qos.logback.core.hook.DelayingShutdownHook";
30      static final String DEFAULT_SHUTDOWN_HOOK_CLASSNAME = DefaultShutdownHook.class.getName();
31      static public final String RENAME_WARNING = OLD_SHUTDOWN_HOOK_CLASSNAME + " was renamed as "+ DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
32  
33      public ShutdownHookModelHandler(Context context) {
34          super(context);
35      }
36      boolean inError = false;
37      ShutdownHook  hook = null;
38  
39      static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext mic) {
40          return new ShutdownHookModelHandler(context);
41      }
42  
43      @Override
44      protected Class<ShutdownHookModel> getSupportedModelClass() {
45          return ShutdownHookModel.class;
46      }
47  
48      @Override
49      public void handle(ModelInterpretationContext mic, Model model) {
50  
51          ShutdownHookModel shutdownHookModel = (ShutdownHookModel) model;
52  
53          String className = shutdownHookModel.getClassName();
54          if (OptionHelper.isNullOrEmptyOrAllSpaces(className)) {
55              className = DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
56              addInfo("Assuming className [" + className + "]");
57          } else {
58              className = mic.getImport(className);
59              if(className.equals(OLD_SHUTDOWN_HOOK_CLASSNAME)) {
60                  className = DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
61                  addWarn(RENAME_WARNING);
62                  addWarn("Please use the new class name");
63              }
64          }
65  
66          addInfo("About to instantiate shutdown hook of type [" + className + "]");
67  
68          try {
69              hook = (ShutdownHookBase) OptionHelper.instantiateByClassName(className, ShutdownHookBase.class, context);
70              hook.setContext(context);
71          } catch (IncompatibleClassException | DynamicClassLoadingException e) {
72              addError("Could not create a shutdown hook of type [" + className + "].", e);
73              inError = true;
74              return;
75          }
76  
77          mic.pushObject(hook);
78      }
79  
80      @Override
81      public void postHandle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
82          if (inError) {
83              return;
84          }
85          Object o = mic.peekObject();
86  
87          if (o != hook) {
88              addWarn("The object on the top the of the stack is not the hook object pushed earlier.");
89          } else {
90              Thread hookThread = new Thread(hook, "Logback shutdown hook [" + context.getName() + "]");
91              addInfo("Registering shutdown hook with JVM runtime.");
92              context.putObject(CoreConstants.SHUTDOWN_HOOK_THREAD, hookThread);
93              Runtime.getRuntime().addShutdownHook(hookThread);
94  
95              mic.popObject();
96          }
97      }
98  }