001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.action;
015
016import org.xml.sax.Attributes;
017
018import ch.qos.logback.core.CoreConstants;
019import ch.qos.logback.core.hook.DefaultShutdownHook;
020import ch.qos.logback.core.hook.ShutdownHookBase;
021import ch.qos.logback.core.joran.spi.ActionException;
022import ch.qos.logback.core.joran.spi.InterpretationContext;
023import ch.qos.logback.core.util.OptionHelper;
024
025/**
026 * Action which handles <shutdownHook> elements in configuration files.
027 * 
028 * @author Mike Reinhold
029 */
030public class ShutdownHookAction extends Action {
031
032    ShutdownHookBase hook;
033    private boolean inError;
034
035    /**
036     * Instantiates a shutdown hook of the given class and sets its name.
037     * 
038     * The hook thus generated is placed in the {@link InterpretationContext}'s
039     * shutdown hook bag.
040     */
041    @Override
042    public void begin(InterpretationContext ic, String name, Attributes attributes) throws ActionException {
043        hook = null;
044        inError = false;
045
046        String className = attributes.getValue(CLASS_ATTRIBUTE);
047        if (OptionHelper.isEmpty(className)) {
048            className = DefaultShutdownHook.class.getName();
049            addInfo("Assuming className [" + className + "]");
050        }
051
052        try {
053            addInfo("About to instantiate shutdown hook of type [" + className + "]");
054
055            hook = (ShutdownHookBase) OptionHelper.instantiateByClassName(className, ShutdownHookBase.class, context);
056            hook.setContext(context);
057
058            ic.pushObject(hook);
059        } catch (Exception e) {
060            inError = true;
061            addError("Could not create a shutdown hook of type [" + className + "].", e);
062            throw new ActionException(e);
063        }
064    }
065
066    /**
067     * Once the children elements are also parsed, now is the time to activate the
068     * shutdown hook options.
069     */
070    @Override
071    public void end(InterpretationContext ic, String name) throws ActionException {
072        if (inError) {
073            return;
074        }
075
076        Object o = ic.peekObject();
077        if (o != hook) {
078            addWarn("The object at the of the stack is not the hook pushed earlier.");
079        } else {
080            ic.popObject();
081
082            Thread hookThread = new Thread(hook, "Logback shutdown hook [" + context.getName() + "]");
083            addInfo("Registeting shuthown hook with JVM runtime.");
084            context.putObject(CoreConstants.SHUTDOWN_HOOK_THREAD, hookThread);
085            Runtime.getRuntime().addShutdownHook(hookThread);
086        }
087    }
088}