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.ContextUtil;
24  import ch.qos.logback.core.util.DynamicClassLoadingException;
25  import ch.qos.logback.core.util.IncompatibleClassException;
26  import ch.qos.logback.core.util.OptionHelper;
27  
28  public class ShutdownHookModelHandler extends ModelHandlerBase {
29  
30      static final String OLD_SHUTDOWN_HOOK_CLASSNAME = "ch.qos.logback.core.hook.DelayingShutdownHook";
31      static final String DEFAULT_SHUTDOWN_HOOK_CLASSNAME = DefaultShutdownHook.class.getName();
32      static public final String RENAME_WARNING = OLD_SHUTDOWN_HOOK_CLASSNAME + " was renamed as "+ DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
33  
34      public ShutdownHookModelHandler(Context context) {
35          super(context);
36      }
37      boolean inError = false;
38      ShutdownHook  hook = null;
39  
40      static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext mic) {
41          return new ShutdownHookModelHandler(context);
42      }
43  
44      @Override
45      protected Class<ShutdownHookModel> getSupportedModelClass() {
46          return ShutdownHookModel.class;
47      }
48  
49      @Override
50      public void handle(ModelInterpretationContext mic, Model model) {
51  
52          ShutdownHookModel shutdownHookModel = (ShutdownHookModel) model;
53  
54          String className = shutdownHookModel.getClassName();
55          if (OptionHelper.isNullOrEmptyOrAllSpaces(className)) {
56              className = DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
57              addInfo("Assuming className [" + className + "]");
58          } else {
59              className = mic.getImport(className);
60              if(className.equals(OLD_SHUTDOWN_HOOK_CLASSNAME)) {
61                  className = DEFAULT_SHUTDOWN_HOOK_CLASSNAME;
62                  addWarn(RENAME_WARNING);
63                  addWarn("Please use the new class name");
64              }
65          }
66  
67          addInfo("About to instantiate shutdown hook of type [" + className + "]");
68  
69          try {
70              hook = (ShutdownHookBase) OptionHelper.instantiateByClassName(className, ShutdownHookBase.class, context);
71              hook.setContext(context);
72          } catch (IncompatibleClassException | DynamicClassLoadingException e) {
73              addError("Could not create a shutdown hook of type [" + className + "].", e);
74              inError = true;
75              return;
76          }
77  
78          mic.pushObject(hook);
79      }
80  
81      @Override
82      public void postHandle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
83          if (inError) {
84              return;
85          }
86          Object o = mic.peekObject();
87  
88          if (o != hook) {
89              addWarn("The object on the top the of the stack is not the hook object pushed earlier.");
90          } else {
91              ContextUtil contextUtil = new ContextUtil(context);
92              contextUtil.addOrReplaceShutdownHook(hook);
93              mic.popObject();
94          }
95      }
96  }