liquibase.configuration.LiquibaseConfiguration Maven / Gradle / Ivy
package liquibase.configuration;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.util.StringUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides unified management of configuration properties within Liquibase core and in extensions.
*
* This class is the top level container used to access {@link ConfigurationContainer} implementations which contain
* the actual configuration properties.
* Normal use is to call
* LiquibaseConfiguration.getInstance().getConfiguration(NEEDED_CONFIGURATION.class).getYOUR_PROPERTY()
*
* This class is implemented as a singleton with a single global set of configuration objects, but the
* {@link #setInstance(LiquibaseConfiguration)} method can be used to replace
* the singleton with an alternate implementation that uses ThreadLocal objects or any other way of managing
* configurations.
*/
public class LiquibaseConfiguration {
private Map configurations;
private ConfigurationValueProvider[] configurationValueProviders;
private static LiquibaseConfiguration instance;
/**
* Returns the singleton instance, creating it if necessary. On creation, the configuration is initialized with {@link liquibase.configuration.SystemPropertyProvider}
*/
public static synchronized LiquibaseConfiguration getInstance() {
if (instance == null) {
instance = new LiquibaseConfiguration();
instance.init(new SystemPropertyProvider());
}
return instance;
}
/**
* Overrides the standard singleton instance created by getInstance().
* Useful for alternate implementations with more complex AbstractConfigurationContainer lookup logic such
* as different configurations per thread.
*/
public static synchronized void setInstance(LiquibaseConfiguration instance) {
LiquibaseConfiguration.instance = instance;
}
/**
* Constructor protected to prevent construction outside getInstance()
*/
protected LiquibaseConfiguration() {
}
/**
* Re-initialize the configuration with the given ConfigurationProviders. Any existing
* AbstractConfigurationContainer instances are reset to defaults.
*/
public void init(ConfigurationValueProvider... configurationValueProviders) {
if (configurationValueProviders == null) {
configurationValueProviders = new ConfigurationValueProvider[0];
}
this.configurationValueProviders = configurationValueProviders;
this.reset();
}
/**
* Resets existing AbstractConfigurationContainer instances to their default values.
*/
public void reset() {
this.configurations = new HashMap<>();
}
/**
* Return an instance of the passed AbstractConfigurationContainer type.
* The same instance is returned from every call to getConfiguration()
*/
public T getConfiguration(Class type) {
if (!configurations.containsKey(type)) {
configurations.put(type, createConfiguration(type));
}
return (T) configurations.get(type);
}
public ConfigurationContainer getConfiguration(String typeName) {
for (Map.Entry entry : configurations.entrySet()) {
if (entry.getKey().getName().equals(typeName)) {
return entry.getValue();
}
}
try {
Class typeClass = Class.forName(typeName);
configurations.put(typeClass, createConfiguration(typeClass));
return configurations.get(typeClass);
} catch (Exception e) {
throw new UnexpectedLiquibaseException(e);
}
}
/**
* Convenience method for liquibaseConfiguration.getConfiguration(type).getProperty(property)
*/
public ConfigurationProperty getProperty(Class extends ConfigurationContainer> type, String property) {
ConfigurationContainer configuration = getConfiguration(type);
return configuration.getProperty(property);
}
protected T createConfiguration(Class type) {
try {
T configuration = type.getConstructor().newInstance();
configuration.init(configurationValueProviders);
return configuration;
} catch (Exception e) {
throw new UnexpectedLiquibaseException("Cannot create default configuration "+type.getName(), e);
}
}
/**
* Convenience method for {@link #describeValueLookupLogic(ConfigurationProperty)}
*/
public String describeValueLookupLogic(Class extends ConfigurationContainer> config, String property) {
return describeValueLookupLogic(getProperty(config, property));
}
/**
* Generates a human consumable description of how the configured ConfigurationValueProvider(s) will
* attempt to set a default value.
*/
public String describeValueLookupLogic(ConfigurationProperty property) {
List reasons = new ArrayList<>();
for (ConfigurationValueProvider container : configurationValueProviders) {
reasons.add(container.describeValueLookupLogic(property));
}
return StringUtils.join(reasons, " AND ");
}
}