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.Properties;
023    
024    import org.apache.logging.log4j.Logger;
025    import 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     */
034    public 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    }