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