1   /*
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2026, 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 v2.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  
15  package ch.qos.logback.classic.tyler;
16  
17  import ch.qos.logback.classic.Level;
18  import ch.qos.logback.classic.Logger;
19  import ch.qos.logback.classic.LoggerContext;
20  import ch.qos.logback.classic.joran.JoranConfigurator;
21  import ch.qos.logback.classic.model.ConfigurationModel;
22  import ch.qos.logback.classic.util.LevelUtil;
23  import ch.qos.logback.core.Context;
24  import ch.qos.logback.core.joran.GenericXMLConfigurator;
25  import ch.qos.logback.core.model.Model;
26  import ch.qos.logback.core.model.processor.ModelHandlerBase;
27  import ch.qos.logback.core.model.util.PropertyModelHandlerHelper;
28  import ch.qos.logback.core.model.util.VariableSubstitutionsHelper;
29  import ch.qos.logback.core.spi.ContextAwareBase;
30  import ch.qos.logback.core.spi.ContextAwarePropertyContainer;
31  import ch.qos.logback.core.status.OnConsoleStatusListener;
32  import ch.qos.logback.core.util.OptionHelper;
33  import ch.qos.logback.core.util.StatusListenerConfigHelper;
34  import ch.qos.logback.core.util.StringUtil;
35  
36  import java.util.Map;
37  import java.util.function.Supplier;
38  
39  public class TylerConfiguratorBase extends ContextAwareBase implements ContextAwarePropertyContainer {
40  
41      public static final String SET_CONTEXT_METHOD_NAME = "setContext";
42      public static final String SET_CONTEXT_NAME_METHOD_NAME = "setContextName";
43      public static final String SETUP_LOGGER_METHOD_NAME = "setupLogger";
44      public static final String VARIABLE_SUBSTITUTIONS_HELPER_FIELD_NAME = "variableSubstitutionsHelper";
45      public static final String PROPERTY_MODEL_HANDLER_HELPER_FIELD_NAME = "propertyModelHandlerHelper";
46  
47      // initialized via #setContext
48      protected VariableSubstitutionsHelper variableSubstitutionsHelper;
49      // context set in #setContext
50      protected PropertyModelHandlerHelper propertyModelHandlerHelper = new PropertyModelHandlerHelper(this);
51  
52      protected Logger setupLogger(String loggerName, String levelString, Boolean additivity) {
53          LoggerContext loggerContext = (LoggerContext) context;
54          Logger logger = loggerContext.getLogger(loggerName);
55          if (!OptionHelper.isNullOrEmptyOrAllSpaces(levelString)) {
56              Level level = LevelUtil.levelStringToLevel(levelString);
57              logger.setLevel(level);
58          }
59          if (additivity != null) {
60              logger.setAdditive(additivity);
61          }
62          return logger;
63      }
64  
65      @Override
66      public void setContext(Context context) {
67          super.setContext(context);
68          variableSubstitutionsHelper = new VariableSubstitutionsHelper(context);
69          propertyModelHandlerHelper.setContext(context);
70      }
71  
72      protected void setContextName(String name) {
73          if (StringUtil.isNullOrEmpty(name)) {
74              addError("Cannot set context name to null or empty string");
75              return;
76          }
77          try {
78              String substName = subst(name);
79              addInfo("Setting context name to [" + substName + "]");
80              context.setName(substName);
81          } catch (IllegalStateException e) {
82              addError("Failed to rename context as [" + name + "]");
83          }
84      }
85  
86      protected void addOnConsoleStatusListener() {
87          StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
88      }
89  
90      /**
91       * Performs variable substitution.
92       *
93       * @param ref
94       * @return
95       */
96      @Override
97      public String subst(String ref) {
98          return variableSubstitutionsHelper.subst(ref);
99      }
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 }