/*
* Copyright 2011, 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.config;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.unitils.core.UnitilsException;
import org.unitils.core.util.Configurable;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import static org.unitils.util.ReflectionUtils.createInstanceOfType;
/**
* @author Tim Ducheyne
* @author Filip Neven
*/
public class UnitilsConfiguration {
/* The logger instance for this class */
private static Log logger = LogFactory.getLog(UnitilsConfiguration.class);
/* All configuration properties, not null */
private Properties properties;
/**
* Creates a configuration for the given properties.
*
* @param properties All configuration properties, not null
*/
public UnitilsConfiguration(Properties properties) {
this.properties = properties;
}
/**
* Gets the string value for the property with the given name. If no such property is found or
* the value is empty, an exception will be raised.
*
* @param propertyName The name, not null
* @return The trimmed string value, not null
*/
public String getString(String propertyName) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
throw new UnitilsException("No value found for property " + propertyName);
}
return value.trim();
}
/**
* Gets the string value for the property with the given name. If no such property is found or
* the value is empty, the given default value is returned.
*
* @param propertyName The name, not null
* @param defaultValue The default value
* @return The trimmed string value, not null
*/
public String getString(String propertyName, String defaultValue) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
return defaultValue;
}
return value.trim();
}
/**
* Gets the list of comma separated string values for the property with the given name. If no such property is found or
* the value is empty, an empty list is returned. Empty elements (",,") will not be added.
*
* @param propertyName The name, not null
* @return The trimmed string list, empty if none found
*/
public List<String> getStringList(String propertyName) {
return getStringList(propertyName, false);
}
/**
* Gets the list of comma separated string values for the property with the given name. If no such property is found or
* the value is empty, an empty list is returned if not required, else an exception is raised. Empty elements (",,")
* will not be added.
*
* @param propertyName The name, not null
* @param required If true an exception will be raised when the property is not found or empty
* @return The trimmed string list, empty or exception if none found
*/
public List<String> getStringList(String propertyName, boolean required) {
String values = properties.getProperty(propertyName);
if (values == null || "".equals(values.trim())) {
if (required) {
throw new UnitilsException("No value found for property " + propertyName);
}
return new ArrayList<String>(0);
}
String[] splitValues = values.split(",");
List<String> result = new ArrayList<String>(splitValues.length);
for (String value : splitValues) {
if (value == null || "".equals(value.trim())) {
continue;
}
result.add(value.trim());
}
if (required && result.isEmpty()) {
throw new UnitilsException("No value found for property " + propertyName);
}
return result;
}
/**
* Gets the boolean value for the property with the given name. If no such property is found,
* the value is empty or not a boolean, an exception will be raised.
*
* @param propertyName The name, not null
* @return The boolean value
*/
public boolean getBoolean(String propertyName) {
String value = getString(propertyName, null);
if (value == null || "".equals(value.trim())) {
throw new UnitilsException("No value found for property " + propertyName);
}
return toBoolean(propertyName, value);
}
/**
* Gets the boolean value for the property with the given name. If no such property is found or
* the value is empty, the given default value is returned. An exception will be raised if the
* value is not a boolean.
*
* @param propertyName The name, not null
* @param defaultValue The default value
* @return The boolean value
*/
public boolean getBoolean(String propertyName, boolean defaultValue) {
String value = getString(propertyName, null);
if (value == null || "".equals(value.trim())) {
return defaultValue;
}
return toBoolean(propertyName, value);
}
private boolean toBoolean(String propertyName, String value) {
if ("true".equalsIgnoreCase(value)) {
return true;
}
if ("false".equalsIgnoreCase(value)) {
return false;
}
throw new UnitilsException("Value " + value + " for property " + propertyName + " is not a boolean.");
}
/**
* Gets the long value for the property with the given name. If no such property is found, the value is empty
* or cannot be converted to a long, an exception will be raised.
*
* @param propertyName The name, not null
* @return The long value
*/
public long getLong(String propertyName) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
throw new UnitilsException("No value found for property " + propertyName);
}
try {
return Long.valueOf(value.trim());
} catch (NumberFormatException e) {
throw new UnitilsException("Value " + value + " for property " + propertyName + " is not a long.");
}
}
/**
* Gets the long value for the property with the given name. If no such property is found or
* the value is empty, the given default value is returned. An exception will be raised if the
* value cannot be converted to a long.
*
* @param propertyName The name, not null
* @param defaultValue The default value
* @return The long value
*/
public long getLong(String propertyName, long defaultValue) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
return defaultValue;
}
try {
return Long.valueOf(value.trim());
} catch (NumberFormatException e) {
throw new UnitilsException("Value " + value + " for property " + propertyName + " is not a long.");
}
}
/**
* Gets the int value for the property with the given name. If no such property is found, the value is empty
* or cannot be converted to an int, an exception will be raised.
*
* @param propertyName The name, not null
* @return The int value
*/
public int getInt(String propertyName) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
throw new UnitilsException("No value found for property " + propertyName);
}
try {
return Integer.valueOf(value.trim());
} catch (NumberFormatException e) {
throw new UnitilsException("Value " + value + " for property " + propertyName + " is not a number.");
}
}
/**
* Gets the int value for the property with the given name. If no such property is found or
* the value is empty, the given default value is returned. An exception will be raised if the
* value cannot be converted to an int.
*
* @param propertyName The name, not null
* @param defaultValue The default value
* @return The int value
*/
public int getInt(String propertyName, int defaultValue) {
String value = properties.getProperty(propertyName);
if (value == null || "".equals(value.trim())) {
return defaultValue;
}
try {
return Integer.valueOf(value.trim());
} catch (NumberFormatException e) {
throw new UnitilsException("Value " + value + " for property " + propertyName + " is not a number.");
}
}
/**
* Gets an instance of the class name specified by the property with the given name. If no such property is found, the
* value is empty or the instance cannot be created, an exception will be raised.<br/>
* <br/>
* If the created instance is implementation of {@link Configurable}, the init method will be called.
*
* @param propertyName The name, not null
* @return The instance value, not null
*/
@SuppressWarnings({"unchecked"})
public <T> T getInstance(String propertyName) {
String className = getString(propertyName);
return (T) createInstanceOfType(className, false);
}
/**
* Gets an instance of the class name specified by the property with the given name. If no such property is found, the
* value is empty, the given default value is returned. An exception will be raised if the instance cannot be created.<br/
* <br/>
* If the created instance is implementation of {@link Configurable}, the init method will be called.
*
* @param propertyName The name, not null
* @param defaultValue The default value
* @return The instance value, not null
*/
@SuppressWarnings({"unchecked"})
public <T> T getInstance(String propertyName, T defaultValue) {
String className = getString(propertyName, null);
if (className == null) {
return defaultValue;
}
return (T) createInstance(className);
}
/**
* Gets an instance of the given type (typically an interface).
* The class name will be resolved as follows:
* 'fully qualified name of type'.implClassName(.discriminator1.discriminator2)
*
* If discriminators are provided, it will first look for a property using all discriminators, then look for
* a property without the last discriminator etc. If still no property was found, it will look for the property
* without discriminators.
*
* E.g. suppose you have following properties: <br/>
* <br/>
* com.package.MyInterface.implClassName = com.package.MyInterfaceImpl<br/>
* com.package.MyInterface.implClassName.oracle = com.package.MyOracleInterfaceImpl<br/>
* <br/>
* getInstanceOf(MyInterface.class, "oracle", "v9");<br/>
* <br/>
* will first try<br/>
* com.package.MyInterface.implClassName.oracle.v9<br/>
* <br/>
* but since no such property exists it will try<br/>
* com.package.MyInterface.implClassName.oracle<br/>
* <br/>
* and since such a property exists, it will return an instance com.package.MyOracleInterfaceImpl<br/>
* <br/>
* If oracle did not exist it would have looked for the property without discriminators, i.e.<br/>
* com.package.MyInterface.implClassName<br/>
* <br/>
* If the created instance is implementation of {@link Configurable}, the init method will be called.
*
* @param type The type of the instance
* @param discriminators Optional. The values that define which specific implementation class should be used.
* @return The instance
*/
@SuppressWarnings({"unchecked"})
public <T> T getInstanceOf(Class<T> type, String... discriminators) {
String implClassName = getImplClassName(type, discriminators);
logger.debug("Creating instance of " + type + ". Implementation class " + implClassName);
return (T) createInstance(implClassName);
}
private String getImplClassName(Class<?> type, String... discriminators) {
String className = null;
String propertyName = type.getName() + ".implClassName";
if (discriminators != null) {
StringBuffer propertyNameWithDiscriminators = new StringBuffer(propertyName);
for (String discriminator : discriminators) {
propertyNameWithDiscriminators.append('.');
propertyNameWithDiscriminators.append(discriminator);
String classNameForDiscriminator = getString(propertyNameWithDiscriminators.toString(), null);
if (classNameForDiscriminator != null) {
className = classNameForDiscriminator;
}
}
}
if (className == null) {
className = getString(propertyName);
}
return className;
}
@SuppressWarnings({"unchecked"})
private <T> T createInstance(String className) {
T instance = (T) createInstanceOfType(className, false);
if (instance instanceof Configurable) {
((Configurable) instance).init(properties);
}
return instance;
}
/**
* @param propertyName The property name, not null
* @return True if the property exists
*/
public boolean containsProperty(String propertyName) {
return properties.getProperty(propertyName) != null;
}
/**
* @return All properties, not null
*/
public Properties getProperties() {
return properties;
}
}