001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2022, 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.joran.spi.ActionException;
019import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
020import ch.qos.logback.core.model.Model;
021
022public abstract class BaseModelAction extends Action {
023
024    Model parentModel;
025    Model currentModel;
026    boolean inError = false;
027
028    @Override
029    public void begin(SaxEventInterpretationContext saxEventInterpretationContext, String name, Attributes attributes)
030            throws ActionException {
031        parentModel = null;
032        inError = false;
033
034        if (!validPreconditions(saxEventInterpretationContext, name, attributes)) {
035            inError = true;
036            return;
037        }
038
039        currentModel = buildCurrentModel(saxEventInterpretationContext, name, attributes);
040        currentModel.setTag(name);
041        if (!saxEventInterpretationContext.isModelStackEmpty()) {
042            parentModel = saxEventInterpretationContext.peekModel();
043        }
044        final int lineNumber = getLineNumber(saxEventInterpretationContext);
045        currentModel.setLineNumber(lineNumber);
046        saxEventInterpretationContext.pushModel(currentModel);
047    }
048
049    abstract protected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,
050            Attributes attributes);
051
052    /**
053     * Validate preconditions of this action.
054     * 
055     * By default, true is returned. Subclasses should override appropriately.
056     * 
057     * @param intercon
058     * @param name
059     * @param attributes
060     * @return
061     */
062    protected boolean validPreconditions(SaxEventInterpretationContext intercon, String name, Attributes attributes) {
063        return true;
064    }
065
066    @Override
067    public void body(SaxEventInterpretationContext ec, String body) throws ActionException {
068        if(currentModel == null) {
069            throw new ActionException("current model is null. Is <configuration> element missing?");
070        }
071        currentModel.addText(body);
072    }
073
074    @Override
075    public void end(SaxEventInterpretationContext saxEventInterpretationContext, String name) throws ActionException {
076        if (inError)
077            return;
078
079        Model m = saxEventInterpretationContext.peekModel();
080
081        if (m != currentModel) {
082            addWarn("The object "+ m +"] at the top of the stack differs from the model [" + currentModel.idString()
083                    + "] pushed earlier.");
084            addWarn("This is wholly unexpected.");
085        }
086
087        // do not pop nor add to parent if there is no parent
088        if (parentModel != null) {
089            parentModel.addSubModel(currentModel);
090            saxEventInterpretationContext.popModel();
091        }
092    }
093}