View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.util;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.net.URL;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Properties;
25  
26  import org.apache.logging.log4j.Logger;
27  import org.apache.logging.log4j.status.StatusLogger;
28  
29  /**
30   * <em>Consider this class private.</em>
31   * <p>
32   * Helps access properties. This utility provides a method to override system properties by specifying properties in a
33   * properties file.
34   * </p>
35   */
36  public final class PropertiesUtil {
37  
38      private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil("log4j2.component.properties");
39  
40      private static final Logger LOGGER = StatusLogger.getLogger();
41  
42      private final Properties props;
43  
44      /**
45       * Constructs a PropertiesUtil using a given Properties object as its source of defined properties.
46       *
47       * @param props the Properties to use by default
48       */
49      public PropertiesUtil(final Properties props) {
50          this.props = props;
51      }
52  
53      /**
54       * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this
55       * file are used by default. If a property is not defined in this file, then the equivalent system property is used.
56       *
57       * @param propertiesFileName the location of properties file to load
58       */
59      public PropertiesUtil(final String propertiesFileName) {
60          @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
61          final Properties properties = new Properties();
62          for (final URL url : LoaderUtil.findResources(propertiesFileName)) {
63              InputStream in = null;
64              try {
65                  in = url.openStream();
66                  properties.load(in);
67              } catch (final IOException ioe) {
68                  LOGGER.error("Unable to read {}", url.toString(), ioe);
69              } finally {
70                  if (in != null) {
71                      try {
72                          in.close();
73                      } catch (final IOException ioe) {
74                          LOGGER.error("Unable to close {}", url.toString(), ioe);
75                      }
76                  }
77              }
78          }
79          this.props = properties;
80      }
81  
82      /**
83       * Loads and closes the given property input stream. If an error occurs, log to the status logger.
84       *
85       * @param in a property input stream.
86       * @param source a source object describing the source, like a resource string or a URL.
87       * @return a new Properties object
88       */
89      static Properties loadClose(final InputStream in, final Object source) {
90          final Properties props = new Properties();
91          if (null != in) {
92              try {
93                  props.load(in);
94              } catch (final IOException e) {
95                  LOGGER.error("Unable to read {}", source, e);
96              } finally {
97                  try {
98                      in.close();
99                  } 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 }