/* * Copyright 2008, Unitils.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.unitils.core; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.unitils.core.util.PropertiesReader; import org.unitils.util.PropertyUtils; import java.util.Properties; /** * Utility that loads the configuration of unitils. * <p/> * Unitils settings can be defined in 3 files and in the system properties:<ul> * <li><b>unitils-default.properties</b> - a fixed file packaged in the unitils jar that contains all predefined defaults. * This file should normally not be modified.</li> * <li><b>unitils.properties</b> - a file somewhere in the classpath or user.home dir that contains all custom configuration * settings. Settings in this file will override the default settings. This is where you should put your project * specific configuration</li> * <li><b>unitils-local.properties</b> - a file somewhere in the classpath or user.home that contains machine/user local * configuration. Eg the database schema specific to the local user could be defined here. Settings in this file * will override the unitil default and custom settings.</li> * <li><b>system properties</b> - These settings override all other settings.</li> * </ul> * The name of the custom settings file (unitils.properties) is defined by the {@link #PROPKEY_CUSTOM_CONFIGURATION} * property in the default settings. The name of the local settings file (unitils-local.propeties) is defined * by the {@link #PROPKEY_LOCAL_CONFIGURATION} in the custom or default settings. If these properties are set to * null or empty, the corresponding property file will not be loaded. * <p/> * A runtime exception is thrown when the default properties cannot be loaded. * A warning is logged when the custom propreties cannot be loaded. * A debug message is logged when the local properties cannot be loaded. * <p/> * Ant-like property place holders, e.g. ${holder} will be expanded if needed all property place holders to actual values. * For example suppose you have a property defined as follows: root.dir=/usr/home * Expanding following ${root.dir}/somesubdir * will then give following result: /usr/home/somesubdir * * @author Tim Ducheyne * @author Filip Neven * @author Fabian Krueger */ public class ConfigurationLoader { /** * Name of the fixed configuration file that contains all defaults */ public static final String DEFAULT_PROPERTIES_FILE_NAME = "unitils-default.properties"; /** * Property in the defaults configuration file that contains the name of the custom configuration file */ public static final String PROPKEY_CUSTOM_CONFIGURATION = "unitils.configuration.customFileName"; /** * Property in the defaults and/or custom configuration file that contains the name of * the user local configuration file */ public static final String PROPKEY_LOCAL_CONFIGURATION = "unitils.configuration.localFileName"; /* The logger instance for this class */ private static Log logger = LogFactory.getLog(ConfigurationLoader.class); /** * reads properties from configuration file */ private PropertiesReader propertiesReader = new PropertiesReader(); /** * Creates and loads all configuration settings. * * @return the settings, not null */ public Properties loadConfiguration() { Properties properties = new Properties(); loadDefaultConfiguration(properties); loadCustomConfiguration(properties); loadLocalConfiguration(properties); loadSystemProperties(properties); expandPropertyValues(properties); return properties; } /** * Load the default properties file that is distributed with unitils (unitils-default.properties) * * @param properties The instance to add to loaded properties to, not null */ protected void loadDefaultConfiguration(Properties properties) { Properties defaultProperties = propertiesReader.loadPropertiesFileFromClasspath(DEFAULT_PROPERTIES_FILE_NAME); if (defaultProperties == null) { throw new UnitilsException("Configuration file: " + DEFAULT_PROPERTIES_FILE_NAME + " not found in classpath."); } properties.putAll(defaultProperties); } /** * Load the custom project level configuration file (unitils.properties) * * @param properties The instance to add to loaded properties to, not null */ protected void loadCustomConfiguration(Properties properties) { String customConfigurationFileName = getConfigurationFileName(PROPKEY_CUSTOM_CONFIGURATION, properties); Properties customProperties = propertiesReader.loadPropertiesFileFromClasspath(customConfigurationFileName); if (customProperties == null) { logger.warn("No custom configuration file " + customConfigurationFileName + " found."); } else { properties.putAll(customProperties); } } /** * Load the local configuration file from the user home, or from the classpath * * @param properties The instance to add to loaded properties to, not null */ protected void loadLocalConfiguration(Properties properties) { String localConfigurationFileName = getConfigurationFileName(PROPKEY_LOCAL_CONFIGURATION, properties); Properties localProperties = propertiesReader.loadPropertiesFileFromUserHome(localConfigurationFileName); if (localProperties == null) { localProperties = propertiesReader.loadPropertiesFileFromClasspath(localConfigurationFileName); } if (localProperties == null) { logger.info("No local configuration file " + localConfigurationFileName + " found."); } else { properties.putAll(localProperties); } } /** * Load the environment properties. * * @param properties The instance to add to loaded properties to, not null */ protected void loadSystemProperties(Properties properties) { properties.putAll(System.getProperties()); } /** * Expands all property place holders to actual values. For example * suppose you have a property defined as follows: root.dir=/usr/home * Expanding following ${root.dir}/somesubdir * will then give following result: /usr/home/somesubdir * * @param properties The properties, not null */ protected void expandPropertyValues(Properties properties) { for (Object key : properties.keySet()) { Object value = properties.get(key); try { String expandedValue = StrSubstitutor.replace(value, properties); properties.put(key, expandedValue); } catch (Exception e) { throw new UnitilsException("Unable to load unitils configuration. Could not expand property value for key: " + key + ", value " + value, e); } } } /** * Gets the configuration file name from the system properties or if not defined, from the given loaded properties. * An exception is raised if no value is defined. * * @param propertyName The name of the property that defines the local/custom file name, not null * @param properties The propertis that were already loaded, not null * @return The property value, not null */ protected String getConfigurationFileName(String propertyName, Properties properties) { String configurationFileName = System.getProperty(propertyName); if (configurationFileName != null) { return configurationFileName; } return PropertyUtils.getString(propertyName, properties); } }