001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.util; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.net.URL; 022import java.util.ArrayList; 023import java.util.List; 024import java.util.Properties; 025 026import org.apache.logging.log4j.Logger; 027import org.apache.logging.log4j.status.StatusLogger; 028 029/** 030 * <em>Consider this class private.</em> 031 * <p> 032 * Helps access properties. This utility provides a method to override system properties by specifying properties 033 * in a properties file. 034 * </p> 035 */ 036public final class PropertiesUtil { 037 038 private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil("log4j2.component.properties"); 039 040 private static final Logger LOGGER = StatusLogger.getLogger(); 041 042 private final Properties props; 043 044 /** 045 * Constructs a PropertiesUtil using a given Properties object as its source of defined properties. 046 * 047 * @param props the Properties to use by default 048 */ 049 public PropertiesUtil(final Properties props) { 050 this.props = props; 051 } 052 053 /** 054 * Loads and closes the given property input stream. 055 * If an error occurs, log to the status logger. 056 * 057 * @param in 058 * a property input stream. 059 * @param source 060 * a source object describing the source, like a resource string 061 * or a URL. 062 * @return a new Properties object 063 */ 064 static Properties loadClose(final InputStream in, final Object source) { 065 final Properties props = new Properties(); 066 if (null != in) { 067 try { 068 props.load(in); 069 } catch (final IOException e) { 070 LOGGER.error("Unable to read {}", source, e); 071 } finally { 072 try { 073 in.close(); 074 } catch (final IOException e) { 075 LOGGER.error("Unable to close {}", source, e); 076 } 077 } 078 } 079 return props; 080 } 081 082 /** 083 * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this 084 * file are used by default. If a property is not defined in this file, then the equivalent system property is 085 * used. 086 * 087 * @param propertiesFileName the location of properties file to load 088 */ 089 public PropertiesUtil(final String propertiesFileName) { 090 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") 091 final Properties properties = new Properties(); 092 for (final URL url : LoaderUtil.findResources(propertiesFileName)) { 093 InputStream in = null; 094 try { 095 in = url.openStream(); 096 properties.load(in); 097 } catch (final IOException ioe) { 098 LOGGER.error("Unable to read {}", url.toString(), ioe); 099 } finally { 100 if (in != null) { 101 try { 102 in.close(); 103 } catch (final IOException ioe) { 104 LOGGER.error("Unable to close {}", url.toString(), ioe); 105 } 106 } 107 } 108 } 109 this.props = properties; 110 } 111 112 /** 113 * Returns the PropertiesUtil used by Log4j. 114 * 115 * @return the main Log4j PropertiesUtil instance. 116 */ 117 public static PropertiesUtil getProperties() { 118 return LOG4J_PROPERTIES; 119 } 120 121 /** 122 * Gets the named property as a String. 123 * 124 * @param name the name of the property to look up 125 * @return the String value of the property or {@code null} if undefined. 126 */ 127 public String getStringProperty(final String name) { 128 String prop = null; 129 try { 130 prop = System.getProperty(name); 131 } catch (final SecurityException ignored) { 132 // Ignore 133 } 134 return prop == null ? props.getProperty(name) : prop; 135 } 136 137 /** 138 * Gets the named property as an integer. 139 * 140 * @param name the name of the property to look up 141 * @param defaultValue the default value to use if the property is undefined 142 * @return the parsed integer value of the property or {@code defaultValue} if it was undefined or could not be 143 * parsed. 144 */ 145 public int getIntegerProperty(final String name, final int defaultValue) { 146 String prop = null; 147 try { 148 prop = System.getProperty(name); 149 } catch (final SecurityException ignored) { 150 // Ignore 151 } 152 if (prop == null) { 153 prop = props.getProperty(name); 154 } 155 if (prop != null) { 156 try { 157 return Integer.parseInt(prop); 158 } catch (final Exception ignored) { 159 return defaultValue; 160 } 161 } 162 return defaultValue; 163 } 164 165 /** 166 * Gets the named property as a long. 167 * 168 * @param name the name of the property to look up 169 * @param defaultValue the default value to use if the property is undefined 170 * @return the parsed long value of the property or {@code defaultValue} if it was undefined or could not be 171 * parsed. 172 */ 173 public long getLongProperty(final String name, final long defaultValue) { 174 String prop = null; 175 try { 176 prop = System.getProperty(name); 177 } catch (final SecurityException ignored) { 178 // Ignore 179 } 180 if (prop == null) { 181 prop = props.getProperty(name); 182 } 183 if (prop != null) { 184 try { 185 return Long.parseLong(prop); 186 } catch (final Exception ignored) { 187 return defaultValue; 188 } 189 } 190 return defaultValue; 191 } 192 193 /** 194 * Gets the named property as a String. 195 * 196 * @param name the name of the property to look up 197 * @param defaultValue the default value to use if the property is undefined 198 * @return the String value of the property or {@code defaultValue} if undefined. 199 */ 200 public String getStringProperty(final String name, final String defaultValue) { 201 final String prop = getStringProperty(name); 202 return (prop == null) ? defaultValue : prop; 203 } 204 205 /** 206 * Gets the named property as a boolean value. If the property matches the string {@code "true"} (case-insensitive), 207 * then it is returned as the boolean value {@code true}. Any other non-{@code null} text in the property is 208 * considered {@code false}. 209 * 210 * @param name the name of the property to look up 211 * @return the boolean value of the property or {@code false} if undefined. 212 */ 213 public boolean getBooleanProperty(final String name) { 214 return getBooleanProperty(name, false); 215 } 216 217 /** 218 * Gets the named property as a boolean value. 219 * 220 * @param name the name of the property to look up 221 * @param defaultValue the default value to use if the property is undefined 222 * @return the boolean value of the property or {@code defaultValue} if undefined. 223 */ 224 public boolean getBooleanProperty(final String name, final boolean defaultValue) { 225 final String prop = getStringProperty(name); 226 return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop); 227 } 228 229 /** 230 * Return the system properties or an empty Properties object if an error occurs. 231 * @return The system properties. 232 */ 233 public static Properties getSystemProperties() { 234 try { 235 return new Properties(System.getProperties()); 236 } catch (final SecurityException ex) { 237 LOGGER.error("Unable to access system properties.", ex); 238 // Sandboxed - can't read System Properties 239 return new Properties(); 240 } 241 } 242 243 /** 244 * Extracts properties that start with or are equals to the specific prefix and returns them in a 245 * new Properties object with the prefix removed. 246 * @param properties The Properties to evaluate. 247 * @param prefix The prefix to extract. 248 * @return The subset of properties. 249 */ 250 public static Properties extractSubset(Properties properties, String prefix) { 251 Properties subset = new Properties(); 252 253 if (prefix == null || prefix.length() == 0) { 254 return subset; 255 } 256 257 String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix; 258 259 List<String> keys = new ArrayList<>(); 260 261 for (String key : properties.stringPropertyNames()) { 262 if (key.startsWith(prefixToMatch)) { 263 subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key)); 264 keys.add(key); 265 } 266 } 267 for (String key : keys) { 268 properties.remove(key); 269 } 270 271 return subset; 272 } 273}