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     */
017    package org.apache.logging.log4j.util;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.net.URL;
022    import java.util.Enumeration;
023    import java.util.Properties;
024    
025    import org.apache.logging.log4j.Logger;
026    import org.apache.logging.log4j.status.StatusLogger;
027    
028    /**
029     * <em>Consider this class private.</em>
030     * <p>
031     * Helps access properties. This utility provides a method to override system properties by specifying properties
032     * in a properties file.
033     * </p>
034     */
035    public final class PropertiesUtil {
036    
037        private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil("log4j2.component.properties");
038    
039        private static final Logger LOGGER = StatusLogger.getLogger();
040    
041        private final Properties props;
042    
043        /**
044         * Constructs a PropertiesUtil using a given Properties object as its source of defined properties.
045         *
046         * @param props the Properties to use by default
047         */
048        public PropertiesUtil(final Properties props) {
049            this.props = props;
050        }
051    
052        /**
053         * Loads and closes the given property input stream.
054         * If an error occurs, log to the status logger.
055         *
056         * @param in
057         *            a property input stream.
058         * @param source
059         *            a source object describing the source, like a resource string
060         *            or a URL.
061         * @return a new Properties object
062         */
063        static Properties loadClose(final InputStream in, final Object source) {
064            final Properties props = new Properties();
065            if (null != in) {
066                try {
067                    props.load(in);
068                } catch (final IOException e) {
069                    LOGGER.error("Unable to read {}", source, e);
070                } finally {
071                    try {
072                        in.close();
073                    } catch (final IOException e) {
074                        LOGGER.error("Unable to close {}", source, e);
075                    }
076                }
077            }
078            return props;
079        }
080    
081        /**
082         * Constructs a PropertiesUtil for a given properties file name on the classpath. The properties specified in this
083         * file are used by default. If a property is not defined in this file, then the equivalent system property is
084         * used.
085         *
086         * @param propsLocn the location of properties file to load
087         */
088        public PropertiesUtil(final String propsLocn) {
089            final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
090            @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
091            final
092            Properties properties = new Properties();
093                try {
094                    final Enumeration<URL> enumeration = loader.getResources(propsLocn);
095                    while (enumeration.hasMoreElements()) {
096                        final URL url = enumeration.nextElement();
097                        final InputStream in = url.openStream();
098                        try {
099                            properties.load(in);
100                        } catch (final IOException ioe) {
101                            LOGGER.error("Unable to read {}", url.toString());
102                        } finally {
103                            try {
104                                in.close();
105                            } catch (final IOException ioe) {
106                                LOGGER.error("Unable to close {}", url.toString(), ioe);
107                            }
108                        }
109    
110                    }
111    
112                } catch (final IOException ioe) {
113                    LOGGER.error("Unable to access {}", propsLocn, ioe);
114                }
115            this.props = properties;
116        }
117    
118        /**
119         * Returns the PropertiesUtil used by Log4j.
120         *
121         * @return the main Log4j PropertiesUtil instance.
122         */
123        public static PropertiesUtil getProperties() {
124            return LOG4J_PROPERTIES;
125        }
126    
127        /**
128         * Gets the named property as a String.
129         *
130         * @param name the name of the property to look up
131         * @return the String value of the property or {@code null} if undefined.
132         */
133        public String getStringProperty(final String name) {
134            String prop = null;
135            try {
136                prop = System.getProperty(name);
137            } catch (final SecurityException ignored) {
138                // Ignore
139            }
140            return prop == null ? props.getProperty(name) : prop;
141        }
142    
143        /**
144         * Gets the named property as an integer.
145         *
146         * @param name         the name of the property to look up
147         * @param defaultValue the default value to use if the property is undefined
148         * @return the parsed integer value of the property or {@code defaultValue} if it was undefined or could not be
149         * parsed.
150         */
151        public int getIntegerProperty(final String name, final int defaultValue) {
152            String prop = null;
153            try {
154                prop = System.getProperty(name);
155            } catch (final SecurityException ignored) {
156                // Ignore
157            }
158            if (prop == null) {
159                prop = props.getProperty(name);
160            }
161            if (prop != null) {
162                try {
163                    return Integer.parseInt(prop);
164                } catch (final Exception ex) {
165                    return defaultValue;
166                }
167            }
168            return defaultValue;
169        }
170    
171        /**
172         * Gets the named property as a long.
173         *
174         * @param name         the name of the property to look up
175         * @param defaultValue the default value to use if the property is undefined
176         * @return the parsed long value of the property or {@code defaultValue} if it was undefined or could not be
177         * parsed.
178         */
179        public long getLongProperty(final String name, final long defaultValue) {
180            String prop = null;
181            try {
182                prop = System.getProperty(name);
183            } catch (final SecurityException ignored) {
184                // Ignore
185            }
186            if (prop == null) {
187                prop = props.getProperty(name);
188            }
189            if (prop != null) {
190                try {
191                    return Long.parseLong(prop);
192                } catch (final Exception ex) {
193                    return defaultValue;
194                }
195            }
196            return defaultValue;
197        }
198    
199        /**
200         * Gets the named property as a String.
201         *
202         * @param name         the name of the property to look up
203         * @param defaultValue the default value to use if the property is undefined
204         * @return the String value of the property or {@code defaultValue} if undefined.
205         */
206        public String getStringProperty(final String name, final String defaultValue) {
207            final String prop = getStringProperty(name);
208            return (prop == null) ? defaultValue : prop;
209        }
210    
211        /**
212         * Gets the named property as a boolean value. If the property matches the string {@code "true"} (case-insensitive),
213         * then it is returned as the boolean value {@code true}. Any other non-{@code null} text in the property is
214         * considered {@code false}.
215         *
216         * @param name the name of the property to look up
217         * @return the boolean value of the property or {@code false} if undefined.
218         */
219        public boolean getBooleanProperty(final String name) {
220            return getBooleanProperty(name, false);
221        }
222    
223        /**
224         * Gets the named property as a boolean value.
225         *
226         * @param name         the name of the property to look up
227         * @param defaultValue the default value to use if the property is undefined
228         * @return the boolean value of the property or {@code defaultValue} if undefined.
229         */
230        public boolean getBooleanProperty(final String name, final boolean defaultValue) {
231            final String prop = getStringProperty(name);
232            return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop);
233        }
234    
235        /**
236         * Return the system properties or an empty Properties object if an error occurs.
237         * @return The system properties.
238         */
239        public static Properties getSystemProperties() {
240            try {
241                return new Properties(System.getProperties());
242            } catch (final SecurityException ex) {
243                LOGGER.error("Unable to access system properties.", ex);
244                // Sandboxed - can't read System Properties
245                return new Properties();
246            }
247        }
248    }