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 */ 014package ch.qos.logback.classic.model.processor; 015 016import ch.qos.logback.classic.LoggerContext; 017import ch.qos.logback.classic.model.ConfigurationModel; 018import ch.qos.logback.core.Context; 019import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil; 020import ch.qos.logback.core.model.Model; 021import ch.qos.logback.core.model.processor.ModelHandlerBase; 022import ch.qos.logback.core.model.processor.ModelHandlerException; 023import ch.qos.logback.core.model.processor.ModelInterpretationContext; 024import ch.qos.logback.core.status.OnConsoleStatusListener; 025import ch.qos.logback.core.util.ContextUtil; 026import ch.qos.logback.core.util.Duration; 027import ch.qos.logback.core.util.OptionHelper; 028import ch.qos.logback.core.util.StatusListenerConfigHelper; 029 030import static ch.qos.logback.core.model.ModelConstants.DEBUG_SYSTEM_PROPERTY_KEY; 031import static ch.qos.logback.core.model.ModelConstants.NULL_STR; 032import static java.lang.Boolean.FALSE; 033 034/** 035 * In 1.3.9/1.49, ConfigurationModelHandler has been reduced in functionality and no 036 * longer initiates a reconfiguration task. This change was justified by the need 037 * to remove java.xml reachability. See also https://jira.qos.ch/browse/LOGBACK-1717 038 * 039 * <p> 040 * See {@link ConfigurationModelHandlerFull} subclass offering configuration 041 * reloading support. 042 * </p> 043 */ 044public class ConfigurationModelHandler extends ModelHandlerBase { 045 046 static final Duration SCAN_PERIOD_DEFAULT = Duration.buildByMinutes(1); 047 048 protected Boolean scanning = null; 049 050 public ConfigurationModelHandler(Context context) { 051 super(context); 052 } 053 054 static public ModelHandlerBase makeInstance(Context context, ModelInterpretationContext mic) { 055 return new ConfigurationModelHandler(context); 056 } 057 058 protected Class<ConfigurationModel> getSupportedModelClass() { 059 return ConfigurationModel.class; 060 } 061 062 @Override 063 public void handle(ModelInterpretationContext mic, Model model) { 064 065 ConfigurationModel configurationModel = (ConfigurationModel) model; 066 067 // See LOGBACK-527 (the system property is looked up first). Thus, it overrides 068 // the equivalent property in the config file. This reversal of scope priority 069 // is justified by the use case: the admin trying to chase rogue config file 070 String debugAttrib = OptionHelper.getSystemProperty(DEBUG_SYSTEM_PROPERTY_KEY, null); 071 if (debugAttrib == null) { 072 debugAttrib = mic.subst(configurationModel.getDebugStr()); 073 } 074 075 076 if (!(OptionHelper.isNullOrEmptyOrAllSpaces(debugAttrib) || debugAttrib.equalsIgnoreCase(FALSE.toString()) 077 || debugAttrib.equalsIgnoreCase(NULL_STR))) { 078 StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); 079 } 080 081 // It is hard to gauge at this stage which URL ares watchable 082 // However, we know for sure if the user wants scanning or not 083 this.scanning = scanAttrToBoolean(configurationModel); 084 085 mic.setTopScanBoolean(scanning); 086 087 printScanMessage(scanning); 088 089 if (scanning == Boolean.TRUE) { 090 ConfigurationWatchListUtil.registerNewConfigurationWatchListWithContext(getContext()); 091 ConfigurationWatchListUtil.setMainWatchURL(context, mic.getTopURL()); 092 } 093 094 LoggerContext lc = (LoggerContext) context; 095 boolean packagingData = OptionHelper.toBoolean(mic.subst(configurationModel.getPackagingDataStr()), 096 LoggerContext.DEFAULT_PACKAGING_DATA); 097 lc.setPackagingDataEnabled(packagingData); 098 099 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}