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
33   * in a 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       * Loads and closes the given property input stream.
55       * If an error occurs, log to the status logger.
56       *
57       * @param in
58       *            a property input stream.
59       * @param source
60       *            a source object describing the source, like a resource string
61       *            or a URL.
62       * @return a new Properties object
63       */
64      static Properties loadClose(final InputStream in, final Object source) {
65          final Properties props = new Properties();
66          if (null != in) {
67              try {
68                  props.load(in);
69              } catch (final IOException e) {
70                  LOGGER.error("Unable to read {}", source, e);
71              } finally {
72                  try {
73                      in.close();
74                  } catch (final IOException e) {
75                      LOGGER.error("Unable to close {}", source, e);
76                  }
77              }
78          }
79          return props;
80      }
81  
82      /**
83       * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this
84       * file are used by default. If a property is not defined in this file, then the equivalent system property is
85       * used.
86       *
87       * @param propertiesFileName the location of properties file to load
88       */
89      public PropertiesUtil(final String propertiesFileName) {
90          @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
91          final Properties properties = new Properties();
92          for (final URL url : LoaderUtil.findResources(propertiesFileName)) {
93              InputStream in = null;
94              try {
95                  in = url.openStream();
96                  properties.load(in);
97              } catch (final IOException ioe) {
98                  LOGGER.error("Unable to read {}", url.toString(), ioe);
99              } 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 }