001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, 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 v2.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 */
014
015package ch.qos.logback.classic.joran.sanity;
016
017import ch.qos.logback.classic.model.LoggerModel;
018import ch.qos.logback.classic.model.RootLoggerModel;
019import ch.qos.logback.core.joran.sanity.Pair;
020import ch.qos.logback.core.joran.sanity.SanityChecker;
021import ch.qos.logback.core.model.AppenderModel;
022import ch.qos.logback.core.model.Model;
023import ch.qos.logback.core.model.conditional.IfModel;
024import ch.qos.logback.core.spi.ContextAwareBase;
025
026import java.util.ArrayList;
027import java.util.List;
028
029import static ch.qos.logback.core.CoreConstants.CODES_URL;
030
031public class IfNestedWithinSecondPhaseElementSC extends ContextAwareBase implements SanityChecker {
032
033    static final public String NESTED_IF_WARNING_URL = CODES_URL+ "#nested_if_element";
034
035    @Override
036    public void check(Model model) {
037        if (model == null)
038            return;
039
040        List<Model> secondPhaseModels = new ArrayList<>();
041        deepFindAllModelsOfType(AppenderModel.class, secondPhaseModels, model);
042        deepFindAllModelsOfType(LoggerModel.class, secondPhaseModels, model);
043        deepFindAllModelsOfType(RootLoggerModel.class, secondPhaseModels, model);
044
045        List<Pair<Model, Model>> nestedPairs = deepFindNestedSubModelsOfType(IfModel.class, secondPhaseModels);
046
047        if (nestedPairs.isEmpty())
048            return;
049
050        addWarn("<if> elements cannot be nested within an <appender>, <logger> or <root> element");
051        addWarn("See also " + NESTED_IF_WARNING_URL);
052        for (Pair<Model, Model> pair : nestedPairs) {
053            Model p = pair.first;
054            int pLine = p.getLineNumber();
055            Model s = pair.second;
056            int sLine = s.getLineNumber();
057            addWarn("Element <"+p.getTag()+"> at line " + pLine + " contains a nested <"+s.getTag()+"> element at line " +sLine);
058        }
059    }
060
061    @Override
062    public String toString() {
063        return "IfNestedWithinSecondPhaseElementSC";
064    }
065}