/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache license, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the license for the specific language governing permissions and
 * limitations under the license.
 */
package org.apache.logging.log4j.util;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

Consider this class private.

Provides utility methods for managing Properties instances as well as access to the global configuration system. Properties by default are loaded from the system properties, system environment, and a classpath resource file named "log4j2.component.properties". Additional properties can be loaded by implementing a custom PropertySource service and specifying it via a ServiceLoader file called META-INF/services/org.apache.logging.log4j.util.PropertySource with a list of fully qualified class names implementing that interface.

See Also:
/** * <em>Consider this class private.</em> * <p> * Provides utility methods for managing {@link Properties} instances as well as access to the global configuration * system. Properties by default are loaded from the system properties, system environment, and a classpath resource * file named {@value #LOG4J_PROPERTIES_FILE_NAME}. Additional properties can be loaded by implementing a custom * {@link PropertySource} service and specifying it via a {@link ServiceLoader} file called * {@code META-INF/services/org.apache.logging.log4j.util.PropertySource} with a list of fully qualified class names * implementing that interface. * </p> * * @see PropertySource */
public final class PropertiesUtil { private static final String LOG4J_PROPERTIES_FILE_NAME = "log4j2.component.properties"; private static final String LOG4J_SYSTEM_PROPERTIES_FILE_NAME = "log4j2.system.properties"; private static final String SYSTEM = "system:"; private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil(LOG4J_PROPERTIES_FILE_NAME); private final Environment environment;
Constructs a PropertiesUtil using a given Properties object as its source of defined properties.
Params:
  • props – the Properties to use by default
/** * Constructs a PropertiesUtil using a given Properties object as its source of defined properties. * * @param props the Properties to use by default */
public PropertiesUtil(final Properties props) { this.environment = new Environment(new PropertiesPropertySource(props)); }
Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this file are used by default. If a property is not defined in this file, then the equivalent system property is used.
Params:
  • propertiesFileName – the location of properties file to load
/** * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this * file are used by default. If a property is not defined in this file, then the equivalent system property is used. * * @param propertiesFileName the location of properties file to load */
public PropertiesUtil(final String propertiesFileName) { this.environment = new Environment(new PropertyFilePropertySource(propertiesFileName)); }
Loads and closes the given property input stream. If an error occurs, log to the status logger.
Params:
  • in – a property input stream.
  • source – a source object describing the source, like a resource string or a URL.
Returns:a new Properties object
/** * Loads and closes the given property input stream. If an error occurs, log to the status logger. * * @param in a property input stream. * @param source a source object describing the source, like a resource string or a URL. * @return a new Properties object */
static Properties loadClose(final InputStream in, final Object source) { final Properties props = new Properties(); if (null != in) { try { props.load(in); } catch (final IOException e) { LowLevelLogUtil.logException("Unable to read " + source, e); } finally { try { in.close(); } catch (final IOException e) { LowLevelLogUtil.logException("Unable to close " + source, e); } } } return props; }
Returns the PropertiesUtil used by Log4j.
Returns:the main Log4j PropertiesUtil instance.
/** * Returns the PropertiesUtil used by Log4j. * * @return the main Log4j PropertiesUtil instance. */
public static PropertiesUtil getProperties() { return LOG4J_PROPERTIES; }
Returns true if the specified property is defined, regardless of its value (it may not have a value).
Params:
  • name – the name of the property to verify
Returns:true if the specified property is defined, regardless of its value
/** * Returns {@code true} if the specified property is defined, regardless of its value (it may not have a value). * * @param name the name of the property to verify * @return {@code true} if the specified property is defined, regardless of its value */
public boolean hasProperty(final String name) { return environment.containsKey(name); }
Gets the named property as a boolean value. If the property matches the string "true" (case-insensitive), then it is returned as the boolean value true. Any other non-null text in the property is considered false.
Params:
  • name – the name of the property to look up
Returns:the boolean value of the property or false if undefined.
/** * Gets the named property as a boolean value. If the property matches the string {@code "true"} (case-insensitive), * then it is returned as the boolean value {@code true}. Any other non-{@code null} text in the property is * considered {@code false}. * * @param name the name of the property to look up * @return the boolean value of the property or {@code false} if undefined. */
public boolean getBooleanProperty(final String name) { return getBooleanProperty(name, false); }
Gets the named property as a boolean value.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the boolean value of the property or defaultValue if undefined.
/** * Gets the named property as a boolean value. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the boolean value of the property or {@code defaultValue} if undefined. */
public boolean getBooleanProperty(final String name, final boolean defaultValue) { final String prop = getStringProperty(name); return prop == null ? defaultValue : "true".equalsIgnoreCase(prop); }
Gets the named property as a boolean value.
Params:
  • name – the name of the property to look up
  • defaultValueIfAbsent – the default value to use if the property is undefined
  • defaultValueIfPresent – the default value to use if the property is defined but not assigned
Returns:the boolean value of the property or defaultValue if undefined.
/** * Gets the named property as a boolean value. * * @param name the name of the property to look up * @param defaultValueIfAbsent the default value to use if the property is undefined * @param defaultValueIfPresent the default value to use if the property is defined but not assigned * @return the boolean value of the property or {@code defaultValue} if undefined. */
public boolean getBooleanProperty(final String name, final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) { final String prop = getStringProperty(name); return prop == null ? defaultValueIfAbsent : prop.isEmpty() ? defaultValueIfPresent : "true".equalsIgnoreCase(prop); }
Gets the named property as a Charset value.
Params:
  • name – the name of the property to look up
Returns:the Charset value of the property or Charset.defaultCharset() if undefined.
/** * Gets the named property as a Charset value. * * @param name the name of the property to look up * @return the Charset value of the property or {@link Charset#defaultCharset()} if undefined. */
public Charset getCharsetProperty(final String name) { return getCharsetProperty(name, Charset.defaultCharset()); }
Gets the named property as a Charset value. If we cannot find the named Charset, see if it is mapped in file Log4j-charsets.properties on the class path.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the Charset value of the property or defaultValue if undefined.
/** * Gets the named property as a Charset value. If we cannot find the named Charset, see if it is mapped in * file {@code Log4j-charsets.properties} on the class path. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the Charset value of the property or {@code defaultValue} if undefined. */
public Charset getCharsetProperty(final String name, final Charset defaultValue) { final String charsetName = getStringProperty(name); if (charsetName == null) { return defaultValue; } if (Charset.isSupported(charsetName)) { return Charset.forName(charsetName); } final ResourceBundle bundle = getCharsetsResourceBundle(); if (bundle.containsKey(name)) { final String mapped = bundle.getString(name); if (Charset.isSupported(mapped)) { return Charset.forName(mapped); } } LowLevelLogUtil.log("Unable to get Charset '" + charsetName + "' for property '" + name + "', using default " + defaultValue + " and continuing."); return defaultValue; }
Gets the named property as a double.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the parsed double value of the property or defaultValue if it was undefined or could not be parsed.
/** * Gets the named property as a double. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the parsed double value of the property or {@code defaultValue} if it was undefined or could not be parsed. */
public double getDoubleProperty(final String name, final double defaultValue) { final String prop = getStringProperty(name); if (prop != null) { try { return Double.parseDouble(prop); } catch (final Exception ignored) { return defaultValue; } } return defaultValue; }
Gets the named property as an integer.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the parsed integer value of the property or defaultValue if it was undefined or could not be parsed.
/** * Gets the named property as an integer. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the parsed integer value of the property or {@code defaultValue} if it was undefined or could not be * parsed. */
public int getIntegerProperty(final String name, final int defaultValue) { final String prop = getStringProperty(name); if (prop != null) { try { return Integer.parseInt(prop); } catch (final Exception ignored) { return defaultValue; } } return defaultValue; }
Gets the named property as a long.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the parsed long value of the property or defaultValue if it was undefined or could not be parsed.
/** * Gets the named property as a long. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the parsed long value of the property or {@code defaultValue} if it was undefined or could not be parsed. */
public long getLongProperty(final String name, final long defaultValue) { final String prop = getStringProperty(name); if (prop != null) { try { return Long.parseLong(prop); } catch (final Exception ignored) { return defaultValue; } } return defaultValue; }
Gets the named property as a String.
Params:
  • name – the name of the property to look up
Returns:the String value of the property or null if undefined.
/** * Gets the named property as a String. * * @param name the name of the property to look up * @return the String value of the property or {@code null} if undefined. */
public String getStringProperty(final String name) { return environment.get(name); }
Gets the named property as a String.
Params:
  • name – the name of the property to look up
  • defaultValue – the default value to use if the property is undefined
Returns:the String value of the property or defaultValue if undefined.
/** * Gets the named property as a String. * * @param name the name of the property to look up * @param defaultValue the default value to use if the property is undefined * @return the String value of the property or {@code defaultValue} if undefined. */
public String getStringProperty(final String name, final String defaultValue) { final String prop = getStringProperty(name); return (prop == null) ? defaultValue : prop; }
Return the system properties or an empty Properties object if an error occurs.
Returns:The system properties.
/** * Return the system properties or an empty Properties object if an error occurs. * * @return The system properties. */
public static Properties getSystemProperties() { try { return new Properties(System.getProperties()); } catch (final SecurityException ex) { LowLevelLogUtil.logException("Unable to access system properties.", ex); // Sandboxed - can't read System Properties return new Properties(); } }
Reloads all properties. This is primarily useful for unit tests.
Since:2.10.0
/** * Reloads all properties. This is primarily useful for unit tests. * * @since 2.10.0 */
public void reload() { environment.reload(); }
Provides support for looking up global configuration properties via environment variables, property files, and system properties, in three variations:

Normalized: all log4j-related prefixes removed, remaining property is camelCased with a log4j2 prefix for property files and system properties, or follows a LOG4J_FOO_BAR format for environment variables.

Legacy: the original property name as defined in the source pre-2.10.0.

Tokenized: loose matching based on word boundaries.

Since:2.10.0
/** * Provides support for looking up global configuration properties via environment variables, property files, * and system properties, in three variations: * <p> * Normalized: all log4j-related prefixes removed, remaining property is camelCased with a log4j2 prefix for * property files and system properties, or follows a LOG4J_FOO_BAR format for environment variables. * <p> * Legacy: the original property name as defined in the source pre-2.10.0. * <p> * Tokenized: loose matching based on word boundaries. * * @since 2.10.0 */
private static class Environment { private final Set<PropertySource> sources = new TreeSet<>(new PropertySource.Comparator()); private final Map<CharSequence, String> literal = new ConcurrentHashMap<>(); private final Map<CharSequence, String> normalized = new ConcurrentHashMap<>(); private final Map<List<CharSequence>, String> tokenized = new ConcurrentHashMap<>(); private Environment(final PropertySource propertySource) { PropertyFilePropertySource sysProps = new PropertyFilePropertySource(LOG4J_SYSTEM_PROPERTIES_FILE_NAME); try { sysProps.forEach(new BiConsumer<String, String>() { @Override public void accept(String key, String value) { if (System.getProperty(key) == null) { System.setProperty(key, value); } } }); } catch (SecurityException ex) { // Access to System Properties is restricted so just skip it. } sources.add(propertySource); for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) { try { for (final PropertySource source : ServiceLoader.load(PropertySource.class, classLoader)) { sources.add(source); } } catch (final Throwable ex) { /* Don't log anything to the console. It may not be a problem that a PropertySource * isn't accessible. */ } } reload(); } private synchronized void reload() { literal.clear(); normalized.clear(); tokenized.clear(); for (final PropertySource source : sources) { source.forEach(new BiConsumer<String, String>() { @Override public void accept(final String key, final String value) { if (key != null && value != null) { literal.put(key, value); final List<CharSequence> tokens = PropertySource.Util.tokenize(key); if (tokens.isEmpty()) { normalized.put(source.getNormalForm(Collections.singleton(key)), value); } else { normalized.put(source.getNormalForm(tokens), value); tokenized.put(tokens, value); } } } }); } } private static boolean hasSystemProperty(final String key) { try { return System.getProperties().containsKey(key); } catch (final SecurityException ignored) { return false; } } private String get(final String key) { if (normalized.containsKey(key)) { return normalized.get(key); } if (literal.containsKey(key)) { return literal.get(key); } if (hasSystemProperty(key)) { return System.getProperty(key); } return tokenized.get(PropertySource.Util.tokenize(key)); } private boolean containsKey(final String key) { return normalized.containsKey(key) || literal.containsKey(key) || hasSystemProperty(key) || tokenized.containsKey(PropertySource.Util.tokenize(key)); } }
Extracts properties that start with or are equals to the specific prefix and returns them in a new Properties object with the prefix removed.
Params:
  • properties – The Properties to evaluate.
  • prefix – The prefix to extract.
Returns:The subset of properties.
/** * Extracts properties that start with or are equals to the specific prefix and returns them in a new Properties * object with the prefix removed. * * @param properties The Properties to evaluate. * @param prefix The prefix to extract. * @return The subset of properties. */
public static Properties extractSubset(final Properties properties, final String prefix) { final Properties subset = new Properties(); if (prefix == null || prefix.length() == 0) { return subset; } final String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix; final List<String> keys = new ArrayList<>(); for (final String key : properties.stringPropertyNames()) { if (key.startsWith(prefixToMatch)) { subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key)); keys.add(key); } } for (final String key : keys) { properties.remove(key); } return subset; } static ResourceBundle getCharsetsResourceBundle() { return ResourceBundle.getBundle("Log4j-charsets"); }
Partitions a properties map based on common key prefixes up to the first period.
Params:
  • properties – properties to partition
Returns:the partitioned properties where each key is the common prefix (minus the period) and the values are new property maps without the prefix and period in the key
Since:2.6
/** * Partitions a properties map based on common key prefixes up to the first period. * * @param properties properties to partition * @return the partitioned properties where each key is the common prefix (minus the period) and the values are * new property maps without the prefix and period in the key * @since 2.6 */
public static Map<String, Properties> partitionOnCommonPrefixes(final Properties properties) { final Map<String, Properties> parts = new ConcurrentHashMap<>(); for (final String key : properties.stringPropertyNames()) { final String prefix = key.substring(0, key.indexOf('.')); if (!parts.containsKey(prefix)) { parts.put(prefix, new Properties()); } parts.get(prefix).setProperty(key.substring(key.indexOf('.') + 1), properties.getProperty(key)); } return parts; }
Returns true if system properties tell us we are running on Windows.
Returns:true if system properties tell us we are running on Windows.
/** * Returns true if system properties tell us we are running on Windows. * * @return true if system properties tell us we are running on Windows. */
public boolean isOsWindows() { return getStringProperty("os.name", "").startsWith("Windows"); } }