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  package ch.qos.logback.classic.model.processor;
15  
16  import ch.qos.logback.classic.LoggerContext;
17  import ch.qos.logback.classic.model.ConfigurationModel;
18  import ch.qos.logback.core.Context;
19  import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
20  import ch.qos.logback.core.model.Model;
21  import ch.qos.logback.core.model.processor.ModelHandlerBase;
22  import ch.qos.logback.core.model.processor.ModelHandlerException;
23  import ch.qos.logback.core.model.processor.ModelInterpretationContext;
24  import ch.qos.logback.core.status.OnConsoleStatusListener;
25  import ch.qos.logback.core.util.ContextUtil;
26  import ch.qos.logback.core.util.Duration;
27  import ch.qos.logback.core.util.OptionHelper;
28  import ch.qos.logback.core.util.StatusListenerConfigHelper;
29  
30  import static ch.qos.logback.core.model.ModelConstants.DEBUG_SYSTEM_PROPERTY_KEY;
31  import static ch.qos.logback.core.model.ModelConstants.NULL_STR;
32  import static java.lang.Boolean.FALSE;
33  
34  /**
35   * In 1.3.9/1.49, ConfigurationModelHandler has been reduced in functionality and no
36   * longer initiates a reconfiguration task. This change was justified by the need
37   * to remove java.xml reachability. See also https://jira.qos.ch/browse/LOGBACK-1717
38   *
39   * <p>
40   * See {@link ConfigurationModelHandlerFull} subclass offering configuration
41   * reloading support.
42   * </p>
43   */
44  public class ConfigurationModelHandler extends ModelHandlerBase {
45  
46      static final Duration SCAN_PERIOD_DEFAULT = Duration.buildByMinutes(1);
47  
48      protected Boolean scanning = null;
49  
50      public ConfigurationModelHandler(Context context) {
51          super(context);
52      }
53  
54      static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext mic) {
55          return new ConfigurationModelHandler(context);
56      }
57  
58      protected Class<ConfigurationModel> getSupportedModelClass() {
59          return ConfigurationModel.class;
60      }
61  
62      @Override
63      public void handle(ModelInterpretationContext mic, Model model) {
64  
65          ConfigurationModel configurationModel = (ConfigurationModel) model;
66  
67          // See LOGBACK-527 (the system property is looked up first). Thus, it overrides
68          // the equivalent property in the config file. This reversal of scope priority
69          // is justified by the use case: the admin trying to chase rogue config file
70          String debugAttrib = OptionHelper.getSystemProperty(DEBUG_SYSTEM_PROPERTY_KEY, null);
71          if (debugAttrib == null) {
72              debugAttrib = mic.subst(configurationModel.getDebugStr());
73          }
74          
75  
76          if (!(OptionHelper.isNullOrEmptyOrAllSpaces(debugAttrib) || debugAttrib.equalsIgnoreCase(FALSE.toString())
77                  || debugAttrib.equalsIgnoreCase(NULL_STR))) {
78              StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
79          }
80  
81          // It is hard to gauge at this stage which URL ares watchable
82          // However, we know for sure if the user wants scanning or not
83          this.scanning = scanAttrToBoolean(configurationModel);
84  
85          mic.setTopScanBoolean(scanning);
86  
87          printScanMessage(scanning);
88  
89          if (scanning == Boolean.TRUE) {
90              ConfigurationWatchListUtil.registerNewConfigurationWatchListWithContext(getContext());
91              ConfigurationWatchListUtil.setMainWatchURL(context, mic.getTopURL());
92          }
93  
94          LoggerContext lc = (LoggerContext) context;
95          boolean packagingData = OptionHelper.toBoolean(mic.subst(configurationModel.getPackagingDataStr()),
96                  LoggerContext.DEFAULT_PACKAGING_DATA);
97          lc.setPackagingDataEnabled(packagingData);
98  
99          ContextUtil contextUtil = new ContextUtil(context);
100         contextUtil.addGroovyPackages(lc.getFrameworkPackages());
101 
102 
103     }
104 
105     void printScanMessage(Boolean scanning) {
106         if (scanning == null) {
107             addInfo("Scan attribute not set or set to unrecognized value.");
108             return;
109         }
110         if (scanning) {
111             addInfo("Scan attribute set to true. Will scan for configuration file changes.");
112         } else  {
113             addInfo("Scan attribute set to false.");
114         }
115     }
116 
117 
118     @Override
119     public void postHandle(ModelInterpretationContext mic, Model model) throws ModelHandlerException {
120         //ConfigurationModel configurationModel = (ConfigurationModel) model;
121 
122     }
123 
124     /**
125      * Converts the scan string attribute of the given model to a Boolean value.
126      *
127      * <p>If the provided model is an instance of {@code ConfigurationModel}, the scan string is retrieved
128      * and converted to a {@code Boolean}. If the provided model is not a {@code ConfigurationModel},
129      * the method returns {@code null}.
130      * </p>
131      *
132      * @param model the model object, which may be an instance of {@code ConfigurationModel}
133      * @return a {@code Boolean} corresponding to the scan string attribute if the model is
134      *         an instance of {@code ConfigurationModel}, or {@code null} otherwise
135      *
136      * @since 1.5.27
137      */
138     private Boolean scanAttrToBoolean(Model model) {
139         if(model instanceof ConfigurationModel) {
140             ConfigurationModel configurationModel = (ConfigurationModel) model;
141             String scanStr = configurationModel.getScanStr();
142             return OptionHelper.toBooleanObject(scanStr);
143         } else {
144             return null;
145         }
146 
147     }
148 }