001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 *  Copyright (C) 1999-2025, 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 v1.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.core.boolex;
016
017import ch.qos.logback.core.model.processor.ModelInterpretationContext;
018import ch.qos.logback.core.spi.ContextAwareBase;
019import ch.qos.logback.core.spi.PropertyContainer;
020import ch.qos.logback.core.util.OptionHelper;
021
022import static ch.qos.logback.core.CoreConstants.EMPTY_STRING;
023
024/**
025 * <p>Abstract base class provides some scaffolding. It is intended to ease migration
026 * from <b>legacy</b> conditional processing in configuration files
027 * (e.g. &lt;if>, &lt;then&gt;, &lt;else>) using the Janino library. Nevertheless,
028 * it should also be useful in newly written code.</p>
029 *
030 * <p>Properties are looked up in the following order:</p>
031 *
032 * <ol>
033 *  <li>In the local property container, usually the {@link ModelInterpretationContext} </li>
034 *  <li>in the logger context</li>
035 *  <li>system properties</li>
036 *  <li>environment variables</li>
037 * </ol>
038 *
039 * @author Ceki G&uuml;lc&uuml;
040 * @see OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)
041 * @since 1.5.20
042 */
043abstract public class PropertyConditionBase extends ContextAwareBase implements PropertyCondition {
044
045    /**
046     * Indicates whether this evaluator has been started.
047     */
048    boolean started;
049    /**
050     * <p>The local property container used for property lookups.</p>
051     *
052     * <p>Local properties correspond to the properties in the embedding
053     * configurator, i.e. usually the {@link ModelInterpretationContext} instance.</p>
054     */
055    PropertyContainer localPropertyContainer;
056
057    /**
058     * Returns the local property container used by this evaluator.
059     *
060     * <p>Local properties correspond to the properties in the embedding
061     * configurator, i.e. usually the {@link ModelInterpretationContext} instance.</p>
062     *
063     * @return the local property container
064     */
065    @Override
066    public PropertyContainer getLocalPropertyContainer() {
067        return localPropertyContainer;
068    }
069
070    /**
071     * Sets the local property container for this evaluator.
072     *
073     * <p>Local properties correspond to the properties in the embedding
074     * configurator, i.e. usually the {@link ModelInterpretationContext} instance.</p>
075     *
076     * @param aLocalPropertyContainer the local property container to set
077     */
078    @Override
079    public void setLocalPropertyContainer(PropertyContainer aLocalPropertyContainer) {
080        this.localPropertyContainer = aLocalPropertyContainer;
081    }
082
083    /**
084     * Checks if the property with the given key is null.
085     *
086     * <p>The property is looked up via the
087     * {@link OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)} method.
088     * See above for the lookup order.</p>
089     *
090     * @param k the property key
091     * @return true if the property is null, false otherwise
092     */
093    public boolean isNull(String k) {
094        String val = OptionHelper.propertyLookup(k, localPropertyContainer, getContext());
095        return (val == null);
096    }
097
098    /**
099     * Checks if the property with the given key is defined (not null).
100     *
101     * <p>The property is looked up via the
102     * {@link OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)} method.
103     * See above for the lookup order.</p>
104     *
105     * @param k the property key
106     * @return true if the property is defined, false otherwise
107     */
108    public boolean isDefined(String k) {
109        String val = OptionHelper.propertyLookup(k, localPropertyContainer, getContext());
110        return (val != null);
111    }
112
113    /**
114     * Retrieves the property value for the given key, returning an empty string if null.
115     * This is a shorthand for {@link #property(String)}.
116     *
117     * @param k the property key
118     * @return the property value or an empty string
119     */
120    public String p(String k) {
121        return property(k);
122    }
123
124    /**
125     * Retrieves the property value for the given key, returning an empty string if null.
126     *
127     * <p>The property is looked up via the
128     * {@link OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)} method.
129     * See above for the lookup order.</p>
130     *
131     * @param k the property key
132     * @return the property value or an empty string
133     */
134    public String property(String k) {
135        String val = OptionHelper.propertyLookup(k, localPropertyContainer, getContext());
136        if (val != null)
137            return val;
138        else
139            return EMPTY_STRING;
140    }
141
142    /**
143     * Compare the resolved property value with the provided expected value.
144     *
145     * <p>The property is looked up via the
146     * {@link OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)} method.
147     * See above for the lookup order.</p>
148     *
149     * <p>Returns {@code true} if the resolved property value is equal to {@code val}
150     * according to {@link String#equals(Object)}. If the resolved property value or {@code val} is null,
151     * then false is returned.</p>
152     *
153     * @param propertyKey the property key to look up
154     * @param value       expected string value to compare against; must be non-null
155     * @return {@code true} if the resolved property equals {@code value},
156     * {@code false} otherwise or if either the resolved property or {@code value} is null.
157     * @since 1.5.24
158     */
159    public boolean propertyEquals(String propertyKey, String value) {
160        String actual = OptionHelper.propertyLookup(propertyKey, localPropertyContainer, getContext());
161        if (actual == null || value == null) {
162            return false;
163        }
164        return actual.equals(value);
165    }
166
167
168    /**
169     * Determine whether the resolved property value contains the given substring.
170     * <p>
171     *
172     * <p>The property is looked up via the
173     * {@link OptionHelper#propertyLookup(String, PropertyContainer, PropertyContainer)} method.
174     * See above for the lookup order.</p>
175     *
176     * <p>This method returns {@code true} if the resolved property value's
177     * {@link String#contains(CharSequence)} returns {@code true} for the supplied
178     * {@code inclusion}. False is returned if either the resolved property value or
179     * {@code inclusion} parameter is null.</p>
180     *
181     * @param k         the property key to look up
182     * @param inclusion substring to search for in the resolved property value; must be non-null
183     * @return {@code true} if the property value contains {@code inclusion}, false otherwise or
184     * if either the resolved property value or {@code inclusion} is null
185     *
186     * @since 1.5.24
187     */
188    public boolean propertyContains(String k, String inclusion) {
189        String actual = OptionHelper.propertyLookup(k, localPropertyContainer, getContext());
190        if (actual == null || inclusion == null)
191            return false;
192
193        return actual.contains(inclusion);
194    }
195
196    /**
197     * Checks if this evaluator has been started.
198     *
199     * @return true if started, false otherwise
200     */
201    public boolean isStarted() {
202        return started;
203    }
204
205    /**
206     * Starts this evaluator.
207     */
208    public void start() {
209        started = true;
210    }
211
212    /**
213     * Stops this evaluator.
214     */
215    public void stop() {
216        started = false;
217    }
218}