package liquibase.configuration; import liquibase.exception.UnexpectedLiquibaseException; import java.util.*; /** * Base class for configuration classes used by {@link liquibase.configuration.LiquibaseConfiguration}. * Implementations must have a no-arg constructor for LiquibaseConfiguration to initialize them as needed. * <p> * AbstractConfigurationContainer implementations contain a "namespace" which can be used as the prefix to system properties or cases where there may be name conflicts. * <p> * Properties can be accessed by name using the {@link #getValue(String, Class)} method, but implementation should implement standard get/set methods for easier use. */ public abstract class AbstractConfigurationContainer implements ConfigurationContainer { private ConfigurationContainer configurationContainer; /** * Subclasses must call this constructor passing the namespace, but must themselves provide a no-arg public constructor. */ protected AbstractConfigurationContainer(String namespace) { this.configurationContainer = new ConfigurationContainer(namespace); } protected ConfigurationContainer getContainer() { return configurationContainer; } /** * Return the ConfigurationProperty object for the given property name. * Normally {@link #getValue(String, Class)} is the easiest method to call. */ @Override public ConfigurationProperty getProperty(String propertyName) { return getContainer().getProperty(propertyName); } /** * Return all available properties. */ @Override public Set<ConfigurationProperty> getProperties() { return new HashSet<ConfigurationProperty>(getContainer().properties.values()); } /** * Returns the value for the given property cast to the passed returnType. * If the type of the property and the given return type are not compatible an exception will be thrown. * If the passed propertyName is not a defined property, an exception is thrown. */ @Override public <T> T getValue(String propertyName, Class<T> returnType) { return getContainer().getValue(propertyName, returnType); } /** * Override default values for properties with the given ConfigurationProviders. */ @Override public void init(ConfigurationValueProvider... configurationValueProviders) { if (configurationValueProviders != null) { for (ConfigurationProperty property : getContainer().properties.values()) { property.init(configurationValueProviders); } } } @Override public void setValue(String propertyName, Object value) { getContainer().setValue(propertyName, value); } /** * Like a java.util.Map, but with extra logic for working with ConfigurationProperties. * Used to define and hold available properties. Methods return "this" to allow easy chaining. */ protected static class ConfigurationContainer { private final String namespace; private final Map<String, ConfigurationProperty> properties = new HashMap<String, ConfigurationProperty>(); protected ConfigurationContainer(String namespace) { this.namespace = namespace; } /** * Adds a property definition to this configuration. */ public ConfigurationProperty addProperty(String propertyName, Class type) { ConfigurationProperty property = new ConfigurationProperty(namespace, propertyName, type); properties.put(propertyName, property); return property; } /** * Returns the ConfigurationProperty object with the given name. If the property was not defined, an exception is thrown. */ public ConfigurationProperty getProperty(String propertyName) { ConfigurationProperty property = properties.get(propertyName); if (property == null) { throw new UnexpectedLiquibaseException("Unknown property on "+getClass().getName()+": "+propertyName); } return property; } /** * Returns the value for the given property. If the property was not defined, an exception is thrown. */ public <T> T getValue(String propertyName, Class<T> returnType) { ConfigurationProperty property = getProperty(propertyName); if (!property.getType().isAssignableFrom(returnType)) { throw new UnexpectedLiquibaseException("Property "+propertyName+" on "+getClass().getName()+" is of type "+property.getType().getName()+", not "+returnType.getName()); } return (T) property.getValue(); } /** * Sets the value for the given property. * Any value set through this method will overwrite any default values found by the configured ConfigurationPropertyProviders. * If the property was not defined, an exception is thrown. */ public void setValue(String propertyName, Object value) { ConfigurationProperty property = properties.get(propertyName); if (property == null) { throw new UnexpectedLiquibaseException("Unknown property on "+getClass().getName()+": "+propertyName); } property.setValue(value); } } }