All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.configuration.LiquibaseConfiguration Maven / Gradle / Ivy

There is a newer version: 4.30.0
Show newest version
package liquibase.configuration;

import liquibase.Scope;
import liquibase.SingletonObject;
import liquibase.exception.UnexpectedLiquibaseException;
import liquibase.servicelocator.ServiceLocator;
import liquibase.util.StringUtil;

import java.util.*;

/**
 * Provides unified management of configuration properties within Liquibase core and in extensions.
 * 

* Because this class focuses on raw/untyped access to what is actually configured, it is usually best to interact with {@link ConfigurationDefinition} instances * which provide type safety, standardized key naming, default values, and more. *

* "Registered" configuration definitions will be available for generated help. *

* This class will search through the configured {@link ConfigurationValueProvider}s. Standard value providers are auto-loaded on startup, but more can be added/removed at runtime. *

*/ public class LiquibaseConfiguration implements SingletonObject { private final SortedSet configurationValueProviders; private final SortedSet> definitions = new TreeSet<>(); public static final String REGISTERED_VALUE_PROVIDERS_KEY = "REGISTERED_VALUE_PROVIDERS"; /** * Track looked up values we have logged to avoid infinite loops between this and the log system using configurations * and to limit logged messages. * Only re-log when values changed from the last time they were logged. */ private final Map lastLoggedKeyValues = new HashMap<>(); protected LiquibaseConfiguration() { configurationValueProviders = new TreeSet<>((o1, o2) -> { if (o1.getPrecedence() < o2.getPrecedence()) { return -1; } else if (o1.getPrecedence() > o2.getPrecedence()) { return 1; } return o1.getClass().getName().compareTo(o2.getClass().getName()); }); } /** * @deprecated use {@link Scope#getSingleton(Class)} */ public static LiquibaseConfiguration getInstance() { return Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); } /** * Finishes configuration of this service. Called as the root scope is set up, should not be called elsewhere. */ public void init(Scope scope) { configurationValueProviders.clear(); ServiceLocator serviceLocator = scope.getServiceLocator(); final List containers = serviceLocator.findInstances(AutoloadedConfigurations.class); for (AutoloadedConfigurations container : containers) { Scope.getCurrentScope().getLog(getClass()).fine("Found ConfigurationDefinitions in " + container.getClass().getName()); } configurationValueProviders.addAll(serviceLocator.findInstances(ConfigurationValueProvider.class)); } /** * Adds a new {@link ConfigurationValueProvider} to the active collection of providers. */ public void registerProvider(ConfigurationValueProvider valueProvider) { this.configurationValueProviders.add(valueProvider); } /** * Removes the given {@link ConfigurationValueProvider} from the active collection of providers. * * @return true if the given provider was previously registered. */ public boolean unregisterProvider(ConfigurationValueProvider valueProvider) { return this.configurationValueProviders.remove(valueProvider); } /** * Removes a specific {@link ConfigurationValueProvider} from the active collection of providers. * * @return true if the provider was removed. */ public boolean removeProvider(ConfigurationValueProvider provider) { return this.configurationValueProviders.remove(provider); } /** * @deprecated use {@link ConfigurationDefinition} instances directly */ public T getConfiguration(Class type) { try { return type.newInstance(); } catch (Throwable e) { throw new UnexpectedLiquibaseException(e); } } public SortedSet getProviders() { return Collections.unmodifiableSortedSet(this.configurationValueProviders); } /** * Convenience method for {@link #getCurrentConfiguredValue(ConfigurationValueConverter, ConfigurationValueObfuscator, ConfigurationValueProvider[], String...)} * with no additional value providers. */ public ConfiguredValue getCurrentConfiguredValue(ConfigurationValueConverter converter, ConfigurationValueObfuscator obfuscator, String... keyAndAliases) { return this.getCurrentConfiguredValue(converter, obfuscator, null, keyAndAliases); } /** * Searches for the given keys in the current providers and applies any applicable modifiers. * * @param keyAndAliases The first element should be the canonical key name, with later elements being aliases. At least one element must be provided. * @param additionalValueProviders additional {@link ConfigurationValueProvider}s to use with higher priority than the ones registered in {@link LiquibaseConfiguration}. The higher the array index, the higher the priority. Can be null. * @return the value for the key, or null if not configured. */ public ConfiguredValue getCurrentConfiguredValue(ConfigurationValueConverter converter, ConfigurationValueObfuscator obfuscator, ConfigurationValueProvider[] additionalValueProviders, String... keyAndAliases) { if (keyAndAliases == null || keyAndAliases.length == 0) { throw new IllegalArgumentException("Must specify at least one key"); } ConfiguredValue details = new ConfiguredValue<>(keyAndAliases[0], converter, obfuscator); List finalValueProviders = new ArrayList<>(configurationValueProviders); if (additionalValueProviders != null) { finalValueProviders.addAll(Arrays.asList(additionalValueProviders)); } for (ConfigurationValueProvider provider : finalValueProviders) { final ProvidedValue providerValue = provider.getProvidedValue(keyAndAliases); if (providerValue != null) { details.override(providerValue); } } Scope.getCurrentScope().getSingleton(ConfiguredValueModifierFactory.class).override(details); final String foundValue = String.valueOf(details.getValue()); if (!foundValue.equals(lastLoggedKeyValues.get(keyAndAliases[0]))) { lastLoggedKeyValues.put(keyAndAliases[0], foundValue); //avoid infinite loop when logging is getting set up if (details.found()) { StringBuilder logMessage = new StringBuilder("Found '" + keyAndAliases[0] + "' configuration of '" + details.getValueObfuscated() + "'"); boolean foundFirstValue = false; for (ProvidedValue providedValue : details.getProvidedValues()) { logMessage.append("\n "); if (foundFirstValue) { logMessage.append("Overrides "); } // // Only lower case the first character is // the first two characters are NOT uppercase. This allows provider // strings like 'AWS' to be displayed correctly, i.e. as 'AWS', not 'aWS' // String describe = providedValue.describe(); char[] chars = describe.toCharArray(); if (chars.length >= 2 && Character.isUpperCase(chars[0]) && Character.isUpperCase(chars[1])) { logMessage.append(describe); } else { logMessage.append(StringUtil.lowerCaseFirst(describe)); } Object value = providedValue.getValue(); if (value != null) { String finalValue = String.valueOf(value); if (obfuscator != null) { finalValue = "*****"; } logMessage.append(" of '").append(finalValue).append("'"); } foundFirstValue = true; } Scope.getCurrentScope().getLog(getClass()).fine(logMessage.toString()); } else { Scope.getCurrentScope().getLog(getClass()).fine("No configuration value for " + StringUtil.join(keyAndAliases, " aka ") + " found"); } } return details; } /** * Registers a {@link ConfigurationDefinition} so it will be returned by {@link #getRegisteredDefinitions(boolean)} */ public void registerDefinition(ConfigurationDefinition definition) { this.definitions.add(definition); } /** * Returns all registered {@link ConfigurationDefinition}s. Registered definitions are used for generated help documentation. * @param includeInternal if true, include {@link ConfigurationDefinition#isInternal()} definitions. */ public SortedSet> getRegisteredDefinitions(boolean includeInternal) { SortedSet> returnSet = new TreeSet<>(); for (ConfigurationDefinition definition : this.definitions) { if (includeInternal || !definition.isInternal()) { returnSet.add(definition); } } return Collections.unmodifiableSortedSet(returnSet); } /** * @return the registered {@link ConfigurationDefinition} associated with this key. Null if none match. */ public ConfigurationDefinition getRegisteredDefinition(String key) { for (ConfigurationDefinition def : getRegisteredDefinitions(true)) { List keys = new ArrayList<>(); keys.add(def.getKey()); keys.addAll(def.getAliasKeys()); for (String keyName : keys) { if (keyName.equalsIgnoreCase(key)) { return def; } if (keyName.replace(".", "").equalsIgnoreCase(key)) { return def; } } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy