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

liquibase.changelog.ChangeLogParameters Maven / Gradle / Ivy

There is a newer version: 4.29.1
Show newest version
package liquibase.changelog;

import liquibase.ContextExpression;
import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Labels;
import liquibase.database.Database;
import liquibase.database.DatabaseList;
import liquibase.exception.DatabaseException;
import liquibase.exception.UnknownChangeLogParameterException;
import liquibase.util.StringUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Holds the parameters configured for a {@link DatabaseChangeLog}.
 * 

* In general, the end behavior of defined parameters is "the first set value wins". * For example, if you set a parameter "x" to "1" and then set it to "2", the value will remain "1". * This immutable property behavior allows users to easily set default values, knowing that any "upstream" overrides will take priority. *

* In determining which property value is actually "first set", context, label, and dbms filtering is taken into account. *

* Properties can be defined as "global" or "local". Global properties span all change logs. * A global setting configured in an included changelog is still available to all changesets * Local properties are only available in the change log that they are defined in -- not even in changelogs "included" by the file that defines the property. */ public class ChangeLogParameters { private final List globalParameters = new ArrayList<>(); private final Map> localParameters = new HashMap<>(); private final ExpressionExpander expressionExpander; private String filterDatabase; private Contexts filterContexts; private LabelExpression filterLabels; /** * Calls {@link #ChangeLogParameters(Database)} with a null database. */ public ChangeLogParameters() { this(null); } /** * Creates a new ChangeLogParameters instance, populated with a set of "database.*" global parameters based on the passed database configuration. * If the database is null, no global parameters are added. * * The passed database is used as a default value for {@link #getDatabase()} */ public ChangeLogParameters(Database database) { globalParameters.addAll(System.getenv().entrySet().stream().map(e -> new ChangeLogParameter(e.getKey(), e.getValue())).collect(Collectors.toList())); globalParameters.addAll(System.getProperties().entrySet().stream().map(e -> new ChangeLogParameter(String.valueOf(e.getKey()), e.getValue())).collect(Collectors.toList())); if (database != null) { this.set("database.autoIncrementClause", database.getAutoIncrementClause(null, null, null, null)); this.set("database.currentDateTimeFunction", database.getCurrentDateTimeFunction()); this.set("database.databaseChangeLogLockTableName", database.getDatabaseChangeLogLockTableName()); this.set("database.databaseChangeLogTableName", database.getDatabaseChangeLogTableName()); try { this.set("database.databaseMajorVersion", database.getDatabaseMajorVersion()); } catch (DatabaseException ignore) { } try { this.set("database.databaseMinorVersion", database.getDatabaseMinorVersion()); } catch (DatabaseException ignore) { } this.set("database.databaseProductName", database.getDatabaseProductName()); try { this.set("database.databaseProductVersion", database.getDatabaseProductVersion()); } catch (DatabaseException ignore) { } this.set("database.defaultCatalogName", database.getDefaultCatalogName()); this.set("database.defaultSchemaName", database.getDefaultSchemaName()); this.set("database.defaultSchemaNamePrefix", (StringUtil.trimToNull(database.getDefaultSchemaName()) == null) ? "" : ("." + database.getDefaultSchemaName())); this.set("database.lineComment", database.getLineComment()); this.set("database.liquibaseSchemaName", database.getLiquibaseSchemaName()); this.set("database.typeName", database.getShortName()); try { this.set("database.isSafeToRunUpdate", database.isSafeToRunUpdate()); } catch (DatabaseException ignore) { } this.set("database.requiresPassword", database.requiresPassword()); this.set("database.requiresUsername", database.requiresUsername()); this.set("database.supportsForeignKeyDisable", database.supportsForeignKeyDisable()); this.set("database.supportsInitiallyDeferrableColumns", database.supportsInitiallyDeferrableColumns()); this.set("database.supportsRestrictForeignKeys", database.supportsRestrictForeignKeys()); this.set("database.supportsSchemas", database.supportsSchemas()); this.set("database.supportsSequences", database.supportsSequences()); this.set("database.supportsTablespaces", database.supportsTablespaces()); this.set("database.supportsNotNullConstraintNames", database.supportsNotNullConstraintNames()); this.filterDatabase = database.getShortName(); } this.expressionExpander = new ExpressionExpander(this); this.filterContexts = new Contexts(); this.filterLabels = new LabelExpression(); } /** * Sets a global changelog parameter with no context/label/database filters on it. * Convenience version of {@link #set(String, Object, ContextExpression, Labels, String...)}. */ public void set(String parameter, Object value) { this.set(parameter, value, new ContextExpression(), new Labels()); } /** * Sets a local changelog parameter with no context/label/database filters on it. * Convenience version of {@link #setLocal(String, Object, DatabaseChangeLog, ContextExpression, Labels, String...)}. */ public void setLocal(String parameter, Object value, DatabaseChangeLog changeLog) { this.setLocal(parameter, value, changeLog, new ContextExpression(), new Labels()); } /** * Calls either {@link #set(String, Object, ContextExpression, Labels, String...)} or {@link #setLocal(String, Object, DatabaseChangeLog, ContextExpression, Labels, String...)} depending on the value of globalParam. */ public void set(String key, Object value, ContextExpression contexts, Labels labels, String databases, boolean globalParam, DatabaseChangeLog changeLog) { String[] parsedDatabases = null; if (databases != null && databases.length() > 0) { parsedDatabases = StringUtil.splitAndTrim(databases, ",").toArray(new String[0]); } if (globalParam) { set(key, value, contexts, labels, parsedDatabases); } else { setLocal(key, value, changeLog, contexts, labels, parsedDatabases); } } /** * Convenience version of {@link #set(String, Object, ContextExpression, Labels, String, boolean, DatabaseChangeLog)}. */ public void set(String key, Object value, String contexts, String labels, String databases, boolean globalParam, DatabaseChangeLog changeLog) { set(key, value, new ContextExpression(contexts), new Labels(labels), databases, globalParam, changeLog); } /** * Sets a global changelog parameter. * Just because you call this with a particular key, does not mean it will override the existing value. See the class description for more details on how values act as if they are immutable. */ public void set(String key, Object value, ContextExpression contexts, Labels labels, String... databases) { globalParameters.add(new ChangeLogParameter(key, value, contexts, labels, databases)); } /** * Sets a changelog parameter local to the given changeLog file. * Just because you call this with a particular key, does not mean it will override the existing value. See the class description for more details on how values act as if they are immutable. * * @param changeLog required for local parameters, ignored for global parameters **/ public void setLocal(String key, Object value, DatabaseChangeLog changeLog, ContextExpression contexts, Labels labels, String... databases) { if (changeLog == null) { throw new IllegalArgumentException("changeLog cannot be null when setting a local parameter"); } final String changelogKey = getLocalKey(changeLog); List localParams = localParameters.get(changelogKey); if (localParams == null) { localParams = new ArrayList<>(); this.localParameters.put(changelogKey, localParams); } localParams.add(new ChangeLogParameter(key, value, contexts, labels, databases)); } /** * Get the value of the given parameter, taking into account parameters local to the given changelog file and * values configured in {@link #getContexts()} and {@link #getLabels()} and the database. */ public Object getValue(String key, DatabaseChangeLog changeLog) { final ChangeLogParameter param = getChangelogParameter(key, changeLog, getFilter()); if (param == null) { return null; } return param.getValue(); } /** * Return whether the given parameters is defined, taking into account parameters local to the given changelog file * as well as contexts, labels, and database configured on this instance */ public boolean hasValue(String key, DatabaseChangeLog changeLog) { return getChangelogParameter(key, changeLog, getFilter()) != null; } /** * Expand any expressions in the given string, taking into account parameters local to the given changelog file as well as * contexts, labels, and database configured in this instance. */ public String expandExpressions(String string, DatabaseChangeLog changeLog) throws UnknownChangeLogParameterException { return expressionExpander.expandExpressions(string, changeLog); } /** * Gets the contexts to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public Contexts getContexts() { return filterContexts; } /** * Sets the contexts to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public void setContexts(Contexts contexts) { this.filterContexts = contexts; } /** * Gets the labels to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public LabelExpression getLabels() { return filterLabels; } /** * Sets the labels to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public void setLabels(LabelExpression labels) { this.filterLabels = labels; } /** * Sets the database to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public String getDatabase() { return filterDatabase; } /** * Sets the database to filter calls to {@link #getValue(String, DatabaseChangeLog)} etc. with. */ public void setDatabase(String filterDatabase) { this.filterDatabase = filterDatabase; } private Filter getFilter() { return new Filter(this.filterDatabase, this.filterContexts, this.filterLabels); } private ChangeLogParameter getChangelogParameter(String key, DatabaseChangeLog changeLog, Filter filter) { List localList = null; if (changeLog != null) { localList = localParameters.get(getLocalKey(changeLog)); } for (List paramList : Arrays.asList(globalParameters, localList)) { if (paramList == null) { continue; } for (ChangeLogParameter parameter : paramList) { if (parameter.getKey().equalsIgnoreCase(key) && (filter == null || filter.matches(parameter))) { return parameter; } } } return null; } /** * The key to use in {@link #localParameters} */ private String getLocalKey(DatabaseChangeLog changeLog) { if (changeLog == null) { return "null changelog path"; } return changeLog.getLogicalFilePath(); } private static class ChangeLogParameter { private final String key; private final Object value; private final ContextExpression validContexts; private final Labels validLabels; private final List validDatabases; public ChangeLogParameter(String key, Object value) { this(key, value, null, null, null); } public ChangeLogParameter(String key, Object value, ContextExpression validContexts, Labels labels, String[] validDatabases) { this.key = key; this.value = value; this.validContexts = validContexts == null ? new ContextExpression() : validContexts; this.validLabels = labels == null ? new Labels() : labels; if (validDatabases == null) { this.validDatabases = null; } else { this.validDatabases = Arrays.asList(validDatabases); } } public String getKey() { return key; } public Object getValue() { return value; } public List getValidDatabases() { return validDatabases; } public ContextExpression getValidContexts() { return validContexts; } public Labels getLabels() { return validLabels; } @Override public String toString() { return getValue().toString(); } } private static class Filter { private final Contexts contexts; private final LabelExpression labels; private final String database; public Filter(String database, Contexts contexts, LabelExpression labels) { this.contexts = contexts; this.labels = labels; this.database = database; } public boolean matches(ChangeLogParameter parameter) { return (labels == null || labels.matches(parameter.getLabels())) && (contexts == null || parameter.getValidContexts().matches(contexts)) && (database == null || DatabaseList.definitionMatches(parameter.getValidDatabases(), database, true)) ; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy