1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, 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.joran.action;
15
16 import org.xml.sax.Attributes;
17
18 import ch.qos.logback.core.CoreConstants;
19 import ch.qos.logback.core.hook.ShutdownHookBase;
20 import ch.qos.logback.core.joran.spi.ActionException;
21 import ch.qos.logback.core.joran.spi.InterpretationContext;
22 import ch.qos.logback.core.util.OptionHelper;
23
24 /**
25  * Action which handles <shutdownHook> elements in configuration files.
26  * 
27  * @author Mike Reinhold
28  */

29 public class ShutdownHookAction extends Action {
30
31     ShutdownHookBase hook;
32     private boolean inError;
33
34     /**
35      * Instantiates a shutdown hook of the given class and sets its name.
36      * 
37      * The hook thus generated is placed in the {@link InterpretationContext}'s
38      * shutdown hook bag.
39      */

40     @Override
41     public void begin(InterpretationContext ic, String name, Attributes attributes) throws ActionException {
42         hook = null;
43         inError = false;
44
45         String className = attributes.getValue(CLASS_ATTRIBUTE);
46         if (OptionHelper.isEmpty(className)) {
47             addError("Missing class name for shutdown hook. Near [" + name + "] line " + getLineNumber(ic));
48             inError = true;
49             return;
50         }
51
52         try {
53             addInfo("About to instantiate shutdown hook of type [" + className + "]");
54
55             hook = (ShutdownHookBase) OptionHelper.instantiateByClassName(className, ShutdownHookBase.class, context);
56             hook.setContext(context);
57
58             ic.pushObject(hook);
59         } catch (Exception e) {
60             inError = true;
61             addError("Could not create a shutdown hook of type [" + className + "].", e);
62             throw new ActionException(e);
63         }
64     }
65
66     /**
67      * Once the children elements are also parsed, now is the time to activate the
68      * shutdown hook options.
69      */

70     @Override
71     public void end(InterpretationContext ic, String name) throws ActionException {
72         if (inError) {
73             return;
74         }
75
76         Object o = ic.peekObject();
77         if (o != hook) {
78             addWarn("The object at the of the stack is not the hook pushed earlier.");
79         } else {
80             ic.popObject();
81
82             Thread hookThread = new Thread(hook, "Logback shutdown hook [" + context.getName() + "]");
83
84             context.putObject(CoreConstants.SHUTDOWN_HOOK_THREAD, hookThread);
85             Runtime.getRuntime().addShutdownHook(hookThread);
86         }
87     }
88 }
89