From 26b9106f96b3065205e7b3bda419976e76a1ec9a Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Mon, 26 Feb 2024 23:34:20 +0100 Subject: [PATCH] refactoring Property* related code Signed-off-by: Ceki Gulcu --- .../classic/tyler/TylerConfiguratorBase.java | 106 ++++++++++++++- .../classic/tyler/VariableModelHelper.java | 122 ++++++++++++++++++ .../classic/sift/SiftingAppenderTest.java | 2 + .../java/ch/qos/logback/core/ContextBase.java | 10 ++ .../spi/SaxEventInterpretationContext.java | 5 +- .../logback/core/model/ModelConstants.java | 5 +- .../processor/ModelInterpretationContext.java | 50 ++----- .../model/processor/PropertyModelHandler.java | 43 +----- .../core/model/util/PropertyModelUtil.java | 49 +++++++ .../util/VariableSubstitutionsHelper.java | 82 ++++++++++++ .../logback/core/spi/PropertyContainer.java | 15 +++ .../core/joran/action/PropertyActionTest.java | 3 +- 12 files changed, 410 insertions(+), 82 deletions(-) create mode 100644 logback-classic/src/main/java/ch/qos/logback/classic/tyler/VariableModelHelper.java create mode 100644 logback-core/src/main/java/ch/qos/logback/core/model/util/PropertyModelUtil.java create mode 100644 logback-core/src/main/java/ch/qos/logback/core/model/util/VariableSubstitutionsHelper.java diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java index df955fd0cc..b5a6e538c3 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java @@ -1,2 +1,106 @@ -package ch.qos.logback.classic.tyler;public class TylerConfiguratorBase { +/* + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ + +package ch.qos.logback.classic.tyler; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.core.model.util.VariableSubstitutionsHelper; +import ch.qos.logback.core.spi.ContextAwareBase; +import ch.qos.logback.core.spi.PropertyContainer; +import ch.qos.logback.core.spi.ScanException; +import ch.qos.logback.core.status.OnConsoleStatusListener; +import ch.qos.logback.core.util.OptionHelper; +import ch.qos.logback.core.util.StatusListenerConfigHelper; +import ch.qos.logback.core.util.StringUtil; + +import java.util.HashMap; +import java.util.Map; + +public class TylerConfiguratorBase extends ContextAwareBase implements PropertyContainer { + + public static final String SET_CONTEXT_NAME = "setContextName"; + public static final String SETUP_LOGGER_METHOD_NAME = "setupLogger"; + + VariableSubstitutionsHelper variableSubstitutionsHelper; + + private Logger setupLogger(String loggerName, Level level, String levelString, Boolean additivity) { + LoggerContext loggerContext = (LoggerContext) context; + Logger logger = loggerContext.getLogger(loggerName); + if (!OptionHelper.isNullOrEmptyOrAllSpaces(levelString)) { + logger.setLevel(level); + } + if (additivity != null) { + logger.setAdditive(additivity); + } + return logger; + } + + protected void setContextName(String name) { + if(StringUtil.isNullOrEmpty(name)) { + addError("Cannot set context name to null or empty string"); + return; + } + try { + String substName = subst(name); + addInfo("Setting context name to ["+substName+"]"); + context.setName(substName); + } catch (IllegalStateException e) { + addError("Failed to rename context as [" + name + "]"); + } + } + + protected void addOnConsoleStatusListener() { + StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener()); + } + + /** + * Performs variable substitution. + * + * @param ref + * @return + */ + public String subst(String ref) { + if (ref == null) { + return null; + } + + try { + return OptionHelper.substVars(ref, this, context); + } catch (ScanException | IllegalArgumentException e) { + addError("Problem while parsing [" + ref + "]", e); + return ref; + } + } + + @Override + public void addSubstitutionProperty(String key, String value) { + variableSubstitutionsHelper.addSubstitutionProperty(key, value); + } + + /** + * If a key is found in propertiesMap then return it. + */ + @Override + public String getProperty(String key) { + return variableSubstitutionsHelper.getProperty(key); + } + + @Override + public Map getCopyOfPropertyMap() { + return variableSubstitutionsHelper.getCopyOfPropertyMap(); + } + } diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/tyler/VariableModelHelper.java b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/VariableModelHelper.java new file mode 100644 index 0000000000..c2fa8b5887 --- /dev/null +++ b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/VariableModelHelper.java @@ -0,0 +1,122 @@ +/* + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ + +package ch.qos.logback.classic.tyler; + +import ch.qos.logback.core.Context; +import ch.qos.logback.core.joran.action.ActionUtil; +import ch.qos.logback.core.model.ModelConstants; +import ch.qos.logback.core.model.PropertyModel; +import ch.qos.logback.core.model.util.PropertyModelUtil; +import ch.qos.logback.core.model.util.VariableSubstitutionsHelper; +import ch.qos.logback.core.spi.ContextAwareBase; +import ch.qos.logback.core.util.ContextUtil; +import ch.qos.logback.core.util.Loader; +import ch.qos.logback.core.util.OptionHelper; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Properties; + +public class VariableModelHelper extends ContextAwareBase { + + TylerConfiguratorBase tylerConfiguratorBase; + VariableSubstitutionsHelper variableSubstitutionsHelper; + + VariableModelHelper(Context context, TylerConfiguratorBase tylerConfiguratorBase) { + super( tylerConfiguratorBase); + this.context = context; + this.tylerConfiguratorBase = tylerConfiguratorBase; + this.variableSubstitutionsHelper = new VariableSubstitutionsHelper(context); + } + + void updateProperties(PropertyModel propertyModel) { + + ActionUtil.Scope scope = ActionUtil.stringToScope(propertyModel.getScopeStr()); + if (PropertyModelUtil.checkFileAttributeSanity(propertyModel)) { + String file = propertyModel.getFile(); + file = tylerConfiguratorBase.subst(file); + try (FileInputStream istream = new FileInputStream(file)) { + loadAndSetProperties(istream, scope); + } catch (FileNotFoundException e) { + addError("Could not find properties file [" + file + "]."); + } catch (IOException |IllegalArgumentException e1) { // IllegalArgumentException is thrown in case the file + // is badly malformed, i.e a binary. + addError("Could not read properties file [" + file + "].", e1); + } + } else if (PropertyModelUtil.checkResourceAttributeSanity(propertyModel)) { + String resource = propertyModel.getResource(); + resource = tylerConfiguratorBase.subst(resource); + URL resourceURL = Loader.getResourceBySelfClassLoader(resource); + if (resourceURL == null) { + addError("Could not find resource [" + resource + "]."); + } else { + try ( InputStream istream = resourceURL.openStream();) { + loadAndSetProperties(istream, scope); + } catch (IOException e) { + addError("Could not read resource file [" + resource + "].", e); + } + } + } else if (PropertyModelUtil.checkValueNameAttributesSanity(propertyModel)) { + // earlier versions performed Java '\' escapes for '\\' '\t' etc. Howevver, there is no + // need to do this. See RegularEscapeUtil.__UNUSED__basicEscape + String value = propertyModel.getValue(); + + // now remove both leading and trailing spaces + value = value.trim(); + value = tylerConfiguratorBase.subst(value); + setProperty(propertyModel.getName(), value, scope); + + } else { + addError(ModelConstants.INVALID_ATTRIBUTES); + } + } + + void loadAndSetProperties(InputStream istream, ActionUtil.Scope scope) throws IOException { + Properties props = new Properties(); + props.load(istream); + setProperties(props, scope); + } + + + public void setProperties(Properties props, ActionUtil.Scope scope) { + switch (scope) { + case LOCAL: + variableSubstitutionsHelper.addSubstitutionProperties(props); + break; + case CONTEXT: + ContextUtil cu = new ContextUtil(getContext()); + cu.addProperties(props); + break; + case SYSTEM: + OptionHelper.setSystemProperties(this, props); + } + } + + public void setProperty(String key, String value, ActionUtil.Scope scope) { + switch (scope) { + case LOCAL: + variableSubstitutionsHelper.addSubstitutionProperty(key, value); + break; + case CONTEXT: + getContext().putProperty(key, value); + break; + case SYSTEM: + OptionHelper.setSystemProperty(this, key, value); + } + } +} diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/sift/SiftingAppenderTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/sift/SiftingAppenderTest.java index 243cce5169..bc7a59f87a 100644 --- a/logback-classic/src/test/java/ch/qos/logback/classic/sift/SiftingAppenderTest.java +++ b/logback-classic/src/test/java/ch/qos/logback/classic/sift/SiftingAppenderTest.java @@ -42,6 +42,7 @@ import ch.qos.logback.core.testUtil.StringListAppender; import ch.qos.logback.core.util.FileSize; +import ch.qos.logback.core.util.StatusPrinter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -244,6 +245,7 @@ public void localPropertiesShouldBeVisible() throws JoranException { SiftingAppender sa = (SiftingAppender) root.getAppender("SIFT"); StringListAppender listAppender = (StringListAppender) sa.getAppenderTracker().find(mdcVal); assertNotNull(listAppender); + List strList = listAppender.strList; assertEquals(1, listAppender.strList.size()); assertEquals(prefix + msg, strList.get(0)); diff --git a/logback-core/src/main/java/ch/qos/logback/core/ContextBase.java b/logback-core/src/main/java/ch/qos/logback/core/ContextBase.java index 96afce2808..0c9920dacb 100755 --- a/logback-core/src/main/java/ch/qos/logback/core/ContextBase.java +++ b/logback-core/src/main/java/ch/qos/logback/core/ContextBase.java @@ -107,6 +107,16 @@ protected void initCollisionMaps() { putObject(RFA_FILENAME_PATTERN_COLLISION_MAP, new HashMap()); } + @Override + public void addSubstitutionProperty(String key, String value) { + if (key == null || value == null) { + return; + } + // values with leading or trailing spaces are bad. We remove them now. + value = value.trim(); + propertyMap.put(key, value); + } + /** * Given a key, return the corresponding property value. If invoked with the * special key "CONTEXT_NAME", the name of the context is returned. diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SaxEventInterpretationContext.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SaxEventInterpretationContext.java index 21b3f0d36e..05f474d4c9 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SaxEventInterpretationContext.java +++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SaxEventInterpretationContext.java @@ -77,6 +77,10 @@ public Stack getCopyOfModelStack() { return copy; } + public void addSubstitutionProperty(String key, String value) { + throw new UnsupportedOperationException(); + } + /** * If a key is found in propertiesMap then return it. Otherwise, delegate to the * context. @@ -85,7 +89,6 @@ public String getProperty(String key) { return context.getProperty(key); } - @Override public Map getCopyOfPropertyMap() { return null; } diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/ModelConstants.java b/logback-core/src/main/java/ch/qos/logback/core/model/ModelConstants.java index 53c772c5e2..dba881e15f 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/model/ModelConstants.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/ModelConstants.java @@ -20,5 +20,8 @@ public class ModelConstants { public static final String DEBUG_SYSTEM_PROPERTY_KEY = "logback.debug"; public static final String NULL_STR = CoreConstants.NULL_STR; - + + public static final String INVALID_ATTRIBUTES = "In element, either the \"file\" attribute alone, or " + + "the \"resource\" element alone, or both the \"name\" and \"value\" attributes must be set."; + } diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java index eff8325bcf..30eadb6c01 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java @@ -27,11 +27,10 @@ import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry; import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache; import ch.qos.logback.core.model.Model; +import ch.qos.logback.core.model.util.VariableSubstitutionsHelper; import ch.qos.logback.core.spi.AppenderAttachable; import ch.qos.logback.core.spi.ContextAwareBase; import ch.qos.logback.core.spi.PropertyContainer; -import ch.qos.logback.core.spi.ScanException; -import ch.qos.logback.core.util.OptionHelper; public class ModelInterpretationContext extends ContextAwareBase implements PropertyContainer { @@ -39,7 +38,7 @@ public class ModelInterpretationContext extends ContextAwareBase implements Prop Stack modelStack; Map objectMap; - protected Map propertiesMap; + protected VariableSubstitutionsHelper variableSubstitutionsHelper; protected Map importMap; final private BeanDescriptionCache beanDescriptionCache; @@ -62,14 +61,14 @@ public ModelInterpretationContext(Context context, Object configuratorHint) { this.modelStack = new Stack<>(); this.beanDescriptionCache = new BeanDescriptionCache(context); objectMap = new HashMap<>(5); - propertiesMap = new HashMap<>(5); + variableSubstitutionsHelper = new VariableSubstitutionsHelper(context); importMap = new HashMap<>(5); } public ModelInterpretationContext(ModelInterpretationContext otherMic) { this(otherMic.context, otherMic.configuratorHint); importMap = new HashMap<>(otherMic.importMap); - propertiesMap = new HashMap<>(otherMic.propertiesMap); + variableSubstitutionsHelper = new VariableSubstitutionsHelper(context, otherMic.getCopyOfPropertyMap()); defaultNestedComponentRegistry.duplicate(otherMic.getDefaultNestedComponentRegistry()); createAppenderBags(); } @@ -149,18 +148,8 @@ public BeanDescriptionCache getBeanDescriptionCache() { return beanDescriptionCache; } - public String subst(String ref) { - if (ref == null) { - return null; - } - - try { - return OptionHelper.substVars(ref, this, context); - } catch (ScanException | IllegalArgumentException e) { - addError("Problem while parsing [" + ref + "]", e); - return ref; - } - + public String subst(String ref) { + return variableSubstitutionsHelper.subst(ref); } /** @@ -168,23 +157,7 @@ public String subst(String ref) { * exists already, it is overwritten. */ public void addSubstitutionProperty(String key, String value) { - if (key == null || value == null) { - return; - } - // values with leading or trailing spaces are bad. We remove them now. - value = value.trim(); - propertiesMap.put(key, value); - } - - public void addSubstitutionProperties(Properties props) { - if (props == null) { - return; - } - for (Object keyObject : props.keySet()) { - String key = (String) keyObject; - String val = props.getProperty(key); - addSubstitutionProperty(key, val); - } + variableSubstitutionsHelper.addSubstitutionProperty(key, value); } public DefaultNestedComponentRegistry getDefaultNestedComponentRegistry() { @@ -241,17 +214,12 @@ public boolean isNamedDependeeStarted(String name) { * context. */ public String getProperty(String key) { - String v = propertiesMap.get(key); - if (v != null) { - return v; - } else { - return context.getProperty(key); - } + return variableSubstitutionsHelper.getProperty(key); } @Override public Map getCopyOfPropertyMap() { - return new HashMap(propertiesMap); + return variableSubstitutionsHelper.getCopyOfPropertyMap(); } // imports diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/processor/PropertyModelHandler.java b/logback-core/src/main/java/ch/qos/logback/core/model/processor/PropertyModelHandler.java index 23e95dcfe8..ab77ad7dcd 100755 --- a/logback-core/src/main/java/ch/qos/logback/core/model/processor/PropertyModelHandler.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/processor/PropertyModelHandler.java @@ -11,16 +11,14 @@ import ch.qos.logback.core.joran.action.ActionUtil; import ch.qos.logback.core.joran.action.ActionUtil.Scope; import ch.qos.logback.core.model.Model; +import ch.qos.logback.core.model.ModelConstants; import ch.qos.logback.core.model.ModelUtil; import ch.qos.logback.core.model.PropertyModel; +import ch.qos.logback.core.model.util.PropertyModelUtil; import ch.qos.logback.core.util.Loader; -import ch.qos.logback.core.util.OptionHelper; public class PropertyModelHandler extends ModelHandlerBase { - public static final String INVALID_ATTRIBUTES = "In element, either the \"file\" attribute alone, or " - + "the \"resource\" element alone, or both the \"name\" and \"value\" attributes must be set."; - public PropertyModelHandler(Context context) { super(context); } @@ -41,7 +39,7 @@ public void handle(ModelInterpretationContext interpretationContext, Model model Scope scope = ActionUtil.stringToScope(propertyModel.getScopeStr()); - if (checkFileAttributeSanity(propertyModel)) { + if (PropertyModelUtil.checkFileAttributeSanity(propertyModel)) { String file = propertyModel.getFile(); file = interpretationContext.subst(file); try (FileInputStream istream = new FileInputStream(file)) { @@ -52,7 +50,7 @@ public void handle(ModelInterpretationContext interpretationContext, Model model // is badly malformed, i.e a binary. addError("Could not read properties file [" + file + "].", e1); } - } else if (checkResourceAttributeSanity(propertyModel)) { + } else if (PropertyModelUtil.checkResourceAttributeSanity(propertyModel)) { String resource = propertyModel.getResource(); resource = interpretationContext.subst(resource); URL resourceURL = Loader.getResourceBySelfClassLoader(resource); @@ -65,7 +63,7 @@ public void handle(ModelInterpretationContext interpretationContext, Model model addError("Could not read resource file [" + resource + "].", e); } } - } else if (checkValueNameAttributesSanity(propertyModel)) { + } else if (PropertyModelUtil.checkValueNameAttributesSanity(propertyModel)) { // earlier versions performed Java '\' escapes for '\\' '\t' etc. Howevver, there is no // need to do this. See RegularEscapeUtil.__UNUSED__basicEscape String value = propertyModel.getValue(); @@ -76,7 +74,7 @@ public void handle(ModelInterpretationContext interpretationContext, Model model ActionUtil.setProperty(interpretationContext, propertyModel.getName(), value, scope); } else { - addError(INVALID_ATTRIBUTES); + addError(ModelConstants.INVALID_ATTRIBUTES); } } @@ -86,33 +84,4 @@ void loadAndSetProperties(ModelInterpretationContext mic, InputStream istream, S ModelUtil.setProperties(mic, props, scope); } - boolean checkFileAttributeSanity(PropertyModel propertyModel) { - String file = propertyModel.getFile(); - String name = propertyModel.getName(); - String value = propertyModel.getValue(); - String resource = propertyModel.getResource(); - - return !(OptionHelper.isNullOrEmptyOrAllSpaces(file)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) - && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(resource)); - } - - boolean checkResourceAttributeSanity(PropertyModel propertyModel) { - String file = propertyModel.getFile(); - String name = propertyModel.getName(); - String value = propertyModel.getValue(); - String resource = propertyModel.getResource(); - - return !(OptionHelper.isNullOrEmptyOrAllSpaces(resource)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) - && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(file)); - } - - boolean checkValueNameAttributesSanity(PropertyModel propertyModel) { - String file = propertyModel.getFile(); - String name = propertyModel.getName(); - String value = propertyModel.getValue(); - String resource = propertyModel.getResource(); - return (!(OptionHelper.isNullOrEmptyOrAllSpaces(name) || OptionHelper.isNullOrEmptyOrAllSpaces(value)) - && (OptionHelper.isNullOrEmptyOrAllSpaces(file) && OptionHelper.isNullOrEmptyOrAllSpaces(resource))); - } - } diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/util/PropertyModelUtil.java b/logback-core/src/main/java/ch/qos/logback/core/model/util/PropertyModelUtil.java new file mode 100644 index 0000000000..14ba246cfe --- /dev/null +++ b/logback-core/src/main/java/ch/qos/logback/core/model/util/PropertyModelUtil.java @@ -0,0 +1,49 @@ +/* + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ + +package ch.qos.logback.core.model.util; + +import ch.qos.logback.core.model.PropertyModel; +import ch.qos.logback.core.util.OptionHelper; + +public class PropertyModelUtil { + public static boolean checkFileAttributeSanity(PropertyModel propertyModel) { + String file = propertyModel.getFile(); + String name = propertyModel.getName(); + String value = propertyModel.getValue(); + String resource = propertyModel.getResource(); + + return !(OptionHelper.isNullOrEmptyOrAllSpaces(file)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) + && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(resource)); + } + + public static boolean checkResourceAttributeSanity(PropertyModel propertyModel) { + String file = propertyModel.getFile(); + String name = propertyModel.getName(); + String value = propertyModel.getValue(); + String resource = propertyModel.getResource(); + + return !(OptionHelper.isNullOrEmptyOrAllSpaces(resource)) && (OptionHelper.isNullOrEmptyOrAllSpaces(name) + && OptionHelper.isNullOrEmptyOrAllSpaces(value) && OptionHelper.isNullOrEmptyOrAllSpaces(file)); + } + + public static boolean checkValueNameAttributesSanity(PropertyModel propertyModel) { + String file = propertyModel.getFile(); + String name = propertyModel.getName(); + String value = propertyModel.getValue(); + String resource = propertyModel.getResource(); + return (!(OptionHelper.isNullOrEmptyOrAllSpaces(name) || OptionHelper.isNullOrEmptyOrAllSpaces(value)) + && (OptionHelper.isNullOrEmptyOrAllSpaces(file) && OptionHelper.isNullOrEmptyOrAllSpaces(resource))); + } +} diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/util/VariableSubstitutionsHelper.java b/logback-core/src/main/java/ch/qos/logback/core/model/util/VariableSubstitutionsHelper.java new file mode 100644 index 0000000000..dd0eef0536 --- /dev/null +++ b/logback-core/src/main/java/ch/qos/logback/core/model/util/VariableSubstitutionsHelper.java @@ -0,0 +1,82 @@ +/* + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2024, QOS.ch. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ + +package ch.qos.logback.core.model.util; + +import ch.qos.logback.core.Context; +import ch.qos.logback.core.spi.ContextAwareBase; +import ch.qos.logback.core.spi.PropertyContainer; +import ch.qos.logback.core.spi.ScanException; +import ch.qos.logback.core.util.OptionHelper; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * Helper methods to deal with properties/ + * + * @since 1.5.1 + */ +public class VariableSubstitutionsHelper extends ContextAwareBase implements PropertyContainer { + + protected Map propertiesMap; + + public VariableSubstitutionsHelper(Context context) { + this.setContext(context); + this.propertiesMap = new HashMap<>(); + } + + public VariableSubstitutionsHelper(Context context, Map otherMap) { + this.setContext(context); + this.propertiesMap = new HashMap<>(otherMap); + } + + public String subst(String ref) { + if (ref == null) { + return null; + } + + try { + return OptionHelper.substVars(ref, this, context); + } catch (ScanException | IllegalArgumentException e) { + addError("Problem while parsing [" + ref + "]", e); + return ref; + } + + } + + /** + * Add a property to the properties of this execution context. If the property + * exists already, it is overwritten. + */ + public void addSubstitutionProperty(String key, String value) { + if (key == null || value == null) { + return; + } + // values with leading or trailing spaces are bad. We remove them now. + value = value.trim(); + propertiesMap.put(key, value); + } + + @Override + public String getProperty(String key) { + return propertiesMap.get(key); + } + + @Override + public Map getCopyOfPropertyMap() { + return new HashMap(propertiesMap); + } +} diff --git a/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java b/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java index 521909b650..d9ae709ddb 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java +++ b/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java @@ -14,10 +14,25 @@ package ch.qos.logback.core.spi; import java.util.Map; +import java.util.Properties; public interface PropertyContainer { + + void addSubstitutionProperty(String key, String value); + String getProperty(String key); Map getCopyOfPropertyMap(); + + default void addSubstitutionProperties(Properties props) { + if (props == null) { + return; + } + for (Object keyObject : props.keySet()) { + String key = (String) keyObject; + String val = props.getProperty(key); + addSubstitutionProperty(key, val); + } + } } diff --git a/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java b/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java index f1fb570c18..a6b158f8d3 100755 --- a/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java +++ b/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java @@ -15,6 +15,7 @@ import java.util.Iterator; +import ch.qos.logback.core.model.ModelConstants; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -197,7 +198,7 @@ public void testLoadNotPossible() throws ActionException { private boolean checkError() { Iterator it = context.getStatusManager().getCopyOfStatusList().iterator(); ErrorStatus es = (ErrorStatus) it.next(); - return PropertyModelHandler.INVALID_ATTRIBUTES.equals(es.getMessage()); + return ModelConstants.INVALID_ATTRIBUTES.equals(es.getMessage()); } private boolean checkFileErrors() {