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 in a 033 * 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 * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this 055 * file are used by default. If a property is not defined in this file, then the equivalent system property is used. 056 * 057 * @param propertiesFileName the location of properties file to load 058 */ 059 public PropertiesUtil(final String propertiesFileName) { 060 @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") 061 final Properties properties = new Properties(); 062 for (final URL url : LoaderUtil.findResources(propertiesFileName)) { 063 InputStream in = null; 064 try { 065 in = url.openStream(); 066 properties.load(in); 067 } catch (final IOException ioe) { 068 LOGGER.error("Unable to read {}", url.toString(), ioe); 069 } finally { 070 if (in != null) { 071 try { 072 in.close(); 073 } catch (final IOException ioe) { 074 LOGGER.error("Unable to close {}", url.toString(), ioe); 075 } 076 } 077 } 078 } 079 this.props = properties; 080 } 081 082 /** 083 * Loads and closes the given property input stream. If an error occurs, log to the status logger. 084 * 085 * @param in a property input stream. 086 * @param source a source object describing the source, like a resource string or a URL. 087 * @return a new Properties object 088 */ 089 static Properties loadClose(final InputStream in, final Object source) { 090 final Properties props = new Properties(); 091 if (null != in) { 092 try { 093 props.load(in); 094 } catch (final IOException e) { 095 LOGGER.error("Unable to read {}", source, e); 096 } finally { 097 try { 098 in.close(); 099 } catch (final IOException e) { 100 LOGGER.error("Unable to close {}", source, e); 101 } 102 } 103 } 104 return props; 105 } 106 107 /** 108 * Returns the PropertiesUtil used by Log4j. 109 * 110 * @return the main Log4j PropertiesUtil instance. 111 */ 112 public static PropertiesUtil getProperties() { 113 return LOG4J_PROPERTIES; 114 } 115 116 /** 117 * Gets the named property as a String. 118 * 119 * @param name the name of the property to look up 120 * @return the String value of the property or {@code null} if undefined. 121 */ 122 public String getStringProperty(final String name) { 123 String prop = null; 124 try { 125 prop = System.getProperty(name); 126 } catch (final SecurityException ignored) { 127 // Ignore 128 } 129 return prop == null ? props.getProperty(name) : prop; 130 } 131 132 /** 133 * Gets the named property as an integer. 134 * 135 * @param name the name of the property to look up 136 * @param defaultValue the default value to use if the property is undefined 137 * @return the parsed integer value of the property or {@code defaultValue} if it was undefined or could not be 138 * parsed. 139 */ 140 public int getIntegerProperty(final String name, final int defaultValue) { 141 String prop = null; 142 try { 143 prop = System.getProperty(name); 144 } catch (final SecurityException ignored) { 145 // Ignore 146 } 147 if (prop == null) { 148 prop = props.getProperty(name); 149 } 150 if (prop != null) { 151 try { 152 return Integer.parseInt(prop); 153 } catch (final Exception ignored) { 154 return defaultValue; 155 } 156 } 157 return defaultValue; 158 } 159 160 /** 161 * Gets the named property as a long. 162 * 163 * @param name the name of the property to look up 164 * @param defaultValue the default value to use if the property is undefined 165 * @return the parsed long value of the property or {@code defaultValue} if it was undefined or could not be parsed. 166 */ 167 public long getLongProperty(final String name, final long defaultValue) { 168 String prop = null; 169 try { 170 prop = System.getProperty(name); 171 } catch (final SecurityException ignored) { 172 // Ignore 173 } 174 if (prop == null) { 175 prop = props.getProperty(name); 176 } 177 if (prop != null) { 178 try { 179 return Long.parseLong(prop); 180 } catch (final Exception ignored) { 181 return defaultValue; 182 } 183 } 184 return defaultValue; 185 } 186 187 /** 188 * Gets the named property as a String. 189 * 190 * @param name the name of the property to look up 191 * @param defaultValue the default value to use if the property is undefined 192 * @return the String value of the property or {@code defaultValue} if undefined. 193 */ 194 public String getStringProperty(final String name, final String defaultValue) { 195 final String prop = getStringProperty(name); 196 return (prop == null) ? defaultValue : prop; 197 } 198 199 /** 200 * Gets the named property as a boolean value. If the property matches the string {@code "true"} (case-insensitive), 201 * then it is returned as the boolean value {@code true}. Any other non-{@code null} text in the property is 202 * considered {@code false}. 203 * 204 * @param name the name of the property to look up 205 * @return the boolean value of the property or {@code false} if undefined. 206 */ 207 public boolean getBooleanProperty(final String name) { 208 return getBooleanProperty(name, false); 209 } 210 211 /** 212 * Gets the named property as a boolean value. 213 * 214 * @param name the name of the property to look up 215 * @param defaultValue the default value to use if the property is undefined 216 * @return the boolean value of the property or {@code defaultValue} if undefined. 217 */ 218 public boolean getBooleanProperty(final String name, final boolean defaultValue) { 219 final String prop = getStringProperty(name); 220 return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop); 221 } 222 223 /** 224 * Return the system properties or an empty Properties object if an error occurs. 225 * 226 * @return The system properties. 227 */ 228 public static Properties getSystemProperties() { 229 try { 230 return new Properties(System.getProperties()); 231 } catch (final SecurityException ex) { 232 LOGGER.error("Unable to access system properties.", ex); 233 // Sandboxed - can't read System Properties 234 return new Properties(); 235 } 236 } 237 238 /** 239 * Extracts properties that start with or are equals to the specific prefix and returns them in a new Properties 240 * object with the prefix removed. 241 * 242 * @param properties The Properties to evaluate. 243 * @param prefix The prefix to extract. 244 * @return The subset of properties. 245 */ 246 public static Properties extractSubset(Properties properties, String prefix) { 247 Properties subset = new Properties(); 248 249 if (prefix == null || prefix.length() == 0) { 250 return subset; 251 } 252 253 String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix; 254 255 List<String> keys = new ArrayList<>(); 256 257 for (String key : properties.stringPropertyNames()) { 258 if (key.startsWith(prefixToMatch)) { 259 subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key)); 260 keys.add(key); 261 } 262 } 263 for (String key : keys) { 264 properties.remove(key); 265 } 266 267 return subset; 268 } 269 270 /** 271 * Returns true if system properties tell us we are running on Windows. 272 * @return true if system properties tell us we are running on Windows. 273 */ 274 public boolean isOsWindows() { 275 return getStringProperty("os.name").startsWith("Windows"); 276 } 277}