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.tyler;
016
017import ch.qos.logback.classic.Level;
018import ch.qos.logback.classic.Logger;
019import ch.qos.logback.classic.LoggerContext;
020import ch.qos.logback.classic.joran.JoranConfigurator;
021import ch.qos.logback.classic.model.ConfigurationModel;
022import ch.qos.logback.classic.util.LevelUtil;
023import ch.qos.logback.core.Context;
024import ch.qos.logback.core.joran.GenericXMLConfigurator;
025import ch.qos.logback.core.model.Model;
026import ch.qos.logback.core.model.processor.ModelHandlerBase;
027import ch.qos.logback.core.model.util.PropertyModelHandlerHelper;
028import ch.qos.logback.core.model.util.VariableSubstitutionsHelper;
029import ch.qos.logback.core.spi.ContextAwareBase;
030import ch.qos.logback.core.spi.ContextAwarePropertyContainer;
031import ch.qos.logback.core.status.OnConsoleStatusListener;
032import ch.qos.logback.core.util.OptionHelper;
033import ch.qos.logback.core.util.StatusListenerConfigHelper;
034import ch.qos.logback.core.util.StringUtil;
035
036import java.util.Map;
037import java.util.function.Supplier;
038
039public class TylerConfiguratorBase extends ContextAwareBase implements ContextAwarePropertyContainer {
040
041    public static final String SET_CONTEXT_METHOD_NAME = "setContext";
042    public static final String SET_CONTEXT_NAME_METHOD_NAME = "setContextName";
043    public static final String SETUP_LOGGER_METHOD_NAME = "setupLogger";
044    public static final String VARIABLE_SUBSTITUTIONS_HELPER_FIELD_NAME = "variableSubstitutionsHelper";
045    public static final String PROPERTY_MODEL_HANDLER_HELPER_FIELD_NAME = "propertyModelHandlerHelper";
046
047    // initialized via #setContext
048    protected VariableSubstitutionsHelper variableSubstitutionsHelper;
049    // context set in #setContext
050    protected PropertyModelHandlerHelper propertyModelHandlerHelper = new PropertyModelHandlerHelper(this);
051
052    protected Logger setupLogger(String loggerName, String levelString, Boolean additivity) {
053        LoggerContext loggerContext = (LoggerContext) context;
054        Logger logger = loggerContext.getLogger(loggerName);
055        if (!OptionHelper.isNullOrEmptyOrAllSpaces(levelString)) {
056            Level level = LevelUtil.levelStringToLevel(levelString);
057            logger.setLevel(level);
058        }
059        if (additivity != null) {
060            logger.setAdditive(additivity);
061        }
062        return logger;
063    }
064
065    @Override
066    public void setContext(Context context) {
067        super.setContext(context);
068        variableSubstitutionsHelper = new VariableSubstitutionsHelper(context);
069        propertyModelHandlerHelper.setContext(context);
070    }
071
072    protected void setContextName(String name) {
073        if (StringUtil.isNullOrEmpty(name)) {
074            addError("Cannot set context name to null or empty string");
075            return;
076        }
077        try {
078            String substName = subst(name);
079            addInfo("Setting context name to [" + substName + "]");
080            context.setName(substName);
081        } catch (IllegalStateException e) {
082            addError("Failed to rename context as [" + name + "]");
083        }
084    }
085
086    protected void addOnConsoleStatusListener() {
087        StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
088    }
089
090    /**
091     * Performs variable substitution.
092     *
093     * @param ref
094     * @return
095     */
096    @Override
097    public String subst(String ref) {
098        return variableSubstitutionsHelper.subst(ref);
099    }
100
101    @Override
102    public void addSubstitutionProperty(String key, String value) {
103        variableSubstitutionsHelper.addSubstitutionProperty(key, value);
104    }
105
106    /**
107     * If a key is found in propertiesMap then return it.
108     */
109    @Override
110    public String getProperty(String key) {
111        return variableSubstitutionsHelper.getProperty(key);
112    }
113
114    @Override
115    public Map<String, String> getCopyOfPropertyMap() {
116        return variableSubstitutionsHelper.getCopyOfPropertyMap();
117    }
118
119    public boolean isNull(String k) {
120        String val = OptionHelper.propertyLookup(k, this, context);
121        return (val == null);
122    }
123
124    /**
125     * Method used in conditional evaluation
126     *
127     * @param k  a property name
128     * @return true if the property is defined
129     * @since 1.5.4
130     */
131    public boolean isDefined(String k) {
132        String val = OptionHelper.propertyLookup(k, this, context);
133        return (val != null);
134    }
135
136    /**
137     * Shorthand for {@link #property(String)}.
138     *
139     * @param k a property name
140     * @return value of property k
141     * @since 1.5.4
142     */
143    public String p(String k) {
144        return property(k);
145    }
146
147    /**
148     * Return the value of the property named k. If the value is null, then the
149     * empty string is returned to avoid null checks.
150     *
151     * @param k property name
152     * @return the value of the property named k
153     * @since 1.5.4
154     */
155    public String property(String k) {
156        String val = OptionHelper.propertyLookup(k, this, context);
157        if (val != null)
158            return val;
159        else
160            return "";
161    }
162
163    private JoranConfigurator makeAnotherInstance() {
164        JoranConfigurator jc = new JoranConfigurator();
165        jc.setContext(context);
166        return jc;
167    }
168
169    /**
170     * Return a supplier which supplies an instance of {@link JoranConfigurator} set to
171     * the same context the context of 'this'.
172     * @since 1.5.11
173     */
174    @Override
175    public Supplier<? extends GenericXMLConfigurator> getConfiguratorSupplier() {
176        Supplier<? extends GenericXMLConfigurator> supplier = () -> this.makeAnotherInstance();
177        return supplier;
178    }
179
180    // used by TylerIncludeModelHandler in logback-tyler
181    protected void processModelFromIncludedFile(Model modelFromIncludedFile) {
182        Supplier<? extends GenericXMLConfigurator > configuratorSupplier = this.getConfiguratorSupplier();
183        GenericXMLConfigurator genericXMLConfigurator = configuratorSupplier.get();
184        ConfigurationModel configurationModel = new ConfigurationModel();
185        configurationModel.addSubModel(modelFromIncludedFile);
186        genericXMLConfigurator.processModel(configurationModel);
187    }
188}