From 2382822cc7db6f02e0810c0dd692a08a00c5a07e Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Fri, 22 Jan 2021 10:03:43 -0600 Subject: [PATCH 01/17] Started refactoring of CLI --- liquibase-cli/pom.xml | 20 +++++ .../integration/commandline/Main.java | 7 ++ .../commandline/CommandLineUtils.java | 3 +- .../commandline/{Main.java => OldMain.java} | 8 +- .../{MainTest.java => OldMainTest.java} | 84 +++++++++---------- pom.xml | 1 + 6 files changed, 75 insertions(+), 48 deletions(-) create mode 100644 liquibase-cli/pom.xml create mode 100644 liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java rename liquibase-core/src/main/java/liquibase/integration/commandline/{Main.java => OldMain.java} (99%) rename liquibase-core/src/test/java/liquibase/integration/commandline/{MainTest.java => OldMainTest.java} (94%) mode change 100755 => 100644 diff --git a/liquibase-cli/pom.xml b/liquibase-cli/pom.xml new file mode 100644 index 00000000000..d9d19909b4f --- /dev/null +++ b/liquibase-cli/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.liquibase + liquibase-base-module + ${liquibase.version} + ../base-module.pom.xml + + + Liquibase CLI interface + + liquibase-cli + + + + + + diff --git a/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java new file mode 100644 index 00000000000..2dbdd710622 --- /dev/null +++ b/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java @@ -0,0 +1,7 @@ +package liquibase.integration.commandline; + +public class Main { + public static void main(String[] args) { + System.out.println("New CLI!"); + } +} diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java index 22eaf33bed7..96c81513572 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java @@ -15,7 +15,6 @@ import liquibase.diff.output.ObjectChangeFilter; import liquibase.exception.DatabaseException; import liquibase.exception.LiquibaseException; -import liquibase.logging.LogService; import liquibase.resource.ClassLoaderResourceAccessor; import liquibase.resource.ResourceAccessor; import liquibase.util.LiquibaseUtil; @@ -36,7 +35,7 @@ /** * Common Utility methods used in the CommandLine application and the Maven plugin. - * These methods were originally moved from {@link Main} so they could be shared. + * These methods were originally moved from {@link OldMain} so they could be shared. * * @author Peter Murray */ diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java similarity index 99% rename from liquibase-core/src/main/java/liquibase/integration/commandline/Main.java rename to liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java index 41dead15250..2bf579a0521 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java @@ -58,9 +58,9 @@ /** * Class for executing Liquibase via the command line. */ -public class Main { +public class OldMain { private static final String ERRORMSG_UNEXPECTED_PARAMETERS = "unexpected.command.parameters"; - private static final Logger LOG = Scope.getCurrentScope().getLog(Main.class); + private static final Logger LOG = Scope.getCurrentScope().getLog(OldMain.class); private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core"); private static XMLResourceBundle commandLineHelpBundle = ((XMLResourceBundle) getBundle ("liquibase/i18n/liquibase-commandline-helptext", new XmlResourceBundleControl())); @@ -193,7 +193,7 @@ public static int run(String[] args) throws Exception { return Scope.child(scopeObjects, new Scope.ScopedRunnerWithReturn() { @Override public Integer run() throws Exception { - Main main = new Main(); + OldMain main = new OldMain(); try { GlobalConfiguration globalConfiguration = LiquibaseConfiguration.getInstance().getConfiguration @@ -409,7 +409,7 @@ public Integer run() throws Exception { }); } - private static boolean setupNeeded(Main main) throws CommandLineParsingException { + private static boolean setupNeeded(OldMain main) throws CommandLineParsingException { if (main.command.toLowerCase().startsWith(COMMANDS.REGISTER_CHANGELOG.toLowerCase())) { return false; } diff --git a/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java old mode 100755 new mode 100644 similarity index 94% rename from liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java rename to liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java index 3a40da1e757..ed7cb726e03 --- a/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java @@ -18,26 +18,26 @@ /** - * Tests for {@link Main} + * Tests for {@link OldMain} */ -public class MainTest { +public class OldMainTest { @Test public void testCodePointCheck() { char badChar = 8192; char anotherBadChar = 160; - Main.CodePointCheck codePointCheck = Main.checkArg("test"); + OldMain.CodePointCheck codePointCheck = OldMain.checkArg("test"); Assert.assertTrue("This should be a valid string", codePointCheck == null); StringBuilder builder = new StringBuilder(); builder.append(badChar); - codePointCheck = Main.checkArg(builder.toString()); + codePointCheck = OldMain.checkArg(builder.toString()); Assert.assertTrue("The first character should be invalid",codePointCheck.position == 0); builder = new StringBuilder(); builder.append("A"); builder.append(badChar); - codePointCheck = Main.checkArg(builder.toString()); + codePointCheck = OldMain.checkArg(builder.toString()); Assert.assertTrue("The last character should be invalid",codePointCheck.position == builder.length()-1); builder = new StringBuilder(); @@ -45,14 +45,14 @@ public void testCodePointCheck() { builder.append(anotherBadChar); builder.append("DEF"); int pos = builder.toString().indexOf(anotherBadChar); - codePointCheck = Main.checkArg(builder.toString()); + codePointCheck = OldMain.checkArg(builder.toString()); Assert.assertTrue("The character in position " + pos + " should be invalid",codePointCheck.position == pos); } @Test public void checkSetup2() { - Main main = new Main(); + OldMain main = new OldMain(); main.command = "snapshot"; main.url = "jdbc:oracle://localhost:1521/ORCL"; main.commandParams.add("--outputSchemasAs"); @@ -77,7 +77,7 @@ public void checkSetup2() { // @Mock // private SnapshotCommand.SnapshotCommandResult snapshotCommandResult; - public MainTest() throws Exception { + public OldMainTest() throws Exception { // PowerMockito.mockStatic(CommandFactory.class); // // commandFactory = PowerMockito.mock(CommandFactory.class); @@ -113,7 +113,7 @@ public void testLocalProperties() throws Exception { "snapshot" }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertTrue("Read context from liquibase.local.properties", ((cli.contexts != null) && cli.contexts.contains @@ -125,7 +125,7 @@ public void testLocalProperties() throws Exception { @Test public void startWithoutParameters() throws Exception { // exit.expectSystemExitWithStatus(1); - Main.run(new String[0]); + OldMain.run(new String[0]); assertTrue("We just want to survive until this point", true); } @@ -133,7 +133,7 @@ public void startWithoutParameters() throws Exception { public void globalConfigurationSaysDoNotRun() throws Exception { LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) .setValue("shouldRun", false); - int errorLevel = Main.run(new String[0]); + int errorLevel = OldMain.run(new String[0]); LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) .setValue("shouldRun", true); assertEquals(errorLevel, 0); // If it SHOULD run, and we would call without parameters, we would get -1 @@ -189,7 +189,7 @@ public void migrateWithAllParameters() throws Exception { "update", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Option --driver was parsed correctly", "DRIVER", cli.driver); @@ -215,7 +215,7 @@ public void falseBooleanParameters() throws Exception { "update", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase=false was parsed correctly", Boolean.FALSE, cli @@ -230,7 +230,7 @@ public void convertMigrateToUpdate() throws Exception { "migrate", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase was parsed correctly", @@ -245,7 +245,7 @@ public void trueBooleanParameters() throws Exception { "update", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase=true was parsed correctly", @@ -261,7 +261,7 @@ public void parameterWithoutDash() throws Exception { "update", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); } @@ -273,7 +273,7 @@ public void emptyUrlParameter() throws Exception { "update", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); List errMsgs = cli.checkSetup(); assertEquals("specifying an empty URL should return 1 error message.", 1, errMsgs.size()); @@ -288,7 +288,7 @@ public void misplacedDiffTypesDataOption() throws Exception { "--diffTypes=data" }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); List errMsgs = cli.checkSetup(); assertEquals("the combination of --diffTypes=data and diffChangeLog must not be accepted.", 1, errMsgs.size()); @@ -304,7 +304,7 @@ public void unknownParameter() throws Exception { "migrate", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); } @@ -317,7 +317,7 @@ public void statusVerbose() throws Exception { "--verbose", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -335,7 +335,7 @@ public void statusVerboseWithValue() throws Exception { "--verbose=true", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -354,7 +354,7 @@ public void statusWithoutVerbose() throws Exception { "status", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -366,14 +366,14 @@ public void statusWithoutVerbose() throws Exception { @Test(expected = CommandLineParsingException.class) public void configureNonExistantClassloaderLocation() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); cli.classpath = "badClasspathLocation"; cli.configureClassLoader(); } @Test public void windowsConfigureClassLoaderLocation() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); if (cli.isWindows()) { @@ -391,7 +391,7 @@ public void windowsConfigureClassLoaderLocation() throws Exception { @Test public void unixConfigureClassLoaderLocation() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); if (!cli.isWindows()) { @@ -410,7 +410,7 @@ public void unixConfigureClassLoaderLocation() throws Exception { @Test public void propertiesFileWithNoOtherArgs() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -440,7 +440,7 @@ public void propertiesFileWithNoOtherArgs() throws Exception { @Test public void propertiesFileWithOtherArgs() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); cli.username = "PASSED USERNAME"; cli.password = "PASSED PASSWD"; @@ -473,7 +473,7 @@ public void propertiesFileWithOtherArgs() throws Exception { @Test public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictFalseIsInFile() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -491,7 +491,7 @@ public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictFalseIsInFi @Test public void propertiesFileChangeLogParameters() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -509,7 +509,7 @@ public void propertiesFileChangeLogParameters() throws Exception { @Test public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictModeIsFalse() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); String[] args = new String[]{"--strict=false"}; cli.parseOptions(args); @@ -528,7 +528,7 @@ public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictModeIsFalse @Test(expected = CommandLineParsingException.class) public void propertiesFileParsingShouldFailOnUnknownArgumentsIfStrictMode() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -544,7 +544,7 @@ public void propertiesFileParsingShouldFailOnUnknownArgumentsIfStrictMode() thro @Test public void applyDefaults() { - Main cli = new Main(); + OldMain cli = new OldMain(); cli.promptForNonLocalDatabase = Boolean.TRUE; cli.applyDefaults(); @@ -562,7 +562,7 @@ public void applyDefaults() { @Test(expected = CommandLineParsingException.class) public void propertiesFileWithBadArgs() throws Exception { - Main cli = new Main(); + OldMain cli = new OldMain(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -577,7 +577,7 @@ public void propertiesFileWithBadArgs() throws Exception { @Test public void checkSetup() { - Main cli = new Main(); + OldMain cli = new OldMain(); assertTrue(!cli.checkSetup().isEmpty()); cli.driver = "driver"; @@ -685,7 +685,7 @@ public void printHelp() throws Exception { final int MAXIMUM_LENGTH = 80; ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Main cli = new Main(); + OldMain cli = new OldMain(); cli.printHelp(new PrintStream(stream)); BufferedReader reader = new BufferedReader(new StringReader(new String(stream.toByteArray()))); @@ -711,7 +711,7 @@ public void tag() throws Exception { "tag", "TagHere" }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals("Command line option --driver is parsed correctly", "DRIVER", cli.driver); @@ -734,7 +734,7 @@ public void migrateWithEqualsInParams() throws Exception { "migrate", }; - Main cli = new Main(); + OldMain cli = new OldMain(); cli.parseOptions(args); assertEquals(url, cli.url); @@ -742,7 +742,7 @@ public void migrateWithEqualsInParams() throws Exception { @Test public void fixArgs() { - Main liquibase = new Main(); + OldMain liquibase = new OldMain(); String[] fixedArgs = liquibase.fixupArgs(new String[]{"--defaultsFile", "liquibase.properties", "migrate"}); assertEquals("--defaultsFile=liquibase.properties migrate", StringUtil.join(Arrays.asList(fixedArgs), " ")); @@ -768,7 +768,7 @@ public void fixArgs() { @Test public void testVersionArg() throws Exception { - Main.run(new String[] {"--version"}); + OldMain.run(new String[] {"--version"}); assertTrue(true); // Just want to test if the call goes through } @@ -776,7 +776,7 @@ public void testVersionArg() throws Exception { public void testSplitArgWithValueEndingByEqualSing() throws CommandLineParsingException { final String argName = "password"; final String argValue = "s3-cr3t="; - Main tested = new Main(); + OldMain tested = new OldMain(); tested.parseOptions(new String[] { "--" + argName + "=" + argValue }); @@ -785,7 +785,7 @@ public void testSplitArgWithValueEndingByEqualSing() throws CommandLineParsingEx @Test public void testDatabaseChangeLogTableName_Properties() throws IOException, CommandLineParsingException { - Main main = new Main(); + OldMain main = new OldMain(); Properties props = new Properties(); props.setProperty("databaseChangeLogTableName", "PROPSCHANGELOG"); props.setProperty("databaseChangeLogLockTableName", "PROPSCHANGELOGLOCK"); @@ -800,7 +800,7 @@ public void testDatabaseChangeLogTableName_Properties() throws IOException, Comm @Test public void testDatabaseChangeLogTableName_Options() throws CommandLineParsingException { - Main main = new Main(); + OldMain main = new OldMain(); String[] opts = { "--databaseChangeLogTableName=OPTSCHANGELOG", "--databaseChangeLogLockTableName=OPTSCHANGELOGLOCK"}; diff --git a/pom.xml b/pom.xml index f66141b17cb..d9ca96f9861 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ liquibase-core + liquibase-cli liquibase-maven-plugin liquibase-cdi liquibase-integration-tests From a00dfb3f2b7827d0183e3059739d9e28bdce50a4 Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Fri, 22 Jan 2021 16:38:51 -0600 Subject: [PATCH 02/17] Converted CommandFactory to standard plugin system --- .../src/main/java/liquibase/Liquibase.java | 2 +- .../liquibase/command/AbstractCommand.java | 12 ++- .../liquibase/command/CommandArgument.java | 45 +++++++++++ .../liquibase/command/CommandFactory.java | 76 +++---------------- .../liquibase/command/LiquibaseCommand.java | 10 ++- .../main/java/liquibase/hub/HubUpdater.java | 2 +- .../commandline/CommandLineUtils.java | 8 +- .../integration/commandline/OldMain.java | 15 ++-- .../integration/commandline/OldMainTest.java | 2 +- .../maven/plugins/LiquibaseDatabaseDiff.java | 3 +- .../maven/plugins/LiquibaseHistoryMojo.java | 3 +- .../LiquibaseRegisterChangeLogMojo.java | 2 +- .../LiquibaseRollbackOneChangeSetMojo.java | 3 +- .../LiquibaseRollbackOneChangeSetSQL.java | 2 +- .../LiquibaseRollbackOneUpdateMojo.java | 3 +- .../LiquibaseRollbackOneUpdateSQL.java | 2 +- .../maven/plugins/LiquibaseSyncHubMojo.java | 3 +- 17 files changed, 99 insertions(+), 94 deletions(-) create mode 100644 liquibase-core/src/main/java/liquibase/command/CommandArgument.java diff --git a/liquibase-core/src/main/java/liquibase/Liquibase.java b/liquibase-core/src/main/java/liquibase/Liquibase.java index 56681a40c30..4f6ab6ea650 100644 --- a/liquibase-core/src/main/java/liquibase/Liquibase.java +++ b/liquibase-core/src/main/java/liquibase/Liquibase.java @@ -1690,7 +1690,7 @@ public final void dropAll(CatalogAndSchema... schemas) throws DatabaseException @Override public void run() throws Exception { - DropAllCommand dropAll = (DropAllCommand) CommandFactory.getInstance().getCommand("dropAll"); + DropAllCommand dropAll = (DropAllCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("dropAll"); dropAll.setDatabase(Liquibase.this.getDatabase()); dropAll.setSchemas(finalSchemas); dropAll.setLiquibase(Liquibase.this); diff --git a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java index a5c78f31e0e..5eb49f3e551 100644 --- a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java @@ -2,14 +2,17 @@ import liquibase.servicelocator.PrioritizedService; +import java.util.SortedSet; +import java.util.TreeSet; + public abstract class AbstractCommand implements LiquibaseCommand { @Override public int getPriority(String commandName) { if ((commandName != null) && commandName.equalsIgnoreCase(getName())) { - return PrioritizedService.PRIORITY_DEFAULT; + return PRIORITY_DEFAULT; } else { - return -1; + return PRIORITY_NOT_APPLICABLE; } } @@ -27,4 +30,9 @@ public final T execute() throws CommandExecutionException { } protected abstract T run() throws Exception; + + @Override + public SortedSet getArguments() { + return new TreeSet<>(); + } } diff --git a/liquibase-core/src/main/java/liquibase/command/CommandArgument.java b/liquibase-core/src/main/java/liquibase/command/CommandArgument.java new file mode 100644 index 00000000000..ac0b7760644 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/command/CommandArgument.java @@ -0,0 +1,45 @@ +package liquibase.command; + +import java.util.Objects; + +public class CommandArgument implements Comparable { + + private String name; + private String description; + private Class dataType; + private boolean required; + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Class getDataType() { + return dataType; + } + + public boolean isRequired() { + return required; + } + + @Override + public int compareTo(Object o) { + return this.getName().compareTo(((CommandArgument) o).getName()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CommandArgument that = (CommandArgument) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java index af9a7937901..527f60945ab 100644 --- a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java +++ b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java @@ -1,79 +1,23 @@ package liquibase.command; -import liquibase.Scope; -import liquibase.exception.UnexpectedLiquibaseException; -import liquibase.servicelocator.ServiceLocator; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import liquibase.plugin.AbstractPluginFactory; /** * Manages {@link LiquibaseCommand} implementations. */ -public class CommandFactory { - - private static CommandFactory instance; +public class CommandFactory extends AbstractPluginFactory { - private List commands; - - private CommandFactory() { - commands = new ArrayList<>(); - try { - for (LiquibaseCommand command : Scope.getCurrentScope().getServiceLocator().findInstances(LiquibaseCommand.class)) { - register(command); - } - } catch (Exception e) { - throw new UnexpectedLiquibaseException(e); - } + @Override + protected Class getPluginClass() { + return LiquibaseCommand.class; } - public static synchronized CommandFactory getInstance() { - if (instance == null) { - instance = new CommandFactory(); - } - return instance; + @Override + protected int getPriority(LiquibaseCommand obj, Object... args) { + return obj.getPriority((String) args[0]); } - public static synchronized void reset() { - instance = new CommandFactory(); + public LiquibaseCommand getCommand(String commandName) { + return getPlugin(commandName); } - - - public LiquibaseCommand getCommand(final String commandName) { - - Comparator commandComparator = new Comparator() { - @Override - public int compare(LiquibaseCommand o1, LiquibaseCommand o2) { - return Integer.valueOf(o2.getPriority(commandName)).compareTo(o1.getPriority(commandName)); - } - }; - - - List sortedCommands = new ArrayList<>(commands); - Collections.sort(sortedCommands, commandComparator); - if (sortedCommands.isEmpty()) { - throw new UnexpectedLiquibaseException("Could not find command class for "+commandName); - } - try { - LiquibaseCommand command = sortedCommands.iterator().next().getClass().getConstructor().newInstance(); - - if (command.getPriority(commandName) <= 0) { - throw new UnexpectedLiquibaseException("Could not find command class for "+commandName); - } - return command; - } catch (Exception e) { - throw new UnexpectedLiquibaseException(e); - } - } - - public void register(LiquibaseCommand command) { - commands.add(command); - } - - public void unregister(LiquibaseCommand command) { - commands.remove(command); - } - } diff --git a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java index 3627208a775..af7e2ea6e4b 100644 --- a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java @@ -1,11 +1,15 @@ package liquibase.command; +import liquibase.plugin.Plugin; + +import java.util.SortedSet; + /** * Commands are higher-level functions. They may execute multiple {@link liquibase.change.Change}s and usually interact with the outside world. * Commands are different from Actions in that they implement end-user functionality rather than small pieces of logic. * We package functionaly as commands so that the command line interface as well as other integrations can all use the same business logic. */ -public interface LiquibaseCommand { +public interface LiquibaseCommand extends Plugin { String getName(); @@ -17,4 +21,6 @@ public interface LiquibaseCommand { T execute() throws CommandExecutionException; int getPriority(String commandName); -} \ No newline at end of file + + SortedSet getArguments(); +} diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index e0e6be36d25..18b4f1824f6 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -219,7 +219,7 @@ public boolean hubIsNotAvailable(String changeLogId) { } public void syncHub(String changeLogFile, Database database, DatabaseChangeLog databaseChangeLog, UUID hubConnectionId) { - final SyncHubCommand syncHub = (SyncHubCommand) CommandFactory.getInstance().getCommand("syncHub"); + final SyncHubCommand syncHub = (SyncHubCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("syncHub"); syncHub.setChangeLogFile(changeLogFile); syncHub.setUrl(database.getConnection().getURL()); syncHub.setHubConnectionId(hubConnectionId != null ? Objects.toString(hubConnectionId) : null); diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java index 96c81513572..f77729b9e51 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java @@ -148,7 +148,7 @@ public static void doDiff(Database referenceDatabase, Database targetDatabase, S public static DiffCommand createDiffCommand(Database referenceDatabase, Database targetDatabase, String snapshotTypes, CompareControl.SchemaComparison[] schemaComparisons, ObjectChangeFilter objectChangeFilter, PrintStream output) { - DiffCommand diffCommand = (DiffCommand) CommandFactory.getInstance().getCommand("diff"); + DiffCommand diffCommand = (DiffCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("diff"); diffCommand .setReferenceDatabase(referenceDatabase) @@ -193,8 +193,7 @@ public static void doDiffToChangeLog(String changeLogFile, CompareControl.SchemaComparison[] schemaComparisons) throws LiquibaseException, IOException, ParserConfigurationException { - DiffToChangeLogCommand command = (DiffToChangeLogCommand) CommandFactory.getInstance().getCommand - ("diffChangeLog"); + DiffToChangeLogCommand command = (DiffToChangeLogCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("diffChangeLog"); command.setReferenceDatabase(referenceDatabase) .setTargetDatabase(targetDatabase) .setSnapshotTypes(snapshotTypes) @@ -232,8 +231,7 @@ public static void doGenerateChangeLog(String changeLogFile, Database originalDa CompareControl compareControl = new CompareControl(comparisons, snapshotTypes); diffOutputControl.setDataDir(dataDir); - GenerateChangeLogCommand command = (GenerateChangeLogCommand) CommandFactory.getInstance().getCommand - ("generateChangeLog"); + GenerateChangeLogCommand command = (GenerateChangeLogCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("generateChangeLog"); command.setReferenceDatabase(originalDatabase) .setSnapshotTypes(snapshotTypes) diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java index 2bf579a0521..a1eabea3989 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java @@ -1466,7 +1466,7 @@ protected void doMigration() throws Exception { System.exit(0); } if (isFormattedDiff()) { - LiquibaseCommand liquibaseCommand = CommandFactory.getInstance().getCommand(COMMANDS.FORMATTED_DIFF); + LiquibaseCommand liquibaseCommand = Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand(COMMANDS.FORMATTED_DIFF); DiffCommand diffCommand = CommandLineUtils.createDiffCommand( createReferenceDatabaseFromCommandParams(commandParams, fileOpener), database, @@ -1522,7 +1522,7 @@ protected void doMigration() throws Exception { diffOutputControl); return; } else if (COMMANDS.SNAPSHOT.equalsIgnoreCase(command)) { - SnapshotCommand snapshotCommand = (SnapshotCommand) CommandFactory.getInstance() + SnapshotCommand snapshotCommand = (SnapshotCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class) .getCommand(COMMANDS.SNAPSHOT); snapshotCommand.setDatabase(database); snapshotCommand.setSchemas(getSchemaParams(database)); @@ -1534,8 +1534,7 @@ protected void doMigration() throws Exception { outputWriter.close(); return; } else if (COMMANDS.EXECUTE_SQL.equalsIgnoreCase(command)) { - ExecuteSqlCommand executeSqlCommand = (ExecuteSqlCommand) CommandFactory.getInstance().getCommand( - COMMANDS.EXECUTE_SQL); + ExecuteSqlCommand executeSqlCommand = (ExecuteSqlCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand(COMMANDS.EXECUTE_SQL); executeSqlCommand.setDatabase(database); executeSqlCommand.setSql(getCommandParam("sql", null)); executeSqlCommand.setSqlFile(getCommandParam("sqlFile", null)); @@ -1546,7 +1545,7 @@ protected void doMigration() throws Exception { outputWriter.close(); return; } else if (COMMANDS.SNAPSHOT_REFERENCE.equalsIgnoreCase(command)) { - SnapshotCommand snapshotCommand = (SnapshotCommand) CommandFactory.getInstance() + SnapshotCommand snapshotCommand = (SnapshotCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class) .getCommand(COMMANDS.SNAPSHOT); Database referenceDatabase = createReferenceDatabaseFromCommandParams(commandParams, fileOpener); snapshotCommand.setDatabase(referenceDatabase); @@ -1701,7 +1700,7 @@ protected void doMigration() throws Exception { } } DropAllCommand dropAllCommand = - (DropAllCommand) CommandFactory.getInstance().getCommand(COMMANDS.DROP_ALL); + (DropAllCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand(COMMANDS.DROP_ALL); if (hubConnectionId != null) { dropAllCommand.setHubConnectionId(hubConnectionId); } @@ -1865,7 +1864,7 @@ protected void doMigration() throws Exception { } else if (COMMANDS.UPDATE_TESTING_ROLLBACK.equalsIgnoreCase(command)) { liquibase.updateTestingRollback(new Contexts(contexts), new LabelExpression(labels)); } else if (COMMANDS.HISTORY.equalsIgnoreCase(command)) { - HistoryCommand historyCommand = (HistoryCommand) CommandFactory.getInstance().getCommand("history"); + HistoryCommand historyCommand = (HistoryCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("history"); historyCommand.setDatabase(database); historyCommand.setOutputStream(new PrintStream(getOutputStream())); historyCommand.execute(); @@ -1958,7 +1957,7 @@ private LiquibaseCommand createLiquibaseCommand(Database database, Liquibase liq if (this.commandParams.contains("--help")) { argsMap.put("help", true); } - LiquibaseCommand liquibaseCommand = CommandFactory.getInstance().getCommand(commandName); + LiquibaseCommand liquibaseCommand = Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand(commandName); AbstractSelfConfiguratingCommand configuratingCommand = (AbstractSelfConfiguratingCommand) liquibaseCommand; configuratingCommand.configure(argsMap); return liquibaseCommand; diff --git a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java index ed7cb726e03..d4d0284d44b 100644 --- a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java @@ -85,7 +85,7 @@ public OldMainTest() throws Exception { // snapshotCommandResult = PowerMockito.mock(SnapshotCommand.SnapshotCommandResult.class); // // // Do not do actual database snapshots. -// when(CommandFactory.getInstance()).thenReturn(commandFactory); +// when(Scope.getCurrentScope().getSingleton(CommandFactory.class)).thenReturn(commandFactory); // when(commandFactory.getCommand("snapshot")).thenReturn(snapshotCommand); // when(snapshotCommand.execute()).thenReturn(snapshotCommandResult); // when(snapshotCommandResult.print()).thenReturn("..."); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java index 7625201260d..e4b5d82c6bc 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java @@ -4,6 +4,7 @@ import liquibase.CatalogAndSchema; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.command.*; import liquibase.command.core.DiffCommand; import liquibase.database.Database; @@ -249,7 +250,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti } else { PrintStream printStream = createPrintStream(); if (isFormattedDiff()) { - LiquibaseCommand liquibaseCommand = CommandFactory.getInstance().getCommand("formattedDiff"); + LiquibaseCommand liquibaseCommand = Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("formattedDiff"); DiffCommand diffCommand = CommandLineUtils.createDiffCommand(referenceDatabase, db, StringUtil.trimToNull(diffTypes), schemaComparisons, objectChangeFilter, printStream); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java index 812a768c921..9342da433a7 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java @@ -1,6 +1,7 @@ package org.liquibase.maven.plugins; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.command.CommandExecutionException; import liquibase.command.CommandFactory; import liquibase.command.CommandResult; @@ -17,7 +18,7 @@ public class LiquibaseHistoryMojo extends AbstractLiquibaseMojo { @Override protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { - HistoryCommand historyCommand = (HistoryCommand) CommandFactory.getInstance().getCommand("history"); + HistoryCommand historyCommand = (HistoryCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("history"); historyCommand.setDatabase(getLiquibase().getDatabase()); try { diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java index d89715909c7..5dd34e457a1 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java @@ -47,7 +47,7 @@ protected void performLiquibaseTask(Liquibase liquibase) super.performLiquibaseTask(liquibase); Database database = liquibase.getDatabase(); RegisterChangeLogCommand registerChangeLog = - (RegisterChangeLogCommand) CommandFactory.getInstance().getCommand("registerChangeLog"); + (RegisterChangeLogCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("registerChangeLog"); registerChangeLog.setChangeLogFile(changeLogFile); registerChangeLog.setHubProjectId(UUID.fromString(hubProjectId)); Map argsMap = new HashMap<>(); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java index 5cebc273c34..a1c8f8d58d9 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java @@ -1,6 +1,7 @@ package org.liquibase.maven.plugins; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.changelog.ChangeLogParameters; import liquibase.command.*; import liquibase.database.Database; @@ -97,7 +98,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti "The command 'rollbackOneChangeSet' requires a Liquibase Pro License, available at http://www.liquibase.org/download or sales@liquibase.com."); } Database database = liquibase.getDatabase(); - LiquibaseCommand liquibaseCommand = (CommandFactory.getInstance().getCommand("rollbackOneChangeSet")); + LiquibaseCommand liquibaseCommand = (Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("rollbackOneChangeSet")); AbstractSelfConfiguratingCommand configuratingCommand = (AbstractSelfConfiguratingCommand)liquibaseCommand; Map argsMap = getCommandArgsObjectMap(liquibase); ChangeLogParameters clp = new ChangeLogParameters(database); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java index 7f6adc151da..e1ab7cf849c 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java @@ -106,7 +106,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti "The command 'rollbackOneChangeSetSQL' requires a Liquibase Pro License, available at http://www.liquibase.org/download or sales@liquibase.com."); } Database database = liquibase.getDatabase(); - LiquibaseCommand liquibaseCommand = (CommandFactory.getInstance().getCommand("rollbackOneChangeSet")); + LiquibaseCommand liquibaseCommand = (Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("rollbackOneChangeSet")); AbstractSelfConfiguratingCommand configuratingCommand = (AbstractSelfConfiguratingCommand)liquibaseCommand; Map argsMap = getCommandArgsObjectMap(liquibase); ChangeLogParameters clp = new ChangeLogParameters(database); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java index 473f03f255f..b53c951d16f 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java @@ -1,6 +1,7 @@ package org.liquibase.maven.plugins; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.changelog.ChangeLogParameters; import liquibase.command.*; import liquibase.database.Database; @@ -63,7 +64,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti "The command 'rollbackOneUpdate' requires a Liquibase Pro License, available at http://www.liquibase.org/download or sales@liquibase.com."); } Database database = liquibase.getDatabase(); - LiquibaseCommand liquibaseCommand = (CommandFactory.getInstance().getCommand("rollbackOneUpdate")); + LiquibaseCommand liquibaseCommand = (Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("rollbackOneUpdate")); AbstractSelfConfiguratingCommand configuratingCommand = (AbstractSelfConfiguratingCommand)liquibaseCommand; Map argsMap = getCommandArgsObjectMap(liquibase); ChangeLogParameters clp = new ChangeLogParameters(database); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java index 4e11c38ad34..193842d7bc2 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java @@ -75,7 +75,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti "The command 'rollbackOneUpdateSQL' requires a Liquibase Pro License, available at http://www.liquibase.org/download or sales@liquibase.com."); } Database database = liquibase.getDatabase(); - LiquibaseCommand liquibaseCommand = (CommandFactory.getInstance().getCommand("rollbackOneUpdate")); + LiquibaseCommand liquibaseCommand = (Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("rollbackOneUpdate")); AbstractSelfConfiguratingCommand configuratingCommand = (AbstractSelfConfiguratingCommand)liquibaseCommand; Map argsMap = getCommandArgsObjectMap(liquibase); Writer outputWriter = null; diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java index c80dcd6fdd1..da19ec60380 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java @@ -3,6 +3,7 @@ import liquibase.Contexts; import liquibase.LabelExpression; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.changelog.ChangeLogParameters; import liquibase.command.*; import liquibase.command.core.SyncHubCommand; @@ -53,7 +54,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { super.performLiquibaseTask(liquibase); Database database = liquibase.getDatabase(); - SyncHubCommand syncHub = (SyncHubCommand) CommandFactory.getInstance().getCommand("syncHub"); + SyncHubCommand syncHub = (SyncHubCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("syncHub"); syncHub.setChangeLogFile(changeLogFile); syncHub.setUrl(database.getConnection().getURL()); syncHub.setHubConnectionId(hubConnectionId); From 1781c92d31c4a633249fcb1c3c7af9fbf310e10e Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Mon, 25 Jan 2021 11:36:12 -0600 Subject: [PATCH 03/17] Moved LiquibaseCommand.execute() method to COmmandFactory --- .../src/main/java/liquibase/Liquibase.java | 5 ++-- .../liquibase/command/AbstractCommand.java | 15 ------------ .../liquibase/command/CommandFactory.java | 16 +++++++++++++ .../liquibase/command/LiquibaseCommand.java | 11 ++++----- .../liquibase/command/core/DiffCommand.java | 2 +- .../command/core/DiffToChangeLogCommand.java | 2 +- .../command/core/DropAllCommand.java | 2 +- .../command/core/ExecuteSqlCommand.java | 2 +- .../core/GenerateChangeLogCommand.java | 2 +- .../command/core/HistoryCommand.java | 2 +- .../core/RegisterChangeLogCommand.java | 2 +- .../command/core/SnapshotCommand.java | 2 +- .../command/core/SyncHubCommand.java | 2 +- .../main/java/liquibase/hub/HubUpdater.java | 2 +- .../commandline/CommandLineUtils.java | 6 ++--- .../integration/commandline/OldMain.java | 24 +++++++++---------- .../src/main/java/liquibase/sdk/Main.java | 4 +++- .../liquibase/sdk/convert/ConvertCommand.java | 2 +- .../maven/plugins/LiquibaseDatabaseDiff.java | 2 +- .../maven/plugins/LiquibaseHistoryMojo.java | 2 +- .../LiquibaseRegisterChangeLogMojo.java | 2 +- .../LiquibaseRollbackOneChangeSetMojo.java | 2 +- .../LiquibaseRollbackOneChangeSetSQL.java | 2 +- .../LiquibaseRollbackOneUpdateMojo.java | 2 +- .../LiquibaseRollbackOneUpdateSQL.java | 2 +- .../maven/plugins/LiquibaseSyncHubMojo.java | 2 +- 26 files changed, 60 insertions(+), 59 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/Liquibase.java b/liquibase-core/src/main/java/liquibase/Liquibase.java index 4f6ab6ea650..0fb0bbd26e6 100644 --- a/liquibase-core/src/main/java/liquibase/Liquibase.java +++ b/liquibase-core/src/main/java/liquibase/Liquibase.java @@ -1689,15 +1689,16 @@ public final void dropAll(CatalogAndSchema... schemas) throws DatabaseException runInScope(new Scope.ScopedRunner() { @Override public void run() throws Exception { + final CommandFactory commandFactory = Scope.getCurrentScope().getSingleton(CommandFactory.class); - DropAllCommand dropAll = (DropAllCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("dropAll"); + DropAllCommand dropAll = (DropAllCommand) commandFactory.getCommand("dropAll"); dropAll.setDatabase(Liquibase.this.getDatabase()); dropAll.setSchemas(finalSchemas); dropAll.setLiquibase(Liquibase.this); dropAll.setChangeLogFile(changeLogFile); try { - dropAll.execute(); + commandFactory.execute(dropAll); } catch (CommandExecutionException e) { throw new DatabaseException(e); } diff --git a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java index 5eb49f3e551..54902574184 100644 --- a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java @@ -16,21 +16,6 @@ public int getPriority(String commandName) { } } - public final T execute() throws CommandExecutionException { - this.validate(); - try { - return this.run(); - } catch (Exception e) { - if (e instanceof CommandExecutionException) { - throw (CommandExecutionException) e; - } else { - throw new CommandExecutionException(e); - } - } - } - - protected abstract T run() throws Exception; - @Override public SortedSet getArguments() { return new TreeSet<>(); diff --git a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java index 527f60945ab..7822c10b67f 100644 --- a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java +++ b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java @@ -20,4 +20,20 @@ protected int getPriority(LiquibaseCommand obj, Object... args) { public LiquibaseCommand getCommand(String commandName) { return getPlugin(commandName); } + + public T execute(LiquibaseCommand command) throws CommandExecutionException { + command.validate(); + try { + return command.run(); + } catch (Exception e) { + if (e instanceof CommandExecutionException) { + throw (CommandExecutionException) e; + } else { + throw new CommandExecutionException(e); + } + } + + } + + } diff --git a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java index af7e2ea6e4b..684185fdbb5 100644 --- a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java @@ -13,14 +13,11 @@ public interface LiquibaseCommand extends Plugin { String getName(); - CommandValidationErrors validate(); - - /** - * Executes the command. Should call {@link #validate()} as part of this method and throw {@link CommandExecutionException} if validation fails or there are any errors executing the command. - */ - T execute() throws CommandExecutionException; - int getPriority(String commandName); SortedSet getArguments(); + + CommandValidationErrors validate(); + + T run() throws Exception; } diff --git a/liquibase-core/src/main/java/liquibase/command/core/DiffCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DiffCommand.java index a765f7f6638..225a9124c40 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DiffCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DiffCommand.java @@ -130,7 +130,7 @@ public DiffCommand setCompareControl(CompareControl compareControl) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { SnapshotCommand.logUnsupportedDatabase(this.getReferenceDatabase(), this.getClass()); DiffResult diffResult = createDiffResult(); diff --git a/liquibase-core/src/main/java/liquibase/command/core/DiffToChangeLogCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DiffToChangeLogCommand.java index 548f1db0d94..b58bba748b6 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DiffToChangeLogCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DiffToChangeLogCommand.java @@ -51,7 +51,7 @@ public DiffToChangeLogCommand setDiffOutputControl(DiffOutputControl diffOutputC } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { SnapshotCommand.logUnsupportedDatabase(this.getReferenceDatabase(), this.getClass()); DiffResult diffResult = createDiffResult(); diff --git a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java index e8e68017152..3d2f35778a6 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java @@ -105,7 +105,7 @@ public void setHubConnectionId(String hubConnectionIdString) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { LockService lockService = LockServiceFactory.getInstance().getLockService(database); Logger log = Scope.getCurrentScope().getLog(getClass()); HubUpdater hubUpdater = null; diff --git a/liquibase-core/src/main/java/liquibase/command/core/ExecuteSqlCommand.java b/liquibase-core/src/main/java/liquibase/command/core/ExecuteSqlCommand.java index 07f6fa414c5..cf9a7b38b04 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/ExecuteSqlCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/ExecuteSqlCommand.java @@ -65,7 +65,7 @@ public CommandValidationErrors validate() { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { Executor executor = Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor("jdbc", database); String sqlText; if (sqlFile == null) { diff --git a/liquibase-core/src/main/java/liquibase/command/core/GenerateChangeLogCommand.java b/liquibase-core/src/main/java/liquibase/command/core/GenerateChangeLogCommand.java index d2f28fac0de..169815e60e0 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/GenerateChangeLogCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/GenerateChangeLogCommand.java @@ -48,7 +48,7 @@ public GenerateChangeLogCommand setContext(String context) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { outputBestPracticeMessage(); String changeLogFile = StringUtil.trimToNull(getChangeLogFile()); diff --git a/liquibase-core/src/main/java/liquibase/command/core/HistoryCommand.java b/liquibase-core/src/main/java/liquibase/command/core/HistoryCommand.java index c5faeccafbd..35bd90859da 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/HistoryCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/HistoryCommand.java @@ -52,7 +52,7 @@ public void setOutputStream(PrintStream outputStream) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { ChangeLogHistoryService historyService = ChangeLogHistoryServiceFactory.getInstance().getChangeLogService(database); outputStream.println("Liquibase History for " + database.getConnection().getURL()); diff --git a/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java b/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java index 5d43bac053e..2b7ffe32488 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java @@ -74,7 +74,7 @@ public void setOutputStream(PrintStream outputStream) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { // // Access the HubService // Stop if we do no have a key diff --git a/liquibase-core/src/main/java/liquibase/command/core/SnapshotCommand.java b/liquibase-core/src/main/java/liquibase/command/core/SnapshotCommand.java index 01d879e5a73..d69f10751b0 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/SnapshotCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/SnapshotCommand.java @@ -94,7 +94,7 @@ public void setSnapshotMetadata(Map snapshotMetadata) { } @Override - protected SnapshotCommandResult run() throws Exception { + public SnapshotCommandResult run() throws Exception { SnapshotCommand.logUnsupportedDatabase(database, this.getClass()); SnapshotControl snapshotControl = new SnapshotControl(database); snapshotControl.setSnapshotListener(snapshotListener); diff --git a/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java b/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java index b68ec0d7f52..218d77d3eb9 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java @@ -86,7 +86,7 @@ public CommandValidationErrors validate() { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { final HubServiceFactory hubServiceFactory = Scope.getCurrentScope().getSingleton(HubServiceFactory.class); if (! hubServiceFactory.isOnline()) { if (failIfOnline) { diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index 18b4f1824f6..50ed898927e 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -228,7 +228,7 @@ public void syncHub(String changeLogFile, Database database, DatabaseChangeLog d try { syncHub.configure(Collections.singletonMap("changeLog", databaseChangeLog)); - final CommandResult commandResult = syncHub.execute(); + final CommandResult commandResult = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(syncHub); if (!commandResult.succeeded) { Scope.getCurrentScope().getLog(getClass()).warning("Liquibase Hub sync failed: " + commandResult.message); } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java index f77729b9e51..db13ae68782 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java @@ -167,7 +167,7 @@ public static void doDiff(Database referenceDatabase, Database targetDatabase, S Scope.getCurrentScope().getUI().sendMessage(""); Scope.getCurrentScope().getUI().sendMessage(coreBundle.getString("diff.results")); try { - diffCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(diffCommand); } catch (CommandExecutionException e) { throw new LiquibaseException(e); } @@ -204,7 +204,7 @@ public static void doDiffToChangeLog(String changeLogFile, .setDiffOutputControl(diffOutputControl); try { - command.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(command); } catch (CommandExecutionException e) { throw new LiquibaseException(e); } @@ -243,7 +243,7 @@ public static void doGenerateChangeLog(String changeLogFile, Database originalDa .setContext(context); try { - command.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(command); } catch (CommandExecutionException e) { throw new LiquibaseException(e); } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java index a1eabea3989..b283451f3a7 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java @@ -1475,7 +1475,7 @@ protected void doMigration() throws Exception { argsMap.put("format", getCommandParam(OPTIONS.FORMAT, "JSON")); argsMap.put("diffCommand", diffCommand); ((AbstractSelfConfiguratingCommand) liquibaseCommand).configure(argsMap); - liquibaseCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); } else { CommandLineUtils.doDiff( createReferenceDatabaseFromCommandParams(commandParams, fileOpener), @@ -1528,7 +1528,7 @@ protected void doMigration() throws Exception { snapshotCommand.setSchemas(getSchemaParams(database)); snapshotCommand.setSerializerFormat(getCommandParam(OPTIONS.SNAPSHOT_FORMAT, null)); Writer outputWriter = getOutputWriter(); - String result = snapshotCommand.execute().print(); + String result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(snapshotCommand).print(); outputWriter.write(result); outputWriter.flush(); outputWriter.close(); @@ -1540,7 +1540,7 @@ protected void doMigration() throws Exception { executeSqlCommand.setSqlFile(getCommandParam("sqlFile", null)); executeSqlCommand.setDelimiter(getCommandParam("delimiter", ";")); Writer outputWriter = getOutputWriter(); - outputWriter.write(executeSqlCommand.execute().print()); + outputWriter.write(Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(executeSqlCommand).print()); outputWriter.flush(); outputWriter.close(); return; @@ -1552,7 +1552,7 @@ protected void doMigration() throws Exception { snapshotCommand.setSchemas(getSchemaParams(database)); snapshotCommand.setSerializerFormat(getCommandParam(OPTIONS.SNAPSHOT_FORMAT, null)); Writer outputWriter = getOutputWriter(); - outputWriter.write(snapshotCommand.execute().print()); + outputWriter.write(Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(snapshotCommand).print()); outputWriter.flush(); outputWriter.close(); @@ -1626,7 +1626,7 @@ protected void doMigration() throws Exception { Map argsMap = new HashMap<>(); loadChangeSetInfoToMap(argsMap); LiquibaseCommand liquibaseCommand = createLiquibaseCommand(database, liquibase, COMMANDS.ROLLBACK_ONE_CHANGE_SET, argsMap); - liquibaseCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); return; } else if (COMMANDS.ROLLBACK_ONE_CHANGE_SET_SQL.equals(command)) { Writer outputWriter = getOutputWriter(); @@ -1635,7 +1635,7 @@ protected void doMigration() throws Exception { argsMap.put("outputWriter", outputWriter); argsMap.put("force", true); LiquibaseCommand liquibaseCommand = createLiquibaseCommand(database, liquibase, COMMANDS.ROLLBACK_ONE_CHANGE_SET, argsMap); - liquibaseCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); outputWriter.flush(); outputWriter.close(); return; @@ -1643,7 +1643,7 @@ protected void doMigration() throws Exception { Map argsMap = new HashMap<>(); argsMap.put("deploymentId", getCommandParam(OPTIONS.DEPLOYMENT_ID, null)); LiquibaseCommand liquibaseCommand = createLiquibaseCommand(database, liquibase, COMMANDS.ROLLBACK_ONE_UPDATE, argsMap); - liquibaseCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); return; } else if (COMMANDS.ROLLBACK_ONE_UPDATE_SQL.equals(command)) { Writer outputWriter = getOutputWriter(); @@ -1652,7 +1652,7 @@ protected void doMigration() throws Exception { argsMap.put("outputWriter", outputWriter); argsMap.put("force", true); LiquibaseCommand liquibaseCommand = createLiquibaseCommand(database, liquibase, COMMANDS.ROLLBACK_ONE_UPDATE, argsMap); - liquibaseCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); outputWriter.flush(); outputWriter.close(); return; @@ -1673,7 +1673,7 @@ protected void doMigration() throws Exception { } catch (IllegalArgumentException e) { throw new LiquibaseException("Unexpected hubProjectId format: "+hubProjectId, e); } - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (result.succeeded) { Scope.getCurrentScope().getUI().sendMessage(result.print()); @@ -1708,7 +1708,7 @@ protected void doMigration() throws Exception { dropAllCommand.setDatabase(liquibase.getDatabase()); dropAllCommand.setSchemas(getSchemaParams(database)); dropAllCommand.setChangeLogFile(changeLogFile); - Scope.getCurrentScope().getUI().sendMessage(dropAllCommand.execute().print()); + Scope.getCurrentScope().getUI().sendMessage(Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(dropAllCommand).print()); return; } else if (COMMANDS.STATUS.equalsIgnoreCase(command)) { boolean runVerbose = false; @@ -1867,7 +1867,7 @@ protected void doMigration() throws Exception { HistoryCommand historyCommand = (HistoryCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("history"); historyCommand.setDatabase(database); historyCommand.setOutputStream(new PrintStream(getOutputStream())); - historyCommand.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(historyCommand); } else { throw new CommandLineParsingException( String.format(coreBundle.getString("command.unknown"), command)); @@ -1897,7 +1897,7 @@ private void executeSyncHub(Database database, Liquibase liquibase) throws Comma liquibaseCommand.setDatabase(database); liquibaseCommand.setChangeLogFile(changeLogFile); liquibaseCommand.setHubProjectId(hubProjectId); - final CommandResult commandResult = liquibaseCommand.execute(); + final CommandResult commandResult = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (commandResult.succeeded) { Scope.getCurrentScope().getUI().sendMessage(commandResult.print()); } else { diff --git a/liquibase-core/src/main/java/liquibase/sdk/Main.java b/liquibase-core/src/main/java/liquibase/sdk/Main.java index 350b2eef7fc..56e71ef5fbd 100644 --- a/liquibase-core/src/main/java/liquibase/sdk/Main.java +++ b/liquibase-core/src/main/java/liquibase/sdk/Main.java @@ -1,5 +1,7 @@ package liquibase.sdk; +import liquibase.Scope; +import liquibase.command.CommandFactory; import liquibase.command.LiquibaseCommand; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.sdk.convert.ConvertCommand; @@ -59,7 +61,7 @@ public static void main(String[] args) { throw new UserError("Unknown command: "+main.command); } - command.execute(); + Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(command); main.divider(); main.out("Command executed successfully"); diff --git a/liquibase-core/src/main/java/liquibase/sdk/convert/ConvertCommand.java b/liquibase-core/src/main/java/liquibase/sdk/convert/ConvertCommand.java index 7c3b64caea0..0b4bdc87c67 100644 --- a/liquibase-core/src/main/java/liquibase/sdk/convert/ConvertCommand.java +++ b/liquibase-core/src/main/java/liquibase/sdk/convert/ConvertCommand.java @@ -55,7 +55,7 @@ public void setClasspath(String classpath) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { List openers = new ArrayList<>(); openers.add(new FileSystemResourceAccessor()); openers.add(new ClassLoaderResourceAccessor()); diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java index e4b5d82c6bc..555157a70d3 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDatabaseDiff.java @@ -259,7 +259,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti argsMap.put("diffCommand", diffCommand); ((AbstractSelfConfiguratingCommand) liquibaseCommand).configure(argsMap); try { - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (!result.succeeded) { throw new LiquibaseException(result.message); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java index 9342da433a7..4fe1eec0187 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseHistoryMojo.java @@ -22,7 +22,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti historyCommand.setDatabase(getLiquibase().getDatabase()); try { - CommandResult result = historyCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(historyCommand); if (!result.succeeded) { throw new LiquibaseException(result.message); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java index 5dd34e457a1..9421bee0466 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRegisterChangeLogMojo.java @@ -57,7 +57,7 @@ protected void performLiquibaseTask(Liquibase liquibase) argsMap.put("changeLog", liquibase.getDatabaseChangeLog()); registerChangeLog.configure(argsMap); try { - CommandResult result = registerChangeLog.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(registerChangeLog); if (result.succeeded) { Scope.getCurrentScope().getUI().sendMessage(result.print()); } else { diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java index a1c8f8d58d9..d4de3843cf8 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetMojo.java @@ -110,7 +110,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti argsMap.put("liquibase", liquibase); configuratingCommand.configure(argsMap); try { - final CommandResult execute = liquibaseCommand.execute(); + final CommandResult execute = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (!execute.succeeded) { throw new LiquibaseException(execute.message); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java index e1ab7cf849c..6e9122fc347 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java @@ -122,7 +122,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti argsMap.put("liquibase", liquibase); configuratingCommand.configure(argsMap); try { - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (!result.succeeded) { throw new LiquibaseException(result.message); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java index b53c951d16f..504f4aff699 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateMojo.java @@ -76,7 +76,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti argsMap.put("liquibase", liquibase); configuratingCommand.configure(argsMap); try { - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (!result.succeeded) { throw new LiquibaseException(result.message); } } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java index 193842d7bc2..a78b0f52a69 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java @@ -95,7 +95,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti argsMap.put("liquibase", liquibase); configuratingCommand.configure(argsMap); try { - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); if (!result.succeeded) { throw new LiquibaseException(result.message); } } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java index da19ec60380..a3de70db402 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseSyncHubMojo.java @@ -62,7 +62,7 @@ protected void performLiquibaseTask(Liquibase liquibase) syncHub.setDatabase(database); syncHub.setFailIfOnline(false); try { - CommandResult result = syncHub.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(syncHub); if (!result.succeeded) { throw new LiquibaseException(result.message); } From c21864b697f3e0c9447b043d07cddd9fa3a3b321 Mon Sep 17 00:00:00 2001 From: Nathan Voxland Date: Thu, 28 Jan 2021 16:34:00 -0600 Subject: [PATCH 04/17] Refactoring LiquibaseConfiguration system --- .../integration/cdi/CDILiquibase.java | 7 +- .../integration/commandline/Main.java | 11 + .../java/liquibase/GlobalConfiguration.java | 139 ++++++++ .../src/main/java/liquibase/Scope.java | 14 +- .../src/main/java/liquibase/ScopeManager.java | 1 - .../liquibase/change/AbstractSQLChange.java | 11 +- .../change/core/CreateProcedureChange.java | 7 +- .../change/core/CreateViewChange.java | 5 +- .../core/ExecuteShellCommandChange.java | 10 +- .../changelog/ChangeLogParameters.java | 5 +- .../OfflineChangeLogHistoryService.java | 19 +- .../command/core/DropAllCommand.java | 12 +- .../core/RegisterChangeLogCommand.java | 10 +- .../AbstractConfigurationContainer.java | 161 ---------- .../AutoloadedConfigurations.java | 5 + .../configuration/ConfigurationContainer.java | 17 - .../ConfigurationDefinition.java | 163 ++++++++++ .../configuration/ConfigurationProperty.java | 207 ------------ .../ConfigurationValueHandler.java | 7 +- .../ConfigurationValueObfuscator.java | 6 + .../ConfigurationValueProvider.java | 14 +- .../configuration/CurrentValueDetails.java | 19 ++ .../configuration/GlobalConfiguration.java | 296 ------------------ .../configuration/HubConfiguration.java | 88 ------ .../configuration/LiquibaseConfiguration.java | 177 +++-------- .../core/EnvironmentVariableProvider.java | 72 +++++ .../{ => core}/SystemPropertyProvider.java | 20 +- .../database/AbstractJdbcDatabase.java | 20 +- .../database/core/MSSQLDatabase.java | 4 +- .../liquibase/datatype/core/ClobType.java | 7 +- .../datatype/core/TimestampType.java | 7 +- .../java/liquibase/dbdoc/ChangeLogWriter.java | 5 +- .../java/liquibase/dbdoc/HTMLListWriter.java | 5 +- .../main/java/liquibase/dbdoc/HTMLWriter.java | 5 +- .../diff/compare/core/CatalogComparator.java | 4 +- .../diff/compare/core/ColumnComparator.java | 5 +- .../diff/compare/core/SchemaComparator.java | 5 +- .../output/changelog/DiffToChangeLog.java | 23 +- .../core/MissingDataChangeGenerator.java | 7 +- ...issingDataExternalFileChangeGenerator.java | 10 +- .../exception/UnknownConfigurationType.java | 15 + .../java/liquibase/hub/HubConfiguration.java | 44 +++ .../java/liquibase/hub/core/HttpClient.java | 18 +- .../liquibase/hub/core/OnlineHubService.java | 14 +- .../hub/listener/HubChangeExecListener.java | 15 +- .../integration/ant/BaseLiquibaseTask.java | 12 +- .../integration/commandline/OldMain.java | 47 ++- .../servlet/LiquibaseServletListener.java | 30 +- .../integration/spring/SpringLiquibase.java | 16 +- .../lockservice/StandardLockService.java | 9 +- .../logging/core/AbstractLogger.java | 11 +- .../logging/core/DefaultLogMessageFilter.java | 11 +- .../core/DefaultLoggerConfiguration.java | 51 +-- .../parser/ChangeLogParserCofiguration.java | 45 --- .../parser/ChangeLogParserConfiguration.java | 28 ++ .../parser/core/yaml/YamlSnapshotParser.java | 5 +- .../sdk/resource/MockResourceAccessor.java | 5 +- .../supplier/resource/ResourceSupplier.java | 6 +- .../FormattedSqlChangeLogSerializer.java | 5 +- .../core/json/JsonChangeLogSerializer.java | 5 +- .../core/string/StringSnapshotSerializer.java | 5 +- .../StringSnapshotSerializerReadable.java | 5 +- .../core/xml/XMLChangeLogSerializer.java | 5 +- .../core/yaml/YamlChangeLogSerializer.java | 5 +- .../core/yaml/YamlSnapshotSerializer.java | 5 +- .../StandardServiceLocator.java | 1 + .../liquibase/snapshot/DatabaseSnapshot.java | 5 +- .../core/CreateProcedureGenerator.java | 12 +- .../core/ReorganizeTableGeneratorDB2.java | 5 +- .../structure/AbstractDatabaseObject.java | 4 +- .../java/liquibase/structure/core/Data.java | 5 +- .../java/liquibase/ui/ConsoleUIService.java | 9 +- .../main/java/liquibase/util/FileUtil.java | 6 +- .../src/main/java/liquibase/util/MD5Util.java | 5 +- .../main/java/liquibase/util/StreamUtil.java | 5 +- .../liquibase/util/xml/DefaultXmlWriter.java | 7 +- ...ase.configuration.AutoloadedConfigurations | 4 + ...e.configuration.ConfigurationValueProvider | 2 + .../command/core/DropAllCommandTest.groovy | 2 +- .../core/RegisterChangeLogCommandTest.groovy | 2 +- .../configuration/HubConfigurationTest.groovy | 2 +- .../EnvironmentVariableProviderTest.groovy | 51 +++ .../hub/core/OnlineHubServiceTest.groovy | 2 +- .../core/CreateProcedureGeneratorTest.groovy | 5 +- .../changelog/ExpressionExpanderTest.java | 81 ++--- .../liquibase/configuration/ContextTest.java | 63 ---- .../LiquibaseConfigurationTest.java | 20 -- .../java/liquibase/datatype/ClobTypeTest.java | 105 +++---- .../integration/ant/AbstractAntTaskTest.java | 7 +- .../integration/commandline/OldMainTest.java | 20 +- .../liquibase/hub/OnlineHubServiceTest.groovy | 1 - .../dbtest/AbstractIntegrationTest.java | 11 +- .../AbstractLiquibaseChangeLogMojo.java | 25 +- .../maven/plugins/AbstractLiquibaseMojo.java | 9 +- .../maven/plugins/LiquibaseDropAll.java | 9 +- .../LiquibaseGenerateChangeLogMojo.java | 19 +- .../plugins/LiquibaseReportStatusMojo.java | 5 +- .../LiquibaseRollbackOneChangeSetSQL.java | 6 +- .../LiquibaseRollbackOneUpdateSQL.java | 6 +- 99 files changed, 980 insertions(+), 1568 deletions(-) create mode 100644 liquibase-core/src/main/java/liquibase/GlobalConfiguration.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/HubConfiguration.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java rename liquibase-core/src/main/java/liquibase/configuration/{ => core}/SystemPropertyProvider.java (61%) create mode 100644 liquibase-core/src/main/java/liquibase/exception/UnknownConfigurationType.java create mode 100644 liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java delete mode 100644 liquibase-core/src/main/java/liquibase/parser/ChangeLogParserCofiguration.java create mode 100644 liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java create mode 100644 liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations create mode 100644 liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy delete mode 100644 liquibase-core/src/test/java/liquibase/configuration/ContextTest.java delete mode 100644 liquibase-core/src/test/java/liquibase/configuration/LiquibaseConfigurationTest.java diff --git a/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java b/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java index 6daaaed69d7..9f8e9c3e33d 100644 --- a/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java +++ b/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java @@ -4,7 +4,7 @@ import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; +import liquibase.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; @@ -108,11 +108,10 @@ public void onStartup() { } LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); - if (!liquibaseConfiguration.getConfiguration(GlobalConfiguration.class).getShouldRun()) { + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { log.info(String.format("Liquibase did not run on %s because %s was set to false.", hostName, - liquibaseConfiguration.describeValueLookupLogic( - GlobalConfiguration.class, GlobalConfiguration.SHOULD_RUN) + GlobalConfiguration.SHOULD_RUN.getProperty() )); return; } diff --git a/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java index 2dbdd710622..95f421f3f20 100644 --- a/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java @@ -1,7 +1,18 @@ package liquibase.integration.commandline; +import liquibase.Scope; +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.LiquibaseConfiguration; + +import java.util.SortedSet; + public class Main { public static void main(String[] args) { System.out.println("New CLI!"); + + final SortedSet definitions = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getDefinitions(); + for (ConfigurationDefinition def : definitions) { + System.out.println("See " + def.getProperty() + " = " + def.getCurrentValue() + " -- " + def.getDescription()); + } } } diff --git a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java new file mode 100644 index 00000000000..e8c865c0c50 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java @@ -0,0 +1,139 @@ +package liquibase; + +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.AutoloadedConfigurations; + +/** + * Configuration container for global properties. + */ +public class GlobalConfiguration implements AutoloadedConfigurations { + + public static final ConfigurationDefinition SHOULD_RUN; + public static final ConfigurationDefinition DATABASECHANGELOG_TABLE_NAME; + public static final ConfigurationDefinition DATABASECHANGELOGLOCK_TABLE_NAME; + public static final ConfigurationDefinition LIQUIBASE_TABLESPACE_NAME; + public static final ConfigurationDefinition LIQUIBASE_CATALOG_NAME; + public static final ConfigurationDefinition LIQUIBASE_SCHEMA_NAME; + public static final ConfigurationDefinition OUTPUT_LINE_SEPARATOR; + public static final ConfigurationDefinition OUTPUT_ENCODING; + public static final ConfigurationDefinition CHANGELOGLOCK_WAIT_TIME; + public static final ConfigurationDefinition CHANGELOGLOCK_POLL_RATE; + public static final ConfigurationDefinition CONVERT_DATA_TYPES; + public static final ConfigurationDefinition GENERATE_CHANGESET_CREATED_VALUES; + public static final ConfigurationDefinition AUTO_REORG; + public static final ConfigurationDefinition DIFF_COLUMN_ORDER; + public static final ConfigurationDefinition ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA; + public static final ConfigurationDefinition GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION; + public static final ConfigurationDefinition INCLUDE_CATALOG_IN_SPECIFICATION; + public static final ConfigurationDefinition SHOULD_SNAPSHOT_DATA; + public static final ConfigurationDefinition FILTER_LOG_MESSAGES; + public static final ConfigurationDefinition HEADLESS; + + static { + ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase"); + + SHOULD_RUN = builder.define("shouldRun", Boolean.class) + .setDescription("Should Liquibase commands execute") + .setDefaultValue(true) + .addAlias("should.run") + .build(); + + DATABASECHANGELOG_TABLE_NAME = builder.define("databaseChangeLogTableName", String.class) + .setDescription("Name of table to use for tracking change history") + .setDefaultValue("DATABASECHANGELOG") + .build(); + + DATABASECHANGELOGLOCK_TABLE_NAME = builder.define("databaseChangeLogLockTableName", String.class) + .setDescription("Name of table to use for tracking concurrent Liquibase usage") + .setDefaultValue("DATABASECHANGELOGLOCK") + .build(); + + CHANGELOGLOCK_WAIT_TIME = builder.define("changeLogLockWaitTimeInMinutes", Long.class) + .setDescription("Number of minutes to wait for the changelog lock to be available before giving up") + .setDefaultValue(5L) + .build(); + + CHANGELOGLOCK_POLL_RATE = builder.define("changeLogLockPollRate", Long.class) + .setDescription("Number of seconds wait between checks to the changelog lock when it is locked") + .setDefaultValue(10L) + .build(); + + LIQUIBASE_TABLESPACE_NAME = builder.define("tablespaceName", String.class) + .setDescription("Tablespace to use for Liquibase objects") + .build(); + + LIQUIBASE_CATALOG_NAME = builder.define("catalogName", String.class) + .setDescription("Catalog to use for Liquibase objects") + .build(); + + LIQUIBASE_SCHEMA_NAME = builder.define("schemaName", String.class) + .setDescription("Schema to use for Liquibase objects") + .build(); + + OUTPUT_LINE_SEPARATOR = builder.define("outputLineSeparator", String.class) + .setDescription("Line separator for output. Defaults to OS default") + .setDefaultValue(System.getProperty("line.separator")) + .build(); + + OUTPUT_ENCODING = builder.define("outputFileEncoding", String.class) + .setDescription("Encoding to output text in. Defaults to file.encoding system property or UTF-8") + .setDefaultValue("UTF-8") + .addAlias("file.encoding") + .setCommonlyUsed(true) + .build(); + + CONVERT_DATA_TYPES = builder.define("convertDataTypes", Boolean.class) + .setDescription("Should Liquibase convert to/from STANDARD data types. Applies to both snapshot and " + + "update commands.") + .setDefaultValue(true) + .build(); + + GENERATE_CHANGESET_CREATED_VALUES = builder.define("generateChangeSetCreatedValues", Boolean.class) + .setDescription("Should Liquibase include a 'created' attribute in diff/generateChangeLog changeSets with" + + " the current datetime") + .setDefaultValue(false) + .build(); + + AUTO_REORG = builder.define("autoReorg", Boolean.class) + .setDescription("Should Liquibase automatically include REORG TABLE commands when needed?") + .setDefaultValue(true) + .build(); + + DIFF_COLUMN_ORDER = builder.define("diffColumnOrder", Boolean.class) + .setDescription("Should Liquibase compare column order in diff operation?") + .setDefaultValue(true) + .build(); + + ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA = builder.define("alwaysOverrideStoredLogicSchema", Boolean.class) + .setDescription("When generating SQL for createProcedure, should the procedure schema be forced to the default schema if no schemaName attribute is set?") + .setDefaultValue(false) + .build(); + + + GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION = builder.define("generatedChangeSetIdsContainsDescription", Boolean.class) + .setDescription("Should Liquibase include the change description in the id when generating changeSets?") + .setDefaultValue(false) + .build(); + + INCLUDE_CATALOG_IN_SPECIFICATION = builder.define("includeCatalogInSpecification", Boolean.class) + .setDescription("Should Liquibase include the catalog name when determining equality?") + .setDefaultValue(false) + .build(); + + SHOULD_SNAPSHOT_DATA = builder.define("shouldSnapshotData", Boolean.class) + .setDescription("Should Liquibase snapshot data by default?") + .setDefaultValue(false) + .build(); + + FILTER_LOG_MESSAGES = builder.define("filterLogMessages", Boolean.class) + .setDescription("Should Liquibase filter log messages for potentially insecure data?") + .setDefaultValue(true) + .build(); + + HEADLESS = builder.define("headless", Boolean.class) + .setDescription("Force liquibase think it has no access to a keyboard?") + .setDefaultValue(false) + .setCommonlyUsed(true) + .build(); + } +} diff --git a/liquibase-core/src/main/java/liquibase/Scope.java b/liquibase-core/src/main/java/liquibase/Scope.java index 1190605bc06..df3bf6ccc1b 100644 --- a/liquibase-core/src/main/java/liquibase/Scope.java +++ b/liquibase-core/src/main/java/liquibase/Scope.java @@ -1,5 +1,6 @@ package liquibase; +import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.OfflineConnection; @@ -38,6 +39,7 @@ public class Scope { public enum Attr { logService, ui, + configuration, resourceAccessor, classLoader, database, @@ -66,6 +68,14 @@ public static Scope getCurrentScope() { Scope rootScope = new Scope(); scopeManager.setCurrentScope(rootScope); + rootScope.values.put(LiquibaseConfiguration.class.getName(), new LiquibaseConfiguration()); + rootScope.values.put(Attr.logService.name(), new JavaLogService()); + rootScope.values.put(Attr.resourceAccessor.name(), new ClassLoaderResourceAccessor()); + rootScope.values.put(Attr.serviceLocator.name(), new StandardServiceLocator()); + + rootScope.values.put(Attr.ui.name(), new ConsoleUIService()); + rootScope.get(LiquibaseConfiguration.class.getName(), LiquibaseConfiguration.class).init(rootScope); + LogService overrideLogService = rootScope.getSingleton(LogServiceFactory.class).getDefaultLogService(); if (overrideLogService == null) { throw new UnexpectedLiquibaseException("Cannot find default log service"); @@ -109,10 +119,6 @@ public static void setScopeManager(ScopeManager scopeManager) { * Defaults serviceLocator to {@link StandardServiceLocator} */ private Scope() { - values.put(Attr.logService.name(), new JavaLogService()); - values.put(Attr.resourceAccessor.name(), new ClassLoaderResourceAccessor()); - values.put(Attr.serviceLocator.name(), new StandardServiceLocator()); - values.put(Attr.ui.name(), new ConsoleUIService()); } protected Scope(Scope parent, Map scopeValues) { diff --git a/liquibase-core/src/main/java/liquibase/ScopeManager.java b/liquibase-core/src/main/java/liquibase/ScopeManager.java index af9e7b87252..c497ca8969c 100644 --- a/liquibase-core/src/main/java/liquibase/ScopeManager.java +++ b/liquibase-core/src/main/java/liquibase/ScopeManager.java @@ -2,7 +2,6 @@ public abstract class ScopeManager { - public abstract Scope getCurrentScope(); protected abstract void setCurrentScope(Scope scope); diff --git a/liquibase-core/src/main/java/liquibase/change/AbstractSQLChange.java b/liquibase-core/src/main/java/liquibase/change/AbstractSQLChange.java index 82c63b2d200..9cf405f8b72 100644 --- a/liquibase-core/src/main/java/liquibase/change/AbstractSQLChange.java +++ b/liquibase-core/src/main/java/liquibase/change/AbstractSQLChange.java @@ -2,8 +2,7 @@ import liquibase.change.core.RawSQLChange; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.MSSQLDatabase; import liquibase.database.core.PostgresDatabase; @@ -194,11 +193,7 @@ public CheckSum generateCheckSum() { } if (sql != null) { - stream = new ByteArrayInputStream( - sql.getBytes( - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getOutputEncoding() - ) + stream = new ByteArrayInputStream(sql.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()) ); } @@ -295,7 +290,7 @@ public static class NormalizingStream extends InputStream { public NormalizingStream(String endDelimiter, Boolean splitStatements, Boolean stripComments, InputStream stream) { this.stream = new PushbackInputStream(stream, 2048); try { - this.headerStream = new ByteArrayInputStream((endDelimiter+":"+splitStatements+":"+stripComments+":").getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + this.headerStream = new ByteArrayInputStream((endDelimiter+":"+splitStatements+":"+stripComments+":").getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } catch (UnsupportedEncodingException e) { throw new UnexpectedLiquibaseException(e); } diff --git a/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java b/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java index 0dec8574a2a..5e99f161830 100644 --- a/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java +++ b/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java @@ -3,9 +3,7 @@ import liquibase.Scope; import liquibase.change.*; import liquibase.changelog.ChangeLogParameters; -import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseList; import liquibase.database.core.*; @@ -251,8 +249,7 @@ public CheckSum generateCheckSum() { procedureText = ""; } - String encoding = - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); if (procedureText != null) { try { stream = new ByteArrayInputStream(procedureText.getBytes(encoding)); diff --git a/liquibase-core/src/main/java/liquibase/change/core/CreateViewChange.java b/liquibase-core/src/main/java/liquibase/change/core/CreateViewChange.java index 907ec808e7d..3f9309962d1 100644 --- a/liquibase-core/src/main/java/liquibase/change/core/CreateViewChange.java +++ b/liquibase-core/src/main/java/liquibase/change/core/CreateViewChange.java @@ -3,8 +3,7 @@ import liquibase.Scope; import liquibase.change.*; import liquibase.changelog.ChangeLogParameters; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.OracleDatabase; import liquibase.database.core.SQLiteDatabase; @@ -199,7 +198,7 @@ public CheckSum generateCheckSum() { selectQuery = ""; } - String encoding = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); if (selectQuery != null) { try { stream = new ByteArrayInputStream(selectQuery.getBytes(encoding)); diff --git a/liquibase-core/src/main/java/liquibase/change/core/ExecuteShellCommandChange.java b/liquibase-core/src/main/java/liquibase/change/core/ExecuteShellCommandChange.java index 4c78cb6f7b2..6b09985df8a 100644 --- a/liquibase-core/src/main/java/liquibase/change/core/ExecuteShellCommandChange.java +++ b/liquibase-core/src/main/java/liquibase/change/core/ExecuteShellCommandChange.java @@ -5,8 +5,7 @@ import liquibase.change.ChangeMetaData; import liquibase.change.DatabaseChange; import liquibase.change.DatabaseChangeProperty; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.exception.ValidationErrors; @@ -25,7 +24,6 @@ import java.io.*; import java.util.*; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; @@ -216,10 +214,8 @@ protected void executeCommand(Database database) throws Exception { Thread.currentThread().interrupt(); } - String errorStreamOut = errorStream.toString(LiquibaseConfiguration.getInstance().getConfiguration - (GlobalConfiguration.class).getOutputEncoding()); - String infoStreamOut = inputStream.toString(LiquibaseConfiguration.getInstance().getConfiguration - (GlobalConfiguration.class).getOutputEncoding()); + String errorStreamOut = errorStream.toString(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); + String infoStreamOut = inputStream.toString(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); if (errorStreamOut != null && !errorStreamOut.isEmpty()) { Scope.getCurrentScope().getLog(getClass()).severe(errorStreamOut); diff --git a/liquibase-core/src/main/java/liquibase/changelog/ChangeLogParameters.java b/liquibase-core/src/main/java/liquibase/changelog/ChangeLogParameters.java index 43923be15fa..32b18c14b5c 100644 --- a/liquibase-core/src/main/java/liquibase/changelog/ChangeLogParameters.java +++ b/liquibase-core/src/main/java/liquibase/changelog/ChangeLogParameters.java @@ -8,7 +8,7 @@ import liquibase.database.Database; import liquibase.database.DatabaseList; import liquibase.exception.DatabaseException; -import liquibase.parser.ChangeLogParserCofiguration; +import liquibase.parser.ChangeLogParserConfiguration; import liquibase.util.StringUtil; import java.util.*; @@ -210,8 +210,7 @@ protected static class ExpressionExpander { public ExpressionExpander(ChangeLogParameters changeLogParameters) { this.changeLogParameters = changeLogParameters; - this.enableEscaping = LiquibaseConfiguration.getInstance() - .getConfiguration(ChangeLogParserCofiguration.class).getSupportPropertyEscaping(); + this.enableEscaping = ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getCurrentValue(); } public String expandExpressions(String text, DatabaseChangeLog changeLog) { diff --git a/liquibase-core/src/main/java/liquibase/changelog/OfflineChangeLogHistoryService.java b/liquibase-core/src/main/java/liquibase/changelog/OfflineChangeLogHistoryService.java index a895d5bc110..719098d51e7 100644 --- a/liquibase-core/src/main/java/liquibase/changelog/OfflineChangeLogHistoryService.java +++ b/liquibase-core/src/main/java/liquibase/changelog/OfflineChangeLogHistoryService.java @@ -5,8 +5,7 @@ import liquibase.Scope; import liquibase.change.CheckSum; import liquibase.changelog.ChangeSet.ExecType; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.OfflineConnection; import liquibase.exception.DatabaseException; @@ -18,7 +17,6 @@ import liquibase.statement.core.MarkChangeSetRanStatement; import liquibase.statement.core.RemoveChangeSetRanStatusStatement; import liquibase.statement.core.UpdateChangeSetChecksumStatement; -import liquibase.structure.core.Column; import liquibase.util.ISODateFormat; import liquibase.util.LiquibaseUtil; import liquibase.util.csv.CSVReader; @@ -26,7 +24,6 @@ import java.io.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; @@ -122,7 +119,7 @@ public void init() throws DatabaseException { protected void writeHeader(File file) throws IOException { try (FileOutputStream outputStream = new FileOutputStream(file); Writer writer = new OutputStreamWriter(outputStream, - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()) + GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()) ) { CSVWriter csvWriter = new CSVWriter(writer); String[] columns = new String[Columns.values().length]; @@ -151,7 +148,7 @@ public String[] execute(String[] line) { @Override public List getRanChangeSets() throws DatabaseException { try ( - Reader reader = new InputStreamReader(new FileInputStream(this.changeLogFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + Reader reader = new InputStreamReader(new FileInputStream(this.changeLogFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); ) { CSVReader csvReader = new CSVReader(reader); @@ -207,8 +204,8 @@ protected void replaceChangeSet(ChangeSet changeSet, ReplaceChangeSetLogic repla File newFile = new File(oldFile.getParentFile(), oldFile.getName()+".new"); try ( - Reader reader = new InputStreamReader(new FileInputStream(oldFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); - Writer writer = new OutputStreamWriter(new FileOutputStream(newFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + Reader reader = new InputStreamReader(new FileInputStream(oldFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); + Writer writer = new OutputStreamWriter(new FileOutputStream(newFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); CSVReader csvReader = new CSVReader(reader); CSVWriter csvWriter = new CSVWriter(writer); ) @@ -235,8 +232,8 @@ protected void appendChangeSet(ChangeSet changeSet, ChangeSet.ExecType execType) File newFile = new File(oldFile.getParentFile(), oldFile.getName()+".new"); try ( - Reader reader = new InputStreamReader(new FileInputStream(oldFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); - Writer writer = new OutputStreamWriter(new FileOutputStream(newFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + Reader reader = new InputStreamReader(new FileInputStream(oldFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); + Writer writer = new OutputStreamWriter(new FileOutputStream(newFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); CSVReader csvReader = new CSVReader(reader); CSVWriter csvWriter = new CSVWriter(writer); ) @@ -319,7 +316,7 @@ public int getNextSequenceValue() throws LiquibaseException { lastChangeSetSequenceValue = 0; try ( - Reader reader = new InputStreamReader(new FileInputStream(this.changeLogFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + Reader reader = new InputStreamReader(new FileInputStream(this.changeLogFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); ) { diff --git a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java index 3d2f35778a6..468c367a99e 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java @@ -7,8 +7,7 @@ import liquibase.command.AbstractCommand; import liquibase.command.CommandResult; import liquibase.command.CommandValidationErrors; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.database.Database; import liquibase.exception.DatabaseException; import liquibase.exception.LiquibaseException; @@ -17,14 +16,10 @@ import liquibase.hub.HubServiceFactory; import liquibase.hub.HubUpdater; import liquibase.hub.LiquibaseHubException; -import liquibase.hub.model.Connection; import liquibase.hub.model.HubChangeLog; -import liquibase.hub.model.Operation; import liquibase.lockservice.LockService; import liquibase.lockservice.LockServiceFactory; import liquibase.logging.Logger; -import liquibase.logging.core.BufferedLogService; -import liquibase.logging.core.CompositeLogService; import liquibase.util.StringUtil; import java.util.ArrayList; @@ -143,9 +138,8 @@ public CommandResult run() throws Exception { private boolean checkForRegisteredChangeLog(DatabaseChangeLog changeLog) throws LiquibaseHubException { Logger log = Scope.getCurrentScope().getLog(getClass()); - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String apiKey = StringUtil.trimToNull(hubConfiguration.getLiquibaseHubApiKey()); - String hubMode = StringUtil.trimToNull(hubConfiguration.getLiquibaseHubMode()); + String apiKey = StringUtil.trimToNull(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()); + String hubMode = StringUtil.trimToNull(HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue()); String changeLogId = changeLog.getChangeLogId(); final HubServiceFactory hubServiceFactory = Scope.getCurrentScope().getSingleton(HubServiceFactory.class); if (apiKey == null || hubMode.equals("off") || ! hubServiceFactory.isOnline()) { diff --git a/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java b/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java index 2b7ffe32488..8d30ae22110 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/RegisterChangeLogCommand.java @@ -5,9 +5,8 @@ import liquibase.command.AbstractSelfConfiguratingCommand; import liquibase.command.CommandResult; import liquibase.command.CommandValidationErrors; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.exception.CommandLineParsingException; import liquibase.exception.LiquibaseException; import liquibase.hub.HubService; @@ -178,7 +177,7 @@ public CommandResult run() throws Exception { list = resourceAccessor.openStreams("", changeLogFile); List uris = list.getURIs(); InputStream is = list.iterator().next(); - String encoding = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); String changeLogString = StreamUtil.readStreamAsString(is, encoding); if (changeLogFile.toLowerCase().endsWith(".xml")) { String patternString = "(?ms).*]*>"; @@ -265,8 +264,7 @@ public int compare(Project o1, Project o2) { private String readProjectNameFromConsole() throws CommandLineParsingException { final UIService ui = Scope.getCurrentScope().getUI(); - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String hubUrl = hubConfiguration.getLiquibaseHubUrl(); + String hubUrl = HubConfiguration.LIQUIBASE_HUB_URL.getCurrentValue(); String input = ui.prompt("Please enter your Project name and press [enter]. This is editable in your Liquibase Hub account at " + hubUrl, null, null, String.class); return StringUtil.trimToEmpty(input); } diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java deleted file mode 100644 index 4e52cd9a8c5..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java +++ /dev/null @@ -1,161 +0,0 @@ -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. - *

- * AbstractConfigurationContainer implementations contain a "namespace" which can be used as the prefix to system properties or cases where there may be name conflicts. - *

- * 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 getProperties() { - return new HashSet<>(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 getValue(String propertyName, Class 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); - } - - @Override - public String getNamespace() { - return getContainer().getNamespace(); - } - - /** - * 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 properties = new HashMap<>(); - - protected ConfigurationContainer(String namespace) { - this.namespace = namespace; - } - - public String getNamespace() { - return 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) { - return property; - } - - // - // Not matching with the actual key then try case insensitive - // - for (Map.Entry entry : properties.entrySet()) { - if (entry.getKey().equalsIgnoreCase(propertyName)) { - return entry.getValue(); - } - } - - // - // No match so throw the exception - // - throw new UnexpectedLiquibaseException("Unknown property on "+getClass().getName()+": "+propertyName); - } - - /** - * Returns the value for the given property. If the property was not defined, an exception is thrown. - */ - public T getValue(String propertyName, Class 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 = getProperty(propertyName); // properties.get(propertyName); - - if (property == null) { - throw new UnexpectedLiquibaseException("Unknown property on "+getClass().getName()+": "+propertyName); - } - - property.setValue(value); - - } - } - -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java b/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java new file mode 100644 index 00000000000..cbc61900eb4 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java @@ -0,0 +1,5 @@ +package liquibase.configuration; + +public interface AutoloadedConfigurations { + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java deleted file mode 100644 index 3cc529f6f5d..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java +++ /dev/null @@ -1,17 +0,0 @@ -package liquibase.configuration; - -import java.util.Set; - -public interface ConfigurationContainer { - ConfigurationProperty getProperty(String propertyName); - - Set getProperties(); - - T getValue(String propertyName, Class returnType); - - void setValue(String propertyName, Object value); - - void init(ConfigurationValueProvider... configurationValueProviders); - - String getNamespace(); -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java new file mode 100644 index 00000000000..768136ba065 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java @@ -0,0 +1,163 @@ +package liquibase.configuration; + +import liquibase.Scope; +import liquibase.util.ObjectUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +public class ConfigurationDefinition implements Comparable { + + private String property; + private Set aliases = new TreeSet<>(); + private Class type; + private String description; + private DataType defaultValue; + private boolean commonlyUsed; + private ConfigurationValueHandler valueHandler; + private ConfigurationValueObfuscator valueObfuscator; + + public ConfigurationDefinition(String property, Class type) { + this.property = property; + this.type = type; + this.valueHandler = value -> ObjectUtil.convert(value, type); + } + + public DataType getCurrentValue() { + return getCurrentValueDetails().value; + } + + public DataType getCurrentValueObfuscated() { + final DataType currentValue = getCurrentValue(); + + if (this.valueObfuscator == null) { + return currentValue; + } + + return this.valueObfuscator.obfuscate(currentValue); + } + + public CurrentValueDetails getCurrentValueDetails() { + CurrentValueDetails details = new CurrentValueDetails<>(); + + final Object configurationValue = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getCurrentValue(this.getProperty()); + if (configurationValue == null) { + details.value = this.getDefaultValue(); + details.wasOverridden = false; + } else { + details.value = valueHandler.convert(configurationValue); + details.wasOverridden = true; + } + + return details; + } + + public String getProperty() { + return property; + } + + public Set getAliases() { + return aliases; + } + + public Class getType() { + return type; + } + + public String getDescription() { + return description; + } + + public DataType getDefaultValue() { + return defaultValue; + } + + public boolean getCommonlyUsed() { + return commonlyUsed; + } + + @Override + public int compareTo(Object o) { + return this.getProperty().compareTo(((ConfigurationDefinition) o).getProperty()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConfigurationDefinition that = (ConfigurationDefinition) o; + return Objects.equals(property, that.property); + } + + @Override + public int hashCode() { + return Objects.hash(property); + } + + public static class Builder { + private String namespace; + + public Builder(String namespace) { + this.namespace = namespace; + } + + public NewDefinition define(String key, Class dataType) { + final ConfigurationDefinition definition = new ConfigurationDefinition<>(namespace + "." + key, dataType); + + return new NewDefinition<>(definition); + } + + public static class NewDefinition { + private ConfigurationDefinition definition; + + private NewDefinition(ConfigurationDefinition definition) { + this.definition = definition; + } + + public NewDefinition addAlias(String alias) { + definition.aliases.add(alias); + + return this; + } + + public NewDefinition setDescription(String description) { + definition.description = description; + return this; + } + + public NewDefinition setDefaultValue(DataType defaultValue) { + definition.defaultValue = defaultValue; + return this; + } + + public NewDefinition setValueHandler(ConfigurationValueHandler handler) { + definition.valueHandler = handler; + + return this; + } + + public NewDefinition setValueObfuscator(ConfigurationValueObfuscator handler) { + definition.valueObfuscator = handler; + + return this; + } + + public NewDefinition setCommonlyUsed(boolean commonlyUsed) { + definition.commonlyUsed = commonlyUsed; + + return this; + } + + public ConfigurationDefinition build() { + Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).addDefinition(definition); + + return definition; + } + } + + + } + + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java deleted file mode 100644 index 51e89b2a6ad..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java +++ /dev/null @@ -1,207 +0,0 @@ -package liquibase.configuration; - -import liquibase.exception.UnexpectedLiquibaseException; -import liquibase.util.ObjectUtil; -import liquibase.util.StringUtil; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Contains the definition and current value of a given configuration property. - */ -public class ConfigurationProperty { - - private final String namespace; - private final String name; - private final Class type; - private List aliases = new ArrayList<>(); - - private Object value; - private String description; - private Object defaultValue; - private boolean wasOverridden; - - private ConfigurationValueHandler valueHandler; - - public ConfigurationProperty(String namespace, String propertyName, Class type) { - this.namespace = namespace; - this.name = propertyName; - this.type = type; - } - - /** - * Initialize this property with values in the given ConfigurationProvers. If the configurationValueProviders do not contain - * a default value, the property is initialized with the value set by {@link #setDefaultValue(Object)}. - * If multiple configurationValueProviders contain values, the first in the list wins. - */ - protected void init(ConfigurationValueProvider[] configurationValueProviders) { - Object containerValue = null; - - for (ConfigurationValueProvider container : configurationValueProviders) { - containerValue = container.getValue(namespace, name); - for (String alias : aliases) { - if (containerValue != null) { - break; - } - containerValue = container.getValue(namespace, alias); - } - } - - if (containerValue == null) { - value = defaultValue; - } else { - try { - value = valueOf(containerValue); - wasOverridden = true; - } catch (NumberFormatException e) { - throw new UnexpectedLiquibaseException("Error parsing "+containerValue+" as a "+type.getSimpleName()); - } - } - } - - - /** - * Returns the property name. - */ - public String getName() { - return name; - } - - /** - * Returns the namespace used by this property's {@link ConfigurationContainer} - */ - public String getNamespace() { - return namespace; - } - - /** - * Returns the type of value stored in this property - */ - public Class getType() { - return type; - } - - /** - * Converts an object of a different type to the type used by this property. If types are not convertible, an exception is thrown. - */ - protected Object valueOf(Object value) { - if (value == null) { - return value; - } else if (type.isAssignableFrom(value.getClass())) { - return value; - } else if (value instanceof String) { - if (type.equals(Boolean.class)) { - return Boolean.valueOf((String) value); - } else if (type.equals(Integer.class)) { - return Integer.valueOf((String) value); - } else if (type.equals(BigDecimal.class)) { - return new BigDecimal((String) value); - } else if (type.equals(Long.class)) { - return Long.valueOf((String) value); - } else if (type.equals(List.class)) { - return StringUtil.splitAndTrim((String) value, ","); - } else { - throw new UnexpectedLiquibaseException("Cannot parse property "+value.getClass().getSimpleName()+" to a "+type.getSimpleName()); - } - } else { - throw new UnexpectedLiquibaseException("Could not convert "+value.getClass().getSimpleName()+" to a "+type.getSimpleName()); - } - } - - /** - * Returns the value currently stored in this property without any casting. - */ - public Object getValue() { - return value; - } - - /** - * Returns the value currently stored in this property cast to the given type. - */ - public T getValue(Class type) { - if (!this.type.isAssignableFrom(type)) { - throw new UnexpectedLiquibaseException("Property "+name+" on is of type "+this.type.getSimpleName()+", not "+type.getSimpleName()); - } - - return (T) value; - } - - /** - * Overwrites the value currently stored in this property. It he passed type is not compatible with the defined type, an exception is thrown. - */ - public void setValue(Object value) { - if (valueHandler == null) { - value = ObjectUtil.convert(value, type); - } else { - value = valueHandler.convert(value); - } - if ((value != null) && !type.isAssignableFrom(value.getClass())) { - throw new UnexpectedLiquibaseException("Property "+name+" is of type "+type.getSimpleName()+", not "+value.getClass().getSimpleName()); - } - - this.value = value; - wasOverridden = true; - } - - /** - * Adds an alias for this property. An alias is an alternate to the "name" field that can be used by the ConfigurationProvers to look up starting values. - */ - public ConfigurationProperty addAlias(String... aliases) { - if (aliases != null) { - this.aliases.addAll(Arrays.asList(aliases)); - } - - return this; - } - - /** - * Returns a human-readable definition of this property - */ - public String getDescription() { - return description; - } - - public ConfigurationProperty setDescription(String description) { - this.description = description; - return this; - } - - /** - * Returns the default value to use if no ConfigurationProviders override it. - */ - public Object getDefaultValue() { - return defaultValue; - } - - /** - * Sets the default value to use if no ConfigurationProviders override it. Throws an exception if the given object is not compatible with the defined type. - */ - public ConfigurationProperty setDefaultValue(Object defaultValue) { - if ((defaultValue != null) && !type.isAssignableFrom(defaultValue.getClass())) { - if ((type == Long.class) && (defaultValue instanceof Integer)) { - return setDefaultValue(((Integer) defaultValue).longValue()); - } - throw new UnexpectedLiquibaseException("Property "+name+" on is of type "+type.getSimpleName()+", not "+defaultValue.getClass().getSimpleName()); - } - - this.defaultValue = defaultValue; - - return this; - } - - /** - * Returns true if the value has been set by a ConfigurationValueProvider or by {@link #setValue(Object)} - */ - public boolean getWasOverridden() { - return wasOverridden; - } - - public ConfigurationProperty setValueHandler(ConfigurationValueHandler handler) { - this.valueHandler = handler; - - return this; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java index 6c086177763..082c90f5604 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java @@ -1,9 +1,6 @@ package liquibase.configuration; -/** - * Implementations can convert specified {@link ConfigurationProperty} values - */ -public interface ConfigurationValueHandler { +public interface ConfigurationValueHandler { - Object convert(Object value); + DataType convert(Object value) throws IllegalArgumentException; } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java new file mode 100644 index 00000000000..d7e1422a8eb --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java @@ -0,0 +1,6 @@ +package liquibase.configuration; + +public interface ConfigurationValueObfuscator { + + DataType obfuscate(DataType value); +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java index 18df84963cd..1c55683d88f 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java @@ -1,19 +1,19 @@ package liquibase.configuration; +import liquibase.configuration.core.SystemPropertyProvider; + /** * Interface for classes that are able to lookup overriding default LiquibaseConfiguration values. - * For example, {@link liquibase.configuration.SystemPropertyProvider} can look up property values in system properties. + * For example, {@link SystemPropertyProvider} can look up property values in system properties. */ public interface ConfigurationValueProvider { - /** - * Return the value for a given namespace and property. Returns null if this provider does not have a value for this property. - */ - Object getValue(String namespace, String property); + int getPrecedence(); + + Object getValue(String property); /** * Generates a human consumable description of how the configured ConfigurationValueProvider(s) will attempt to set a default value. - * See {@link LiquibaseConfiguration#describeValueLookupLogic(ConfigurationProperty)} */ - String describeValueLookupLogic(ConfigurationProperty property); + String describeValueLookupLogic(String property); } diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java new file mode 100644 index 00000000000..28aa573210d --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java @@ -0,0 +1,19 @@ +package liquibase.configuration; + +public class CurrentValueDetails { + DataType value; + boolean wasOverridden; + String sourceDescription; + + public DataType getValue() { + return value; + } + + public boolean getWasOverridden() { + return wasOverridden; + } + + public String getSourceDescription() { + return sourceDescription; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java deleted file mode 100644 index ec0789dc1ea..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java +++ /dev/null @@ -1,296 +0,0 @@ -package liquibase.configuration; - -/** - * Configuration container for global properties. - */ -public class GlobalConfiguration extends AbstractConfigurationContainer { - - public static final String SHOULD_RUN = "shouldRun"; - public static final String DATABASECHANGELOG_TABLE_NAME = "databaseChangeLogTableName"; - public static final String DATABASECHANGELOGLOCK_TABLE_NAME = "databaseChangeLogLockTableName"; - public static final String LIQUIBASE_TABLESPACE_NAME = "tablespaceName"; - public static final String LIQUIBASE_CATALOG_NAME = "catalogName"; - public static final String LIQUIBASE_SCHEMA_NAME = "schemaName"; - public static final String OUTPUT_LINE_SEPARATOR = "outputLineSeparator"; - public static final String OUTPUT_ENCODING = "outputFileEncoding"; - public static final String CHANGELOGLOCK_WAIT_TIME = "changeLogLockWaitTimeInMinutes"; - public static final String CHANGELOGLOCK_POLL_RATE = "changeLogLockPollRate"; - public static final String CONVERT_DATA_TYPES = "convertDataTypes"; - public static final String GENERATE_CHANGESET_CREATED_VALUES = "generateChangeSetCreatedValues"; - public static final String AUTO_REORG = "autoReorg"; - public static final String DIFF_COLUMN_ORDER = "diffColumnOrder"; - public static final String ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA = "alwaysOverrideStoredLogicSchema"; - public static final String GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION = "generatedChangeSetIdsContainsDescription"; - public static final String INCLUDE_CATALOG_IN_SPECIFICATION = "includeCatalogInSpecification"; - public static final String SHOULD_SNAPSHOT_DATA = "shouldSnapshotData"; - public static final String FILTER_LOG_MESSAGES = "filterLogMessages"; - public static final String HEADLESS = "headless"; - - public GlobalConfiguration() { - super("liquibase"); - - getContainer().addProperty(SHOULD_RUN, Boolean.class) - .setDescription("Should Liquibase commands execute") - .setDefaultValue(true) - .addAlias("should.run"); - - getContainer().addProperty(DATABASECHANGELOG_TABLE_NAME, String.class) - .setDescription("Name of table to use for tracking change history") - .setDefaultValue("DATABASECHANGELOG"); - - getContainer().addProperty(DATABASECHANGELOGLOCK_TABLE_NAME, String.class) - .setDescription("Name of table to use for tracking concurrent Liquibase usage") - .setDefaultValue("DATABASECHANGELOGLOCK"); - - getContainer().addProperty(CHANGELOGLOCK_WAIT_TIME, Long.class) - .setDescription("Number of minutes to wait for the changelog lock to be available before giving up") - .setDefaultValue(5); - - getContainer().addProperty(CHANGELOGLOCK_POLL_RATE, Long.class) - .setDescription("Number of seconds wait between checks to the changelog lock when it is locked") - .setDefaultValue(10); - - getContainer().addProperty(LIQUIBASE_TABLESPACE_NAME, String.class) - .setDescription("Tablespace to use for Liquibase objects"); - - getContainer().addProperty(LIQUIBASE_CATALOG_NAME, String.class) - .setDescription("Catalog to use for Liquibase objects"); - - getContainer().addProperty(LIQUIBASE_SCHEMA_NAME, String.class) - .setDescription("Schema to use for Liquibase objects"); - - getContainer().addProperty(OUTPUT_LINE_SEPARATOR, String.class) - .setDescription("Line separator for output. Defaults to OS default") - .setDefaultValue(System.getProperty("line.separator")); - - getContainer().addProperty(OUTPUT_ENCODING, String.class) - .setDescription("Encoding to output text in. Defaults to file.encoding system property or UTF-8") - .setDefaultValue("UTF-8") - .addAlias("file.encoding"); - - getContainer().addProperty(CONVERT_DATA_TYPES, Boolean.class) - .setDescription("Should Liquibase convert to/from STANDARD data types. Applies to both snapshot and " + - "update commands.") - .setDefaultValue(true); - - getContainer().addProperty(GENERATE_CHANGESET_CREATED_VALUES, Boolean.class) - .setDescription("Should Liquibase include a 'created' attribute in diff/generateChangeLog changeSets with" + - " the current datetime") - .setDefaultValue(false); - - getContainer().addProperty(AUTO_REORG, Boolean.class) - .setDescription("Should Liquibase automatically include REORG TABLE commands when needed?") - .setDefaultValue(true); - - getContainer().addProperty(DIFF_COLUMN_ORDER, Boolean.class) - .setDescription("Should Liquibase compare column order in diff operation?") - .setDefaultValue(true); - - getContainer().addProperty(ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA, Boolean.class) - .setDescription("When generating SQL for createProcedure, should the procedure schema be forced to the default schema if no schemaName attribute is set?") - .setDefaultValue(false); - - - getContainer().addProperty(GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION, Boolean.class) - .setDescription("Should Liquibase include the change description in the id when generating changeSets?") - .setDefaultValue(false); - - getContainer().addProperty(INCLUDE_CATALOG_IN_SPECIFICATION, Boolean.class) - .setDescription("Should Liquibase include the catalog name when determining equality?") - .setDefaultValue(false); - - getContainer().addProperty(SHOULD_SNAPSHOT_DATA, Boolean.class) - .setDescription("Should Liquibase snapshot data by default?") - .setDefaultValue(false); - - getContainer().addProperty(FILTER_LOG_MESSAGES, Boolean.class) - .setDescription("Should Liquibase filter log messages for potentially insecure data?") - .setDefaultValue(true); - - getContainer().addProperty(HEADLESS, Boolean.class) - .setDescription("Force liquibase think it has no access to a keyboard?") - .setDefaultValue(false); - - } - - /** - * Should Liquibase execute - */ - public boolean getShouldRun() { - return getContainer().getValue(SHOULD_RUN, Boolean.class); - } - - public GlobalConfiguration setShouldRun(boolean shouldRun) { - getContainer().setValue(SHOULD_RUN, shouldRun); - return this; - } - - /** - * Table name to use for DATABASECHANGELOG - */ - public String getDatabaseChangeLogTableName() { - return getContainer().getValue(DATABASECHANGELOG_TABLE_NAME, String.class); - } - - public GlobalConfiguration setDatabaseChangeLogTableName(String name) { - getContainer().setValue(DATABASECHANGELOG_TABLE_NAME, name); - return this; - } - - /** - * Table name to use for DATABASECHANGELOGLOCK - */ - public String getDatabaseChangeLogLockTableName() { - return getContainer().getValue(DATABASECHANGELOGLOCK_TABLE_NAME, String.class); - } - - public GlobalConfiguration setDatabaseChangeLogLockTableName(String name) { - getContainer().setValue(DATABASECHANGELOGLOCK_TABLE_NAME, name); - return this; - } - - /** - * Wait time (in minutes) to wait to receive the changelog lock before giving up. - */ - public Long getDatabaseChangeLogLockWaitTime() { - return getContainer().getValue(CHANGELOGLOCK_WAIT_TIME, Long.class); - } - - public GlobalConfiguration setDatabaseChangeLogLockWaitTime(Long minutes) { - getContainer().setValue(CHANGELOGLOCK_WAIT_TIME, minutes); - return this; - } - - /** - * Wait time (in seconds) between polling requests to the changelog lock system. - */ - public Long getDatabaseChangeLogLockPollRate() { - return getContainer().getValue(CHANGELOGLOCK_POLL_RATE, Long.class); - } - - public GlobalConfiguration setDatabaseChangeLogLockPollRate(Long seconds) { - getContainer().setValue(CHANGELOGLOCK_POLL_RATE, seconds); - return this; - } - - /** - * Name of the tablespace to use for liquibase database objects - */ - public String getLiquibaseTablespaceName() { - return getContainer().getValue(LIQUIBASE_TABLESPACE_NAME, String.class); - } - - public GlobalConfiguration setLiquibaseTablespaceName(String name) { - getContainer().setValue(LIQUIBASE_TABLESPACE_NAME, name); - return this; - } - - /** - * - * Should Liquibase snapshot data for table by default - * - */ - public boolean getShouldSnapshotData() { - return getContainer().getValue(SHOULD_SNAPSHOT_DATA, Boolean.class); - } - - public GlobalConfiguration setShouldSnapshotData(boolean shouldSnapshotData) { - getContainer().setValue(SHOULD_SNAPSHOT_DATA, shouldSnapshotData); - return this; - } - - public boolean getShouldFilterLogMessages() { - return getContainer().getValue(FILTER_LOG_MESSAGES, Boolean.class); - } - - public GlobalConfiguration setShouldFilterLogMessages(boolean filter) { - getContainer().setValue(FILTER_LOG_MESSAGES, filter); - return this; - } - - public boolean getHeadless() { - return getContainer().getValue(HEADLESS, Boolean.class); - } - - public GlobalConfiguration setHeadless(boolean headless) { - getContainer().setValue(HEADLESS, headless); - return this; - } - - /** - * Name of the catalog to use for liquibase database objects - */ - public String getLiquibaseCatalogName() { - return getContainer().getValue(LIQUIBASE_CATALOG_NAME, String.class); - } - - public GlobalConfiguration setLiquibaseCatalogName(String name) { - getContainer().setValue(LIQUIBASE_CATALOG_NAME, name); - return this; - } - - /** - * Name of the schema to use for liquibase database objects - */ - public String getLiquibaseSchemaName() { - return getContainer().getValue(LIQUIBASE_SCHEMA_NAME, String.class); - } - - public GlobalConfiguration setLiquibaseSchemaName(String name) { - getContainer().setValue(LIQUIBASE_SCHEMA_NAME, name); - return this; - } - - /** - * Line separator to use in output - */ - public String getOutputLineSeparator() { - return getContainer().getValue(OUTPUT_LINE_SEPARATOR, String.class); - } - - public GlobalConfiguration setOutputLineSeparator(String name) { - getContainer().setValue(OUTPUT_LINE_SEPARATOR, name); - return this; - } - - /** - * String encoding to use in output. - */ - public String getOutputEncoding() { - return getContainer().getValue(OUTPUT_ENCODING, String.class); - } - - public GlobalConfiguration setOutputEncoding(String name) { - getContainer().setValue(OUTPUT_ENCODING, name); - return this; - } - - public Boolean getDiffColumnOrder() { - return getContainer().getValue(DIFF_COLUMN_ORDER, Boolean.class); - } - - public GlobalConfiguration setDiffColumnOrder(boolean diff) { - getContainer().setValue(DIFF_COLUMN_ORDER, diff); - return this; - } - - - public Boolean getAlwaysOverrideStoredLogicSchema() { - return getContainer().getValue(ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA, Boolean.class); - } - - public GlobalConfiguration setAlwaysOverrideStoredLogicSchema(boolean override) { - getContainer().setValue(ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA, override); - return this; - } - - - public Boolean getGeneratedChangeSetIdsContainDescription() { - return getContainer().getValue(GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION, Boolean.class); - } - - public GlobalConfiguration setGeneratedChangeSetIdsContainDescription(boolean containDescription) { - getContainer().setValue(GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION, containDescription); - return this; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/HubConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/HubConfiguration.java deleted file mode 100644 index 90ec1be492d..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/HubConfiguration.java +++ /dev/null @@ -1,88 +0,0 @@ -package liquibase.configuration; - -import liquibase.util.StringUtil; - -import java.util.Arrays; -import java.util.List; - -/** - * Configuration container for global properties. - */ -public class HubConfiguration extends AbstractConfigurationContainer { - - public static final String LIQUIBASE_HUB_API_KEY = "apiKey"; - public static final String LIQUIBASE_HUB_URL = "url"; - public static final String LIQUIBASE_HUB_MODE = "mode"; - - public HubConfiguration() { - super("liquibase.hub"); - - getContainer().addProperty(LIQUIBASE_HUB_API_KEY, String.class) - .setDescription("Liquibase Hub API key for operations"); - getContainer().addProperty(LIQUIBASE_HUB_URL, String.class) - .setDescription("Liquibase Hub URL for operations") - .setValueHandler(value -> { - if (value == null) { - return null; - } - return value.toString().replaceFirst("(https?://[^/]+).*", "$1"); - }); - getContainer().addProperty(LIQUIBASE_HUB_MODE, String.class) - .setDescription("Content to send to Liquibase Hub during operations. Values can be 'all', 'meta', or 'off'") - .setDefaultValue("all"); - } - - @Override - public void setValue(String propertyName, Object value) { - super.setValue(propertyName, value); - } - - /** - * Output {@link #getLiquibaseHubApiKey()} but in a way that is secure for message output. - * - */ - public String getLiquibaseHubApiKeySecureDescription() { - final String key = getContainer().getValue(LIQUIBASE_HUB_API_KEY, String.class); - if (key == null) { - return null; - } - return key.substring(0,6) + "************"; - } - - public String getLiquibaseHubApiKey() { - return getContainer().getValue(LIQUIBASE_HUB_API_KEY, String.class); - } - - public HubConfiguration setLiquibaseHubApiKey(String liquibaseHubApiKey) { - getContainer().setValue(LIQUIBASE_HUB_API_KEY, liquibaseHubApiKey); - return this; - } - - public HubConfiguration setLiquibaseHubUrl(String liquibaseHubUrl) { - getContainer().setValue(LIQUIBASE_HUB_URL, liquibaseHubUrl); - return this; - } - - public String getLiquibaseHubUrl() { - String hubUrl = getContainer().getValue(LIQUIBASE_HUB_URL, String.class); - if (hubUrl == null || hubUrl.isEmpty()) { - return "https://hub.liquibase.com"; - } - return hubUrl; - } - - public HubConfiguration setLiquibaseHubMode(String liquibaseHubMode) { - getContainer().setValue(LIQUIBASE_HUB_MODE, liquibaseHubMode); - return this; - } - - public String getLiquibaseHubMode() { - final String value = getContainer().getValue(LIQUIBASE_HUB_MODE, String.class); - - final List validValues = Arrays.asList("off", "meta", "all"); - if (!validValues.contains(value.toLowerCase())) { - throw new RuntimeException(" An invalid liquibase.hub.mode value of "+value+" detected. Acceptable values are "+StringUtil.join(validValues, ", ")); - } - return value; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index b623258de18..7e119a1aa80 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -1,17 +1,15 @@ package liquibase.configuration; -import liquibase.exception.UnexpectedLiquibaseException; -import liquibase.util.StringUtil; +import liquibase.Scope; +import liquibase.SingletonObject; +import liquibase.servicelocator.ServiceLocator; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * 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 + * This class is the top level container used to access {@link AutoloadedConfigurations} implementations which contain * the actual configuration properties. * Normal use is to call * LiquibaseConfiguration.getInstance().getConfiguration(NEEDED_CONFIGURATION.class).getYOUR_PROPERTY() @@ -21,40 +19,29 @@ * the singleton with an alternate implementation that uses ThreadLocal objects or any other way of managing * configurations. */ -public class LiquibaseConfiguration { +public class LiquibaseConfiguration implements SingletonObject { - private Map configurations; + private final SortedSet configurationValueProviders; + private final SortedSet definitions = new TreeSet<>(); - 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; + public static LiquibaseConfiguration getInstance() { + return Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); } /** - * Overrides the standard singleton instance created by getInstance(). - * Useful for alternate implementations with more complex AbstractConfigurationContainer lookup logic such - * as different configurations per thread. + * Constructor protected to prevent construction outside getInstance() */ - public static synchronized void setInstance(LiquibaseConfiguration instance) { - LiquibaseConfiguration.instance = instance; - } + public LiquibaseConfiguration() { + configurationValueProviders = new TreeSet<>((o1, o2) -> { + if (o1.getPrecedence() < o1.getPrecedence()) { + return -1; + } else if (o1.getPrecedence() > o1.getPrecedence()) { + return 1; + } + return o1.getClass().getName().compareTo(o2.getClass().getName()); + }); - /** - * Constructor protected to prevent construction outside getInstance() - */ - protected LiquibaseConfiguration() { } @@ -62,123 +49,45 @@ 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]; + public void init(Scope scope) { + 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()); } - this.configurationValueProviders = configurationValueProviders; - this.reset(); + configurationValueProviders.addAll(serviceLocator.findInstances(ConfigurationValueProvider.class)); } - /** - * Resets existing AbstractConfigurationContainer instances to their default values. - */ + //TODO: remove 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); } - /** - * - * Return an instance of the passed ConfigurationContainer type - * The typeName can be the name of a class or the namespace associated with the container - * - * @param typeName - * @return ConfigurationContainer - * - */ - public ConfigurationContainer getConfiguration(String typeName) { - // - // Lookup by class name - // - for (Map.Entry entry : configurations.entrySet()) { - if (entry.getKey().getName().equals(typeName)) { - return entry.getValue(); - } - } - - // - // Lookup by namespace - // - for (ConfigurationContainer container : configurations.values()) { - String namespace = container.getNamespace(); - if (namespace.equalsIgnoreCase(typeName)) { - return container; + public ConfigurationDefinition getDefinition(String property) { + for (ConfigurationDefinition definition : definitions) { + if (definition.getProperty().equals(property)) { + return definition; } } - - // - // Instantiate and put in the map - // - 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 type, String property) { - ConfigurationContainer configuration = getConfiguration(type); - return configuration.getProperty(property); + return null; } - 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); + public Object getCurrentValue(String property) { + for (ConfigurationValueProvider provider : configurationValueProviders) { + final Object value = provider.getValue(property); + if (value != null) { + return value; + } } - } - /** - * Convenience method for {@link #describeValueLookupLogic(ConfigurationProperty)} - */ - public String describeValueLookupLogic(Class config, String property) { - return describeValueLookupLogic(getProperty(config, property)); + return null; } - /** - * 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 StringUtil.join(reasons, " AND "); + public void addDefinition(ConfigurationDefinition definition) { + this.definitions.add(definition); } - /** - * Convenience method to check if the object types should consider catalog name - * also during comparision (equals(), hashcode() and compareTo()) - * - * @return - */ - public boolean shouldIncludeCatalogInSpecification() { - Boolean includeCatalog = getConfiguration(GlobalConfiguration.class) - .getValue(GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION, Boolean.class); - return includeCatalog != null ? includeCatalog : false; + public SortedSet getDefinitions() { + return Collections.unmodifiableSortedSet(this.definitions); } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java new file mode 100644 index 00000000000..c87a9ce4723 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java @@ -0,0 +1,72 @@ +package liquibase.configuration.core; + +import liquibase.configuration.ConfigurationValueProvider; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Searches for the configuration values in the system environment variables. + * + * To handle shells that only allow underscores, it checks the following variations of a proprty: + *

    + *
  • foo.bar - the original name
  • + *
  • foo_bar - with underscores for periods (if any)
  • + *
  • FOO.BAR - original, with upper case
  • + *
  • FOO_BAR - with underscores and upper case
  • + *
+ * Any hyphen variant of the above would work as well, or even mix dot/hyphen variants. + * + */ +public class EnvironmentVariableProvider implements ConfigurationValueProvider { + + @Override + public int getPrecedence() { + return 10; + } + + @Override + public Object getValue(String property) { + if (property == null) { + return null; + } + + Set checked = new HashSet<>(); + + for (String name : new String[]{property, property.toUpperCase(), property.toLowerCase()}) { + for (String variation : new String[] { + name, + + // Check name with just dots replaced + name.replace('.', '_'), + + // Check name with just hyphens replaced + name.replace('-', '_'), + + // Check name with dots and hyphens replaced + name.replace('.', '_').replace('-', '_') + }) { + if (checked.add(variation)) { + final String foundValue = getEnvironmentVariable(variation); + if (foundValue != null) { + return foundValue; + } + + } + + } + } + + return null; + } + + protected String getEnvironmentVariable(String name) { + return System.getenv(name); + } + + @Override + public String describeValueLookupLogic(String property) { + return "Environment variable '" + property + "'"; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/SystemPropertyProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java similarity index 61% rename from liquibase-core/src/main/java/liquibase/configuration/SystemPropertyProvider.java rename to liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java index 91ffc63a74e..7909e823125 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/SystemPropertyProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java @@ -1,5 +1,6 @@ -package liquibase.configuration; +package liquibase.configuration.core; +import liquibase.configuration.ConfigurationValueProvider; import liquibase.util.StringUtil; import java.util.Map; @@ -12,8 +13,13 @@ public class SystemPropertyProvider implements ConfigurationValueProvider { @Override - public Object getValue(String namespace, String property) { - String propValue = System.getProperty(namespace +"."+property); + public int getPrecedence() { + return 20; + } + + @Override + public Object getValue(String property) { + String propValue = System.getProperty(property); if (StringUtil.isNotEmpty(propValue)) { return propValue; } @@ -23,8 +29,8 @@ public Object getValue(String namespace, String property) { // Properties properties = System.getProperties(); for (Map.Entry entry : properties.entrySet()) { - String key = (String)entry.getKey(); - if (key.equalsIgnoreCase(namespace + "." + property)) { + String key = (String) entry.getKey(); + if (key.equalsIgnoreCase(property)) { return entry.getValue(); } } @@ -32,7 +38,7 @@ public Object getValue(String namespace, String property) { } @Override - public String describeValueLookupLogic(ConfigurationProperty property) { - return "System property '"+property.getNamespace()+"."+property.getName()+"'"; + public String describeValueLookupLogic(String property) { + return "System property '" + property + "'"; } } diff --git a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java index dd328f8ce2c..ab952c83cc1 100644 --- a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java +++ b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java @@ -9,9 +9,7 @@ import liquibase.changelog.DatabaseChangeLog; import liquibase.changelog.RanChangeSet; import liquibase.changelog.StandardChangeLogHistoryService; -import liquibase.configuration.ConfigurationProperty; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.core.OracleDatabase; import liquibase.database.core.PostgresDatabase; import liquibase.database.core.SQLiteDatabase; @@ -623,7 +621,7 @@ public String getDatabaseChangeLogTableName() { return databaseChangeLogTableName; } - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getDatabaseChangeLogTableName(); + return GlobalConfiguration.DATABASECHANGELOG_TABLE_NAME.getCurrentValue(); } @Override @@ -637,7 +635,7 @@ public String getDatabaseChangeLogLockTableName() { return databaseChangeLogLockTableName; } - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getDatabaseChangeLogLockTableName(); + return GlobalConfiguration.DATABASECHANGELOGLOCK_TABLE_NAME.getCurrentValue(); } @Override @@ -651,7 +649,7 @@ public String getLiquibaseTablespaceName() { return liquibaseTablespaceName; } - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getLiquibaseTablespaceName(); + return GlobalConfiguration.LIQUIBASE_TABLESPACE_NAME.getCurrentValue(); } @Override @@ -674,9 +672,8 @@ public String getLiquibaseCatalogName() { return liquibaseCatalogName; } - ConfigurationProperty configuration = LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration.LIQUIBASE_CATALOG_NAME); - if (configuration.getWasOverridden()) { - return configuration.getValue(String.class); + if (GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValueDetails().getWasOverridden()) { + return GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValue(); } return getDefaultCatalogName(); @@ -693,9 +690,8 @@ public String getLiquibaseSchemaName() { return liquibaseSchemaName; } - ConfigurationProperty configuration = LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration.LIQUIBASE_SCHEMA_NAME); - if (configuration.getWasOverridden()) { - return configuration.getValue(String.class); + if (GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValueDetails().getWasOverridden()) { + return GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValue(); } return getDefaultSchemaName(); diff --git a/liquibase-core/src/main/java/liquibase/database/core/MSSQLDatabase.java b/liquibase-core/src/main/java/liquibase/database/core/MSSQLDatabase.java index 0fac70df533..e9bbe1c9186 100644 --- a/liquibase-core/src/main/java/liquibase/database/core/MSSQLDatabase.java +++ b/liquibase-core/src/main/java/liquibase/database/core/MSSQLDatabase.java @@ -2,7 +2,7 @@ import liquibase.CatalogAndSchema; import liquibase.Scope; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.AbstractJdbcDatabase; import liquibase.database.DatabaseConnection; import liquibase.database.OfflineConnection; @@ -377,7 +377,7 @@ public String escapeObjectName(String catalogName, String schemaName, String obj return super.escapeObjectName(objectName, objectType); } - boolean includeCatalog = LiquibaseConfiguration.getInstance().shouldIncludeCatalogInSpecification(); + boolean includeCatalog = GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION.getCurrentValue(); if ((catalogName != null) && (includeCatalog || !catalogName.equalsIgnoreCase(this.getDefaultCatalogName()))) { return super.escapeObjectName(catalogName, schemaName, objectName, objectType); } else { diff --git a/liquibase-core/src/main/java/liquibase/datatype/core/ClobType.java b/liquibase-core/src/main/java/liquibase/datatype/core/ClobType.java index c0b2d49babb..0ebcb582e4e 100644 --- a/liquibase-core/src/main/java/liquibase/datatype/core/ClobType.java +++ b/liquibase-core/src/main/java/liquibase/datatype/core/ClobType.java @@ -1,8 +1,7 @@ package liquibase.datatype.core; import liquibase.change.core.LoadDataChange; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.*; import liquibase.datatype.DataTypeInfo; @@ -44,8 +43,8 @@ public String objectToSql(Object value, Database database) { public DatabaseDataType toDatabaseDataType(Database database) { String originalDefinition = StringUtil.trimToEmpty(getRawDefinition()); if (database instanceof MSSQLDatabase) { - if ((!LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration - .CONVERT_DATA_TYPES).getValue(Boolean.class) && originalDefinition.toLowerCase(Locale.US).startsWith("text")) + if ((!GlobalConfiguration.CONVERT_DATA_TYPES.getCurrentValue() + && originalDefinition.toLowerCase(Locale.US).startsWith("text")) || originalDefinition.toLowerCase(Locale.US).startsWith("[text]")) { DatabaseDataType type = new DatabaseDataType(database.escapeDataTypeName("varchar")); // If there is additional specification after ntext (e.g. COLLATE), import that. diff --git a/liquibase-core/src/main/java/liquibase/datatype/core/TimestampType.java b/liquibase-core/src/main/java/liquibase/datatype/core/TimestampType.java index 5d92519c1d7..eb040198662 100644 --- a/liquibase-core/src/main/java/liquibase/datatype/core/TimestampType.java +++ b/liquibase-core/src/main/java/liquibase/datatype/core/TimestampType.java @@ -4,8 +4,7 @@ import liquibase.change.core.LoadDataChange; import java.util.Locale; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.*; import liquibase.datatype.DataTypeInfo; @@ -67,9 +66,7 @@ public DatabaseDataType toDatabaseDataType(Database database) { return super.toDatabaseDataType(database); } if (database instanceof MSSQLDatabase) { - if (!LiquibaseConfiguration.getInstance() - .getProperty(GlobalConfiguration.class, GlobalConfiguration.CONVERT_DATA_TYPES) - .getValue(Boolean.class) + if (!GlobalConfiguration.CONVERT_DATA_TYPES.getCurrentValue() && originalDefinition.toLowerCase(Locale.US).startsWith("timestamp")) { return new DatabaseDataType(database.escapeDataTypeName("timestamp")); } diff --git a/liquibase-core/src/main/java/liquibase/dbdoc/ChangeLogWriter.java b/liquibase-core/src/main/java/liquibase/dbdoc/ChangeLogWriter.java index 13c3c4c9f17..def4f16277e 100644 --- a/liquibase-core/src/main/java/liquibase/dbdoc/ChangeLogWriter.java +++ b/liquibase-core/src/main/java/liquibase/dbdoc/ChangeLogWriter.java @@ -1,7 +1,6 @@ package liquibase.dbdoc; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.resource.ResourceAccessor; import liquibase.util.StreamUtil; @@ -22,7 +21,7 @@ public void writeChangeLog(String changeLog, String physicalFilePath) throws IOE xmlFile.getParentFile().mkdirs(); BufferedWriter changeLogStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(xmlFile, - false), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + false), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); try (InputStream stylesheet = resourceAccessor.openStream(null, physicalFilePath)) { if (stylesheet == null) { throw new IOException("Can not find " + changeLog); diff --git a/liquibase-core/src/main/java/liquibase/dbdoc/HTMLListWriter.java b/liquibase-core/src/main/java/liquibase/dbdoc/HTMLListWriter.java index a73fd8a64e5..6a9b99c7167 100644 --- a/liquibase-core/src/main/java/liquibase/dbdoc/HTMLListWriter.java +++ b/liquibase-core/src/main/java/liquibase/dbdoc/HTMLListWriter.java @@ -1,7 +1,6 @@ package liquibase.dbdoc; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.util.StringUtil; import java.io.*; @@ -24,7 +23,7 @@ public HTMLListWriter(String title, String filename, String subdir, File outputD } public void writeHTML(SortedSet objects) throws IOException { - Writer fileWriter = new OutputStreamWriter(new FileOutputStream(new File(outputDir, filename)), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + Writer fileWriter = new OutputStreamWriter(new FileOutputStream(new File(outputDir, filename)), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); try { fileWriter.append("\n" + "\n" + "\n"); diff --git a/liquibase-core/src/main/java/liquibase/dbdoc/HTMLWriter.java b/liquibase-core/src/main/java/liquibase/dbdoc/HTMLWriter.java index 3580e676b0f..221a4a1e4b8 100644 --- a/liquibase-core/src/main/java/liquibase/dbdoc/HTMLWriter.java +++ b/liquibase-core/src/main/java/liquibase/dbdoc/HTMLWriter.java @@ -2,8 +2,7 @@ import liquibase.change.Change; import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.exception.DatabaseException; import liquibase.exception.DatabaseHistoryException; @@ -30,7 +29,7 @@ public HTMLWriter(File outputDir, Database database) { protected abstract void writeCustomHTML(Writer fileWriter, Object object, List<Change> changes, Database database) throws IOException; private Writer createFileWriter(Object object) throws IOException { - return new OutputStreamWriter(new FileOutputStream(new File(outputDir, DBDocUtil.toFileName(object.toString().toLowerCase()) + ".html")), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + return new OutputStreamWriter(new FileOutputStream(new File(outputDir, DBDocUtil.toFileName(object.toString().toLowerCase()) + ".html")), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); } public void writeHTML(Object object, List<Change> ranChanges, List<Change> changesToRun, String changeLog) throws IOException, DatabaseHistoryException, DatabaseException { diff --git a/liquibase-core/src/main/java/liquibase/diff/compare/core/CatalogComparator.java b/liquibase-core/src/main/java/liquibase/diff/compare/core/CatalogComparator.java index 1a71907561a..e8ef0b79b0f 100644 --- a/liquibase-core/src/main/java/liquibase/diff/compare/core/CatalogComparator.java +++ b/liquibase-core/src/main/java/liquibase/diff/compare/core/CatalogComparator.java @@ -1,7 +1,7 @@ package liquibase.diff.compare.core; import liquibase.CatalogAndSchema; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.diff.ObjectDifferences; import liquibase.diff.compare.CompareControl; @@ -38,7 +38,7 @@ public boolean isSameObject(DatabaseObject databaseObject1, DatabaseObject datab } // the flag will be set true in multi catalog environments - boolean shouldIncludeCatalog = LiquibaseConfiguration.getInstance().shouldIncludeCatalogInSpecification(); + boolean shouldIncludeCatalog = GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION.getCurrentValue(); String object1Name; if (!shouldIncludeCatalog && ((Catalog) databaseObject1).isDefault()) { object1Name = null; diff --git a/liquibase-core/src/main/java/liquibase/diff/compare/core/ColumnComparator.java b/liquibase-core/src/main/java/liquibase/diff/compare/core/ColumnComparator.java index 9d889bd4a8d..76c592598c3 100644 --- a/liquibase-core/src/main/java/liquibase/diff/compare/core/ColumnComparator.java +++ b/liquibase-core/src/main/java/liquibase/diff/compare/core/ColumnComparator.java @@ -1,7 +1,6 @@ package liquibase.diff.compare.core; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.diff.ObjectDifferences; import liquibase.diff.compare.CompareControl; @@ -77,7 +76,7 @@ public ObjectDifferences findDifferences(DatabaseObject databaseObject1, Databas exclude.add("type"); exclude.add("autoIncrementInformation"); - if (!LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getDiffColumnOrder()) { + if (!GlobalConfiguration.DIFF_COLUMN_ORDER.getCurrentValue()) { exclude.add("order"); } diff --git a/liquibase-core/src/main/java/liquibase/diff/compare/core/SchemaComparator.java b/liquibase-core/src/main/java/liquibase/diff/compare/core/SchemaComparator.java index e123f5e3e52..13c89a715b3 100644 --- a/liquibase-core/src/main/java/liquibase/diff/compare/core/SchemaComparator.java +++ b/liquibase-core/src/main/java/liquibase/diff/compare/core/SchemaComparator.java @@ -1,7 +1,7 @@ package liquibase.diff.compare.core; import liquibase.CatalogAndSchema; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.diff.ObjectDifferences; import liquibase.diff.compare.CompareControl; @@ -10,7 +10,6 @@ import liquibase.structure.DatabaseObject; import liquibase.structure.core.Catalog; import liquibase.structure.core.Schema; -import liquibase.util.StringUtil; import java.util.Set; @@ -38,7 +37,7 @@ public boolean isSameObject(DatabaseObject databaseObject1, DatabaseObject datab String schemaName2 = null; // the flag will be set true in multi catalog environments - boolean shouldIncludeCatalog = LiquibaseConfiguration.getInstance().shouldIncludeCatalogInSpecification(); + boolean shouldIncludeCatalog = GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION.getCurrentValue(); if (shouldIncludeCatalog) { Catalog catalog1 = ((Schema) databaseObject1).getCatalog(); Catalog catalog2 = ((Schema) databaseObject2).getCatalog(); diff --git a/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java b/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java index 50269e5d448..2db7d90510a 100644 --- a/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java +++ b/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java @@ -4,8 +4,7 @@ import liquibase.change.Change; import liquibase.change.core.*; import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.*; import liquibase.database.core.*; import liquibase.diff.DiffResult; @@ -134,9 +133,9 @@ public void run() { } else { Scope.getCurrentScope().getLog(getClass()).info(file + " exists, appending"); ByteArrayOutputStream out = new ByteArrayOutputStream(); - print(new PrintStream(out, true, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()), changeLogSerializer); + print(new PrintStream(out, true, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()), changeLogSerializer); - String xml = new String(out.toByteArray(), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + String xml = new String(out.toByteArray(), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); String innerXml = xml.replaceFirst("(?ms).*<databaseChangeLog[^>]*>", ""); innerXml = innerXml.replaceFirst(DATABASE_CHANGE_LOG_CLOSING_XML_TAG, ""); @@ -161,23 +160,19 @@ public void run() { } } - String lineSeparator = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration - .class).getOutputLineSeparator(); + String lineSeparator = GlobalConfiguration.OUTPUT_LINE_SEPARATOR.getCurrentValue(); if (foundEndTag) { randomAccessFile.seek(offset); randomAccessFile.writeBytes(" "); - randomAccessFile.write(innerXml.getBytes(LiquibaseConfiguration.getInstance().getConfiguration - (GlobalConfiguration.class).getOutputEncoding())); + randomAccessFile.write(innerXml.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); randomAccessFile.writeBytes(lineSeparator); randomAccessFile.writeBytes(DATABASE_CHANGE_LOG_CLOSING_XML_TAG + lineSeparator); } else { randomAccessFile.seek(0); long length = randomAccessFile.length(); randomAccessFile.seek(length); - randomAccessFile.write( - xml.getBytes(LiquibaseConfiguration.getInstance().getConfiguration - (GlobalConfiguration.class).getOutputEncoding())); + randomAccessFile.write(xml.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } } @@ -233,7 +228,7 @@ public void printNew(ChangeLogSerializer changeLogSerializer, File file) throws } try (FileOutputStream stream = new FileOutputStream(file); - PrintStream out = new PrintStream(stream, true, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())) { + PrintStream out = new PrintStream(stream, true, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())) { changeLogSerializer.write(changeSets, out); } } @@ -255,7 +250,7 @@ public List<ChangeSet> generateChangeSets() { DatabaseObjectComparator comparator = new DatabaseObjectComparator(); String created = null; - if (LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration.GENERATE_CHANGESET_CREATED_VALUES).getValue(Boolean.class)) { + if (GlobalConfiguration.GENERATE_CHANGESET_CREATED_VALUES.getCurrentValue()) { created = new SimpleDateFormat("yyyy-MM-dd HH:mmZ").format(new Date()); } @@ -858,7 +853,7 @@ public void setIdRoot(String idRoot) { protected String generateId(Change[] changes) { String desc = ""; - if (LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getGeneratedChangeSetIdsContainDescription()) { + if (GlobalConfiguration.GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION.getCurrentValue()) { if (!overriddenIdRoot) { //switch timestamp to a shorter string (last 4 digits in base 36 format). Still mostly unique, but shorter since we also now have mostly-unique descriptions of the changes this.idRoot = Long.toString(Long.decode(idRoot), 36); idRoot = idRoot.substring(idRoot.length() - 4); diff --git a/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataChangeGenerator.java b/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataChangeGenerator.java index 227d4820a8c..a8cb96201fc 100644 --- a/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataChangeGenerator.java +++ b/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataChangeGenerator.java @@ -3,9 +3,7 @@ import liquibase.change.Change; import liquibase.change.ColumnConfig; import liquibase.change.core.InsertDataChange; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; -import liquibase.database.AbstractJdbcDatabase; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.InformixDatabase; import liquibase.database.jvm.JdbcConnection; @@ -18,7 +16,6 @@ import liquibase.structure.DatabaseObject; import liquibase.structure.core.*; import liquibase.util.JdbcUtils; -import liquibase.util.StringUtil; import java.sql.ResultSet; import java.sql.SQLException; @@ -100,7 +97,7 @@ public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl outpu column.setValueDate((Date) value); } else if (value instanceof byte[]) { if (referenceDatabase instanceof InformixDatabase) { - column.setValue(new String((byte[]) value, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + column.setValue(new String((byte[]) value, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } column.setValueComputed(new DatabaseFunction("UNSUPPORTED FOR DIFF: BINARY DATA")); } else { // fall back to simple string diff --git a/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataExternalFileChangeGenerator.java b/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataExternalFileChangeGenerator.java index 706763bcb78..596c71c0916 100644 --- a/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataExternalFileChangeGenerator.java +++ b/liquibase-core/src/main/java/liquibase/diff/output/changelog/core/MissingDataExternalFileChangeGenerator.java @@ -3,8 +3,7 @@ import liquibase.change.Change; import liquibase.change.core.LoadDataChange; import liquibase.change.core.LoadDataColumnConfig; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.jvm.JdbcConnection; import liquibase.diff.output.DiffOutputControl; @@ -89,10 +88,7 @@ public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl outpu try ( FileOutputStream fileOutputStream = new FileOutputStream(fileName); OutputStreamWriter outputStreamWriter = new OutputStreamWriter( - fileOutputStream, - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getOutputEncoding() - ); + fileOutputStream, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); CSVWriter outputFile = new CSVWriter(new BufferedWriter(outputStreamWriter)); ) { @@ -146,7 +142,7 @@ public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl outpu LoadDataChange change = new LoadDataChange(); change.setFile(fileName); - change.setEncoding(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + change.setEncoding(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); if (outputControl.getIncludeCatalog()) { change.setCatalogName(table.getSchema().getCatalogName()); } diff --git a/liquibase-core/src/main/java/liquibase/exception/UnknownConfigurationType.java b/liquibase-core/src/main/java/liquibase/exception/UnknownConfigurationType.java new file mode 100644 index 00000000000..473472d20f8 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/exception/UnknownConfigurationType.java @@ -0,0 +1,15 @@ +package liquibase.exception; + +public class UnknownConfigurationType extends UnexpectedLiquibaseException { + public UnknownConfigurationType(String message) { + super(message); + } + + public UnknownConfigurationType(String message, Throwable cause) { + super(message, cause); + } + + public UnknownConfigurationType(Throwable cause) { + super(cause); + } +} diff --git a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java new file mode 100644 index 00000000000..007bb1c355d --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java @@ -0,0 +1,44 @@ +package liquibase.hub; + +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.AutoloadedConfigurations; + +/** + * Configuration container for global properties. + */ +public class HubConfiguration implements AutoloadedConfigurations { + + public static final ConfigurationDefinition<String> LIQUIBASE_HUB_API_KEY; + public static final ConfigurationDefinition<String> LIQUIBASE_HUB_URL; + public static final ConfigurationDefinition<String> LIQUIBASE_HUB_MODE; + + static { + ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase.hub"); + + LIQUIBASE_HUB_API_KEY = builder.define("apiKey", String.class) + .setDescription("Liquibase Hub API key for operations") + .setValueObfuscator(value -> { + if (value == null) { + return null; + } + return value.substring(0, 6) + "************"; + + }) + .build(); + + LIQUIBASE_HUB_URL = builder.define("url", String.class) + .setDescription("Liquibase Hub URL for operations") + .setDefaultValue("https://hub.liquibase.com") + .setValueHandler(value -> { + if (value == null) { + return null; + } + return value.toString().replaceFirst("(https?://[^/]+).*", "$1"); + }) + .build(); + LIQUIBASE_HUB_MODE = builder.define("mode", String.class) + .setDescription("Content to send to Liquibase Hub during operations. Values can be 'all', 'meta', or 'off'") + .setDefaultValue("all") + .build(); + } +} diff --git a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java index 166a5afaae6..427e9acd739 100644 --- a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java +++ b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java @@ -1,8 +1,7 @@ package liquibase.hub.core; import liquibase.Scope; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.hub.LiquibaseHubException; import liquibase.hub.LiquibaseHubObjectNotFoundException; import liquibase.hub.LiquibaseHubRedirectException; @@ -90,8 +89,7 @@ protected <T> T doDelete(String url, Class<T> returnType) throws LiquibaseHubExc } private URLConnection openConnection(String url) throws LiquibaseHubException { - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String apiKey = hubConfiguration.getLiquibaseHubApiKey(); + String apiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); try { final URLConnection connection = new URL(getHubUrl() + url).openConnection(); @@ -180,9 +178,12 @@ protected <T> T doRequest(String method, String url, Object requestBodyObject, String newHubUrl = connection.getHeaderField("Location"); newHubUrl = newHubUrl.replaceAll(url, ""); Scope.getCurrentScope().getLog(getClass()).info("Redirecting to URL: " + newHubUrl); - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - hubConfiguration.setLiquibaseHubUrl(newHubUrl); - throw new LiquibaseHubRedirectException(); + + //TODO + throw new RuntimeException("TODO: "); +// HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); +// hubConfiguration.setLiquibaseHubUrl(newHubUrl); +// throw new LiquibaseHubRedirectException(); } } @@ -230,8 +231,7 @@ protected <T> T doRequest(String method, String url, Object requestBodyObject, } public String getHubUrl() { - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - return hubConfiguration.getLiquibaseHubUrl(); + return HubConfiguration.LIQUIBASE_HUB_URL.getCurrentValue(); } diff --git a/liquibase-core/src/main/java/liquibase/hub/core/OnlineHubService.java b/liquibase-core/src/main/java/liquibase/hub/core/OnlineHubService.java index 8d7ac234e2b..459d18b0afa 100644 --- a/liquibase-core/src/main/java/liquibase/hub/core/OnlineHubService.java +++ b/liquibase-core/src/main/java/liquibase/hub/core/OnlineHubService.java @@ -3,8 +3,7 @@ import liquibase.Scope; import liquibase.changelog.ChangeSet; import liquibase.changelog.RanChangeSet; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.exception.LiquibaseException; import liquibase.hub.*; import liquibase.hub.model.*; @@ -58,7 +57,7 @@ public boolean isHubAvailable() { final Logger log = Scope.getCurrentScope().getLog(getClass()); final HubServiceFactory hubServiceFactory = Scope.getCurrentScope().getSingleton(HubServiceFactory.class); - if (LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("OFF")) { + if (HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("OFF")) { hubServiceFactory.setOfflineReason("property liquibase.hub.mode is 'OFF'. To send data to Liquibase Hub, please set it to \"all\""); this.available = false; } else if (getApiKey() == null) { @@ -75,7 +74,7 @@ public boolean isHubAvailable() { this.organizationId = organization.getId(); } - log.info("Connected to Liquibase Hub with an API Key '" + LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubApiKeySecureDescription() + "'"); + log.info("Connected to Liquibase Hub with an API Key '" + HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValueObfuscated() + "'"); this.available = true; } catch (LiquibaseHubException e) { if (e.getCause() instanceof ConnectException) { @@ -100,8 +99,7 @@ public boolean isHubAvailable() { } public String getApiKey() { - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - return StringUtil.trimToNull(hubConfiguration.getLiquibaseHubApiKey()); + return StringUtil.trimToNull(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()); } @Override @@ -405,7 +403,7 @@ public OperationEvent sendOperationEvent(Operation operation, OperationEvent ope } if (operationEvent.getOperationEventLog() != null) { - if (!LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("meta")) { + if (!HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("meta")) { requestParams.put("logs", operationEvent.getOperationEventLog().getLogMessage()); requestParams.put("logsTimestamp", operationEvent.getOperationEventLog().getTimestampLog()); } @@ -426,7 +424,7 @@ public void sendOperationChangeEvent(OperationChangeEvent operationChangeEvent) String[] generatedSql = null; String logs = null; Date logsTimestamp = operationChangeEvent.getLogsTimestamp(); - if (!LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("meta")) { + if (!HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("meta")) { changesetBody = operationChangeEvent.getChangesetBody(); generatedSql = operationChangeEvent.getGeneratedSql(); diff --git a/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java b/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java index 1c01fc53a0f..b8e7b49d601 100644 --- a/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java +++ b/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java @@ -7,8 +7,7 @@ import liquibase.changelog.visitor.AbstractChangeExecListener; import liquibase.changelog.visitor.ChangeExecListener; import liquibase.changelog.visitor.ChangeLogSyncListener; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.database.Database; import liquibase.exception.LiquibaseException; import liquibase.exception.PreconditionErrorException; @@ -160,10 +159,8 @@ private void updateHubForRollback(ChangeSet changeSet, String operationStatusType, String statusMessage) { if (operation == null) { - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String apiKey = StringUtil.trimToNull(hubConfiguration.getLiquibaseHubApiKey()); - boolean hubOn = - ! (LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("off")); + String apiKey = StringUtil.trimToNull(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()); + boolean hubOn = !(HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("off")); if (apiKey != null && hubOn) { String message = "Hub communication failure.\n" + @@ -302,10 +299,8 @@ private void updateHub(ChangeSet changeSet, // If not connected to Hub but we are supposed to be then show message // if (operation == null) { - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String apiKey = StringUtil.trimToNull(hubConfiguration.getLiquibaseHubApiKey()); - boolean hubOn = - ! (LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("off")); + String apiKey = StringUtil.trimToNull(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValueObfuscated()); + boolean hubOn = ! (HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("off")); if (apiKey != null && hubOn) { String message; if (databaseChangeLog.getChangeLogId() == null) { diff --git a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java index 5be67ece6f0..c9c17f8d98b 100644 --- a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java +++ b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java @@ -2,7 +2,7 @@ import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; +import liquibase.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.exception.DatabaseException; @@ -136,19 +136,15 @@ protected String getChangeLogFile() { protected boolean shouldRun() { LiquibaseConfiguration configuration = LiquibaseConfiguration.getInstance(); - GlobalConfiguration globalConfiguration = configuration.getConfiguration(GlobalConfiguration.class); - if (!globalConfiguration.getShouldRun()) { - log("Liquibase did not run because " + configuration.describeValueLookupLogic(globalConfiguration - .getProperty(GlobalConfiguration.SHOULD_RUN)) + " was set to false", Project.MSG_INFO); + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { + log("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getProperty() + " was set to false", Project.MSG_INFO); return false; } return true; } protected String getDefaultOutputEncoding() { - LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); - GlobalConfiguration globalConfiguration = liquibaseConfiguration.getConfiguration(GlobalConfiguration.class); - return globalConfiguration.getOutputEncoding(); + return GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); } /** diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java index b283451f3a7..9a1dc0bd6e7 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java @@ -9,9 +9,8 @@ import liquibase.command.CommandResult; import liquibase.command.LiquibaseCommand; import liquibase.command.core.*; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.database.Database; import liquibase.diff.compare.CompareControl; import liquibase.diff.output.DiffOutputControl; @@ -196,17 +195,12 @@ public Integer run() throws Exception { OldMain main = new OldMain(); try { - GlobalConfiguration globalConfiguration = LiquibaseConfiguration.getInstance().getConfiguration - (GlobalConfiguration.class); - - if (!globalConfiguration.getShouldRun()) { + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getUI().sendErrorMessage(( String.format(coreBundle.getString("did.not.run.because.param.was.set.to.false"), - LiquibaseConfiguration.getInstance().describeValueLookupLogic( - globalConfiguration.getProperty(GlobalConfiguration.SHOULD_RUN))))); + GlobalConfiguration.SHOULD_RUN.getProperty()))); return 0; } - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); if ((args.length == 0) || ((args.length == 1) && ("--" + OPTIONS.HELP).equals(args[0]))) { main.printHelp(System.out); @@ -346,14 +340,16 @@ public Integer run() throws Exception { // Store the Hub API key for later use // if (StringUtil.isNotEmpty(main.liquibaseHubApiKey)) { - hubConfiguration.setLiquibaseHubApiKey(main.liquibaseHubApiKey); + //TODO: +// hubConfiguration.setLiquibaseHubApiKey(main.liquibaseHubApiKey); } // // Store the Hub URL for later use // if (StringUtil.isNotEmpty(main.liquibaseHubUrl)) { - hubConfiguration.setLiquibaseHubUrl(main.liquibaseHubUrl); + //TODO: +// hubConfiguration.setLiquibaseHubUrl(main.liquibaseHubUrl); } main.applyDefaults(); @@ -399,7 +395,7 @@ public Integer run() throws Exception { } if (isHubEnabled(main.command) && - LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubApiKey() != null && + HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue() != null && !Scope.getCurrentScope().getSingleton(HubServiceFactory.class).isOnline()) { ui.sendMessage("WARNING: The command "+main.command+" operations were not synced with your Liquibase Hub account because: " + StringUtil.lowerCaseFirst(Scope.getCurrentScope().getSingleton(HubServiceFactory.class).getOfflineReason())); } @@ -1022,7 +1018,7 @@ protected void parsePropertiesFile(InputStream propertiesInputStream) throws IOE } String valueKey = splitKey[splitKey.length-1]; try { - LiquibaseConfiguration.getInstance().getConfiguration(namespace).setValue(valueKey, entry.getValue()); + //TODO: LiquibaseConfiguration.getInstance().getConfiguration(namespace).setValue(valueKey, entry.getValue()); } catch (Exception e) { if (strict) { @@ -1355,15 +1351,14 @@ protected void doMigration() throws Exception { // // Log setting for Hub properties // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - if (StringUtil.isNotEmpty(hubConfiguration.getLiquibaseHubApiKey())) { - LOG.fine("Liquibase Hub API Key: " + hubConfiguration.getLiquibaseHubApiKeySecureDescription()); + if (StringUtil.isNotEmpty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue())) { + LOG.fine("Liquibase Hub API Key: " + HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValueObfuscated()); } - if (StringUtil.isNotEmpty(hubConfiguration.getLiquibaseHubUrl())) { - LOG.fine("Liquibase Hub URL: " + hubConfiguration.getLiquibaseHubUrl()); + if (StringUtil.isNotEmpty(HubConfiguration.LIQUIBASE_HUB_URL.getCurrentValue())) { + LOG.fine("Liquibase Hub URL: " + HubConfiguration.LIQUIBASE_HUB_URL.getCurrentValue()); } - if (StringUtil.isNotEmpty(hubConfiguration.getLiquibaseHubMode())) { - LOG.fine("Liquibase Hub Mode: " + hubConfiguration.getLiquibaseHubMode()); + if (StringUtil.isNotEmpty(HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue())) { + LOG.fine("Liquibase Hub Mode: " + HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue()); } // @@ -1426,7 +1421,8 @@ protected void doMigration() throws Exception { // Set the global configuration option based on presence of the dataOutputDirectory // boolean b = dataOutputDirectory != null; - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); + //TODO: +// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); ObjectChangeFilter objectChangeFilter = null; CompareControl.ComputedSchemas computedSchemas = CompareControl.computeSchemas( @@ -1685,8 +1681,8 @@ protected void doMigration() throws Exception { executeSyncHub(database, liquibase); return; } else if (COMMANDS.DROP_ALL.equals(command)) { - String liquibaseHubApiKey = hubConfiguration.getLiquibaseHubApiKey(); - String hubMode = hubConfiguration.getLiquibaseHubMode(); + String liquibaseHubApiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); + String hubMode = HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue(); if (liquibaseHubApiKey != null && ! hubMode.toLowerCase().equals("off")) { if (hubConnectionId == null && changeLogFile == null) { String warningMessage = @@ -2068,8 +2064,7 @@ private OutputStream getOutputStream() throws IOException { } private Writer getOutputWriter() throws IOException { - String charsetName = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getOutputEncoding(); + String charsetName = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); return new OutputStreamWriter(getOutputStream(), charsetName); } diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java index 42ef6e7d70e..29e79e26b4e 100644 --- a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java @@ -4,10 +4,8 @@ import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.ConfigurationProperty; import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.core.DerbyDatabase; @@ -115,7 +113,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { ic = new InitialContext(); servletValueContainer = new ServletValueContainer(servletContext, ic); - LiquibaseConfiguration.getInstance().init(servletValueContainer); + //TODO: LiquibaseConfiguration.getInstance().init(servletValueContainer); failOnError = (String) servletValueContainer.getValue(LIQUIBASE_ONERROR_FAIL); if (checkPreconditions(servletContext, ic)) { @@ -147,10 +145,9 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { * </ol> */ private boolean checkPreconditions(ServletContext servletContext, InitialContext ic) { - GlobalConfiguration globalConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class); - if (!globalConfiguration.getShouldRun()) { + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run on " + hostName - + " because "+ LiquibaseConfiguration.getInstance().describeValueLookupLogic(globalConfiguration.getProperty(GlobalConfiguration.SHOULD_RUN)) + + " because "+ GlobalConfiguration.SHOULD_RUN.getProperty() + " was set to false"); return false; } @@ -178,10 +175,10 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext } } - if (globalConfiguration.getShouldRun() && globalConfiguration.getProperty(GlobalConfiguration.SHOULD_RUN).getWasOverridden()) { + if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getWasOverridden()) { shouldRun = true; servletContext.log("ignoring " + LIQUIBASE_HOST_INCLUDES + " and " - + LIQUIBASE_HOST_EXCLUDES + ", since " + LiquibaseConfiguration.getInstance().describeValueLookupLogic(globalConfiguration.getProperty(GlobalConfiguration.SHOULD_RUN)) + + LIQUIBASE_HOST_EXCLUDES + ", since " + GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getSourceDescription() + "=true"); } if (!shouldRun) { @@ -260,6 +257,11 @@ public void contextDestroyed(ServletContextEvent servletContextEvent) { protected class ServletValueContainer implements ConfigurationValueProvider { + @Override + public int getPrecedence() { + return 0; + } + private ServletContext servletContext; private InitialContext initialContext; @@ -269,13 +271,8 @@ public ServletValueContainer(ServletContext servletContext, InitialContext initi } @Override - public String describeValueLookupLogic(ConfigurationProperty property) { - return "JNDI, servlet container init parameter, and system property '"+property.getNamespace()+"."+property.getName()+"'"; - } - - @Override - public Object getValue(String namespace, String property) { - return getValue(namespace +"."+property); + public String describeValueLookupLogic(String property) { + return "JNDI, servlet container init parameter, and system property '"+property+"'"; } /** @@ -286,6 +283,7 @@ public Object getValue(String namespace, String property) { * <li>system properties</li> * </ul> */ + @Override public Object getValue(String prefixAndProperty) { // Try to get value from JNDI try { diff --git a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java index 476bb7fcfd4..d3f3348508c 100644 --- a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java +++ b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java @@ -4,9 +4,8 @@ import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.ConfigurationProperty; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.configuration.CurrentValueDetails; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.DatabaseFactory; @@ -252,12 +251,10 @@ public void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) { */ @Override public void afterPropertiesSet() throws LiquibaseException { - ConfigurationProperty shouldRunProperty = LiquibaseConfiguration.getInstance() - .getProperty(GlobalConfiguration.class, GlobalConfiguration.SHOULD_RUN); + final CurrentValueDetails<Boolean> shouldRunProperty = GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails(); - if (!shouldRunProperty.getValue(Boolean.class)) { - Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " + LiquibaseConfiguration - .getInstance().describeValueLookupLogic(shouldRunProperty) + " was set to false"); + if (!shouldRunProperty.getValue()) { + Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " +shouldRunProperty.getSourceDescription() + " was set to false"); return; } if (!shouldRun) { @@ -287,8 +284,7 @@ private void generateRollbackFile(Liquibase liquibase) throws LiquibaseException try ( FileOutputStream fileOutputStream = new FileOutputStream(rollbackFile); - Writer output = new OutputStreamWriter(fileOutputStream, LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class).getOutputEncoding()) + Writer output = new OutputStreamWriter(fileOutputStream, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()) ) { diff --git a/liquibase-core/src/main/java/liquibase/lockservice/StandardLockService.java b/liquibase-core/src/main/java/liquibase/lockservice/StandardLockService.java index 63e8dab4dd1..4204160f89b 100644 --- a/liquibase-core/src/main/java/liquibase/lockservice/StandardLockService.java +++ b/liquibase-core/src/main/java/liquibase/lockservice/StandardLockService.java @@ -2,8 +2,7 @@ import liquibase.Scope; import liquibase.change.Change; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.ObjectQuotingStrategy; import liquibase.database.core.DB2Database; @@ -68,8 +67,7 @@ public Long getChangeLogLockWaitTime() { if (changeLogLockPollRate != null) { return changeLogLockPollRate; } - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getDatabaseChangeLogLockWaitTime(); + return GlobalConfiguration.CHANGELOGLOCK_WAIT_TIME.getCurrentValue(); } @Override @@ -81,8 +79,7 @@ public Long getChangeLogLockRecheckTime() { if (changeLogLockRecheckTime != null) { return changeLogLockRecheckTime; } - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getDatabaseChangeLogLockPollRate(); + return GlobalConfiguration.CHANGELOGLOCK_POLL_RATE.getCurrentValue(); } @Override diff --git a/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java b/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java index 53fded1f43d..7de09661ed7 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java @@ -1,8 +1,8 @@ package liquibase.logging.core; import liquibase.AbstractExtensibleObject; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; +import liquibase.exception.UnknownConfigurationType; import liquibase.logging.LogMessageFilter; import liquibase.logging.Logger; @@ -81,7 +81,12 @@ public void debug(String message, Throwable e) { } protected String filterMessage(String message) { - if (filter == null || !LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getShouldFilterLogMessages()) { + try { + if (filter == null || !GlobalConfiguration.FILTER_LOG_MESSAGES.getCurrentValue()) { + return message; + } + } catch (UnknownConfigurationType unknownConfigurationType) { + //probably in initial scope bootstrap return message; } return filter.filterMessage(message); diff --git a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java index 9c3766578ae..6f6f45d1db6 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java @@ -1,20 +1,15 @@ package liquibase.logging.core; -import liquibase.Scope; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.logging.LogMessageFilter; -import liquibase.util.StringUtil; public class DefaultLogMessageFilter implements LogMessageFilter { @Override public String filterMessage(String message) { - final HubConfiguration configuration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - - final String liquibaseHubApiKey = StringUtil.trimToNull(configuration.getLiquibaseHubApiKey()); + final String liquibaseHubApiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); if (liquibaseHubApiKey != null) { - message = message.replace(liquibaseHubApiKey, configuration.getLiquibaseHubApiKeySecureDescription()); + message = message.replace(liquibaseHubApiKey, HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValueObfuscated()); } return message; diff --git a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java index 421d80f79a7..3a4a8af1836 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java @@ -1,53 +1,20 @@ package liquibase.logging.core; -import liquibase.configuration.AbstractConfigurationContainer; -import liquibase.exception.UnexpectedLiquibaseException; - -import java.util.logging.Level; +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.AutoloadedConfigurations; /** * Configuration container for {@link liquibase.logging.LogService} properties */ -public class DefaultLoggerConfiguration extends AbstractConfigurationContainer { - - public static final String LOG_LEVEL = "level"; +public class DefaultLoggerConfiguration implements AutoloadedConfigurations { - public DefaultLoggerConfiguration() { - super("liquibase.defaultlogger"); + public static ConfigurationDefinition<String> LOG_LEVEL; - getContainer().addProperty(LOG_LEVEL, String.class) + static { + ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase.defaultlogger"); + LOG_LEVEL = builder.define("level", String.class) .setDescription("Logging level") - .setDefaultValue("INFO"); - } - - public String getLogLevelName() { - return getContainer().getValue(LOG_LEVEL, String.class); - } - - - /** - * Transforms the strings DEBUG, INFO, WARNING, ERROR and OFF (case-insensitive) into the appropriate LogLevel. - * @return a value from the LogLevel enum - */ - public Level getLogLevel() { - String logLevel = getLogLevelName(); - - if ("fine".equalsIgnoreCase(logLevel) || "debug".equalsIgnoreCase(logLevel)) { - return Level.FINE; - } else if ("info".equalsIgnoreCase(logLevel)) { - return Level.INFO; - } else if ("warning".equalsIgnoreCase(logLevel)) { - return Level.WARNING; - } else if ("error".equalsIgnoreCase(logLevel) || "severe".equalsIgnoreCase(logLevel)) { - return Level.SEVERE; - } else if ("off".equalsIgnoreCase(logLevel)) { - return Level.OFF; - } else { - throw new UnexpectedLiquibaseException("Unknown log level: " + logLevel+". Valid levels are: debug, info, warning, error, off"); - } - } - public DefaultLoggerConfiguration setLogLevel(String name) { - getContainer().setValue(LOG_LEVEL, name); - return this; + .setDefaultValue("INFO") + .build(); } } diff --git a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserCofiguration.java b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserCofiguration.java deleted file mode 100644 index 917fb6aaead..00000000000 --- a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserCofiguration.java +++ /dev/null @@ -1,45 +0,0 @@ -package liquibase.parser; - -import liquibase.configuration.AbstractConfigurationContainer; - -/** - * Configuration container for properties applicable to most {@link liquibase.parser.ChangeLogParser} implementations - */ -public class ChangeLogParserCofiguration extends AbstractConfigurationContainer { - - public static final String SUPPORT_PROPERTY_ESCAPING = "supportPropertyEscaping"; - public static final String USE_PROCEDURE_SCHEMA = "useProcedureSchema"; - - public ChangeLogParserCofiguration() { - super("liquibase"); - - getContainer().addProperty(SUPPORT_PROPERTY_ESCAPING, Boolean.class) - .setDescription("Support escaping changelog parameters using a colon. Example: ${:user.name}") - .setDefaultValue(false) - .addAlias("enableEscaping"); - - getContainer().addProperty(USE_PROCEDURE_SCHEMA, Boolean.class) - .setDescription("If set to true (default value), createProcedure tags with a set schemaName will modify the procedure body with the given schema name.") - .setDefaultValue(true); - } - - public boolean getSupportPropertyEscaping() { - return getContainer().getValue(SUPPORT_PROPERTY_ESCAPING, Boolean.class); - } - - public ChangeLogParserCofiguration setSupportPropertyEscaping(boolean support) { - getContainer().setValue(SUPPORT_PROPERTY_ESCAPING, support); - return this; - } - - public boolean getUseProcedureSchema() { - return getContainer().getValue(USE_PROCEDURE_SCHEMA, Boolean.class); - } - - public ChangeLogParserCofiguration setUseProcedureSchema(boolean useSchema) { - getContainer().setValue(USE_PROCEDURE_SCHEMA, useSchema); - return this; - } - - -} diff --git a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java new file mode 100644 index 00000000000..c316bff468a --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java @@ -0,0 +1,28 @@ +package liquibase.parser; + +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.AutoloadedConfigurations; + +/** + * Configuration container for properties applicable to most {@link liquibase.parser.ChangeLogParser} implementations + */ +public class ChangeLogParserConfiguration implements AutoloadedConfigurations { + + public static final ConfigurationDefinition<Boolean> SUPPORT_PROPERTY_ESCAPING; + public static final ConfigurationDefinition<Boolean> USE_PROCEDURE_SCHEMA; + + static { + ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase"); + + SUPPORT_PROPERTY_ESCAPING = builder.define("supportPropertyEscaping", Boolean.class) + .setDescription("Support escaping changelog parameters using a colon. Example: ${:user.name}") + .setDefaultValue(false) + .addAlias("enableEscaping") + .build(); + + USE_PROCEDURE_SCHEMA = builder.define("useProcedureSchema", Boolean.class) + .setDescription("If set to true (default value), createProcedure tags with a set schemaName will modify the procedure body with the given schema name.") + .setDefaultValue(true) + .build(); + } +} diff --git a/liquibase-core/src/main/java/liquibase/parser/core/yaml/YamlSnapshotParser.java b/liquibase-core/src/main/java/liquibase/parser/core/yaml/YamlSnapshotParser.java index e0eb0ba9d5d..cec42c76a09 100644 --- a/liquibase-core/src/main/java/liquibase/parser/core/yaml/YamlSnapshotParser.java +++ b/liquibase-core/src/main/java/liquibase/parser/core/yaml/YamlSnapshotParser.java @@ -1,7 +1,6 @@ package liquibase.parser.core.yaml; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.OfflineConnection; @@ -67,7 +66,7 @@ private Map getParsedYamlFromInputStream(Yaml yaml, InputStream stream) throws L Map parsedYaml; try ( InputStreamReader inputStreamReader = new InputStreamReader( - stream, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding() + stream, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue() ); ) { parsedYaml = (Map) yaml.load(inputStreamReader); diff --git a/liquibase-core/src/main/java/liquibase/sdk/resource/MockResourceAccessor.java b/liquibase-core/src/main/java/liquibase/sdk/resource/MockResourceAccessor.java index 331d3c414c7..23828f2f052 100644 --- a/liquibase-core/src/main/java/liquibase/sdk/resource/MockResourceAccessor.java +++ b/liquibase-core/src/main/java/liquibase/sdk/resource/MockResourceAccessor.java @@ -1,7 +1,6 @@ package liquibase.sdk.resource; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.resource.AbstractResourceAccessor; import liquibase.resource.InputStreamList; @@ -28,7 +27,7 @@ public MockResourceAccessor(Map<String, String> contentByFileName) { public InputStreamList openStreams(String relativeTo, String streamPath) throws IOException { InputStream stream = null; if (contentByFileName.containsKey(streamPath)) { - stream = new ByteArrayInputStream(contentByFileName.get(streamPath).getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + stream = new ByteArrayInputStream(contentByFileName.get(streamPath).getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } if (stream == null) { return null; diff --git a/liquibase-core/src/main/java/liquibase/sdk/supplier/resource/ResourceSupplier.java b/liquibase-core/src/main/java/liquibase/sdk/supplier/resource/ResourceSupplier.java index 9902e87d85a..6acc06bb5d6 100644 --- a/liquibase-core/src/main/java/liquibase/sdk/supplier/resource/ResourceSupplier.java +++ b/liquibase-core/src/main/java/liquibase/sdk/supplier/resource/ResourceSupplier.java @@ -3,8 +3,7 @@ import liquibase.Scope; import liquibase.change.ChangeFactory; import liquibase.change.core.CreateProcedureChange; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.core.HsqlDatabase; import liquibase.resource.AbstractResourceAccessor; import liquibase.resource.InputStreamList; @@ -36,8 +35,7 @@ private static class SimpleResourceAccessor extends AbstractResourceAccessor{ @Override public InputStreamList openStreams(String relativeTo, String streamPath) throws IOException { InputStream stream = null; - String encoding = LiquibaseConfiguration.getInstance().getConfiguration( - GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); if (streamPath.toLowerCase().endsWith("csv")) { stream = new ByteArrayInputStream(USERS_CSV.getBytes(encoding)); } else if (streamPath.toLowerCase().endsWith("my-logic.sql")) { diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/formattedsql/FormattedSqlChangeLogSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/formattedsql/FormattedSqlChangeLogSerializer.java index dc7ebae0354..2548f1cb545 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/formattedsql/FormattedSqlChangeLogSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/formattedsql/FormattedSqlChangeLogSerializer.java @@ -4,8 +4,7 @@ import liquibase.change.Change; import liquibase.changelog.ChangeLogChild; import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.diff.output.changelog.DiffToChangeLog; @@ -105,7 +104,7 @@ public <T extends ChangeLogChild> void write(List<T> children, OutputStream out) builder.append("\n"); } - out.write(builder.toString().getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + out.write(builder.toString().getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/json/JsonChangeLogSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/json/JsonChangeLogSerializer.java index f05a26cb79e..aabfbc95235 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/json/JsonChangeLogSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/json/JsonChangeLogSerializer.java @@ -1,8 +1,7 @@ package liquibase.serializer.core.json; import liquibase.changelog.ChangeLogChild; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.serializer.core.yaml.YamlChangeLogSerializer; import liquibase.util.StringUtil; @@ -16,7 +15,7 @@ public class JsonChangeLogSerializer extends YamlChangeLogSerializer { @Override public <T extends ChangeLogChild> void write(List<T> children, OutputStream out) throws IOException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); writer.write("{ \"databaseChangeLog\": [\n"); int i = 0; for (T child : children) { diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializer.java index 0b7fce6816a..82a941bce93 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializer.java @@ -1,7 +1,6 @@ package liquibase.serializer.core.string; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.serializer.LiquibaseSerializable; import liquibase.serializer.SnapshotSerializer; @@ -149,7 +148,7 @@ private String serializeObject(Map collection, int indent) { @Override public void write(DatabaseSnapshot snapshot, OutputStream out) throws IOException { - out.write(serialize(snapshot, true).getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + out.write(serialize(snapshot, true).getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } @Override diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializerReadable.java b/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializerReadable.java index 6e722597386..5bff4c45934 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializerReadable.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/string/StringSnapshotSerializerReadable.java @@ -1,7 +1,6 @@ package liquibase.serializer.core.string; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.serializer.LiquibaseSerializable; @@ -221,7 +220,7 @@ private <T> List<T> sort(Collection objects, Comparator<T> comparator) { @Override public void write(DatabaseSnapshot snapshot, OutputStream out) throws IOException { - out.write(serialize(snapshot, true).getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + out.write(serialize(snapshot, true).getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } @Override diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/xml/XMLChangeLogSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/xml/XMLChangeLogSerializer.java index e0ebc6df074..e7b61da7009 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/xml/XMLChangeLogSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/xml/XMLChangeLogSerializer.java @@ -5,8 +5,7 @@ import liquibase.changelog.ChangeLogChild; import liquibase.changelog.ChangeSet; import liquibase.changelog.DatabaseChangeLog; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.parser.NamespaceDetails; import liquibase.parser.NamespaceDetailsFactory; @@ -168,7 +167,7 @@ public void append(ChangeSet changeSet, File changeLogFile) throws IOException { } else { existingChangeLog = existingChangeLog.replaceFirst("</databaseChangeLog>", serialize(changeSet, true) + "\n</databaseChangeLog>"); - StreamUtil.copy(new ByteArrayInputStream(existingChangeLog.getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())), out); + StreamUtil.copy(new ByteArrayInputStream(existingChangeLog.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())), out); } out.flush(); } diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlChangeLogSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlChangeLogSerializer.java index 219e3afc9af..428f25a57bb 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlChangeLogSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlChangeLogSerializer.java @@ -2,8 +2,7 @@ import liquibase.changelog.ChangeLogChild; import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.serializer.ChangeLogSerializer; import liquibase.serializer.LiquibaseSerializable; @@ -29,7 +28,7 @@ public <T extends ChangeLogChild> void write(List<T> children, OutputStream out) Map<String, Object> containerMap = new HashMap<>(); containerMap.put("databaseChangeLog", maps); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); writer.write(yaml.dumpAsMap(containerMap)); writer.write("\n"); writer.flush(); diff --git a/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlSnapshotSerializer.java b/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlSnapshotSerializer.java index dcbf2edf97e..db46511d645 100644 --- a/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlSnapshotSerializer.java +++ b/liquibase-core/src/main/java/liquibase/serializer/core/yaml/YamlSnapshotSerializer.java @@ -1,7 +1,6 @@ package liquibase.serializer.core.yaml; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.serializer.LiquibaseSerializable; import liquibase.serializer.SnapshotSerializer; @@ -33,7 +32,7 @@ public class YamlSnapshotSerializer extends YamlSerializer implements SnapshotSe @Override public void write(DatabaseSnapshot snapshot, OutputStream out) throws IOException { - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); writer.write(serialize(snapshot, true)); } diff --git a/liquibase-core/src/main/java/liquibase/servicelocator/StandardServiceLocator.java b/liquibase-core/src/main/java/liquibase/servicelocator/StandardServiceLocator.java index eae3d46d067..309bdfa4aa5 100644 --- a/liquibase-core/src/main/java/liquibase/servicelocator/StandardServiceLocator.java +++ b/liquibase-core/src/main/java/liquibase/servicelocator/StandardServiceLocator.java @@ -26,6 +26,7 @@ public <T> List<T> findInstances(Class<T> interfaceType) throws ServiceNotFoundE allInstances.add(service); } catch (Throwable e) { log.info("Cannot load service: "+e.getMessage()); + log.fine(e.getMessage(), e); } } diff --git a/liquibase-core/src/main/java/liquibase/snapshot/DatabaseSnapshot.java b/liquibase-core/src/main/java/liquibase/snapshot/DatabaseSnapshot.java index 4dc20cdc01a..c9d51c700aa 100644 --- a/liquibase-core/src/main/java/liquibase/snapshot/DatabaseSnapshot.java +++ b/liquibase-core/src/main/java/liquibase/snapshot/DatabaseSnapshot.java @@ -2,8 +2,7 @@ import liquibase.CatalogAndSchema; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.OfflineConnection; @@ -613,7 +612,7 @@ public void load(ParsedNode parsedNode, ResourceAccessor resourceAccessor) throw if ((value != null) && ObjectUtil.hasProperty(object, attr)) { if ((value instanceof byte[]) && ObjectUtil.getPropertyType(object, attr).equals(String .class)) { - value = new String((byte[]) value, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + value = new String((byte[]) value, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); } object.setAttribute(attr, null); ObjectUtil.setProperty(object, attr, value); diff --git a/liquibase-core/src/main/java/liquibase/sqlgenerator/core/CreateProcedureGenerator.java b/liquibase-core/src/main/java/liquibase/sqlgenerator/core/CreateProcedureGenerator.java index 845fdb8010a..4262b6f6d64 100644 --- a/liquibase-core/src/main/java/liquibase/sqlgenerator/core/CreateProcedureGenerator.java +++ b/liquibase-core/src/main/java/liquibase/sqlgenerator/core/CreateProcedureGenerator.java @@ -1,11 +1,10 @@ package liquibase.sqlgenerator.core; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.*; import liquibase.exception.ValidationErrors; -import liquibase.parser.ChangeLogParserCofiguration; +import liquibase.parser.ChangeLogParserConfiguration; import liquibase.sql.Sql; import liquibase.sql.UnparsedSql; import liquibase.sqlgenerator.SqlGeneratorChain; @@ -42,8 +41,7 @@ public Sql[] generateSql(CreateProcedureStatement statement, Database database, List<Sql> sql = new ArrayList<>(); String schemaName = statement.getSchemaName(); - if ((schemaName == null) && LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getAlwaysOverrideStoredLogicSchema()) { + if ((schemaName == null) && GlobalConfiguration.ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA.getCurrentValue()) { schemaName = database.getDefaultSchemaName(); } @@ -129,7 +127,7 @@ public static String removeTrailingDelimiter(String procedureText, String endDel */ public static void surroundWithSchemaSets(List<Sql> sql, String schemaName, Database database) { if ((StringUtil.trimToNull(schemaName) != null) && - !LiquibaseConfiguration.getInstance().getProperty(ChangeLogParserCofiguration.class, ChangeLogParserCofiguration.USE_PROCEDURE_SCHEMA).getValue(Boolean.class)) { + !ChangeLogParserConfiguration.USE_PROCEDURE_SCHEMA.getCurrentValue()) { String defaultSchema = database.getDefaultSchemaName(); if (database instanceof OracleDatabase) { sql.add(0, new UnparsedSql("ALTER SESSION SET CURRENT_SCHEMA=" + database.escapeObjectName(schemaName, Schema.class))); @@ -149,7 +147,7 @@ public static String addSchemaToText(String procedureText, String schemaName, St if (schemaName == null) { return procedureText; } - if ((StringUtil.trimToNull(schemaName) != null) && LiquibaseConfiguration.getInstance().getProperty(ChangeLogParserCofiguration.class, ChangeLogParserCofiguration.USE_PROCEDURE_SCHEMA).getValue(Boolean.class)) { + if ((StringUtil.trimToNull(schemaName) != null) && ChangeLogParserConfiguration.USE_PROCEDURE_SCHEMA.getCurrentValue()) { StringClauses parsedSql = SqlParser.parse(procedureText, true, true); StringClauses.ClauseIterator clauseIterator = parsedSql.getClauseIterator(); Object next = "START"; diff --git a/liquibase-core/src/main/java/liquibase/sqlgenerator/core/ReorganizeTableGeneratorDB2.java b/liquibase-core/src/main/java/liquibase/sqlgenerator/core/ReorganizeTableGeneratorDB2.java index 35d862a87e0..5c6e8a81a4c 100644 --- a/liquibase-core/src/main/java/liquibase/sqlgenerator/core/ReorganizeTableGeneratorDB2.java +++ b/liquibase-core/src/main/java/liquibase/sqlgenerator/core/ReorganizeTableGeneratorDB2.java @@ -1,7 +1,6 @@ package liquibase.sqlgenerator.core; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.core.DB2Database; import liquibase.exception.DatabaseException; @@ -33,7 +32,7 @@ public ValidationErrors validate(ReorganizeTableStatement reorganizeTableStateme @Override public Sql[] generateSql(ReorganizeTableStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { - if (!LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration.AUTO_REORG).getValue(Boolean.class)) { + if (!GlobalConfiguration.AUTO_REORG.getCurrentValue()) { return null; } diff --git a/liquibase-core/src/main/java/liquibase/structure/AbstractDatabaseObject.java b/liquibase-core/src/main/java/liquibase/structure/AbstractDatabaseObject.java index c02a108e225..fa439c0cf97 100644 --- a/liquibase-core/src/main/java/liquibase/structure/AbstractDatabaseObject.java +++ b/liquibase-core/src/main/java/liquibase/structure/AbstractDatabaseObject.java @@ -1,6 +1,6 @@ package liquibase.structure; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.parser.core.ParsedNode; import liquibase.parser.core.ParsedNodeException; @@ -237,6 +237,6 @@ public String toString() { * @return */ public boolean shouldIncludeCatalogInSpecification() { - return LiquibaseConfiguration.getInstance().shouldIncludeCatalogInSpecification(); + return GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION.getCurrentValue(); } } diff --git a/liquibase-core/src/main/java/liquibase/structure/core/Data.java b/liquibase-core/src/main/java/liquibase/structure/core/Data.java index 7209a7e3a8d..229a2b077b8 100644 --- a/liquibase-core/src/main/java/liquibase/structure/core/Data.java +++ b/liquibase-core/src/main/java/liquibase/structure/core/Data.java @@ -1,7 +1,6 @@ package liquibase.structure.core; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.structure.AbstractDatabaseObject; import liquibase.structure.DatabaseObject; @@ -9,7 +8,7 @@ public class Data extends AbstractDatabaseObject { @Override public boolean snapshotByDefault() { - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getShouldSnapshotData(); + return GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getCurrentValue(); } public Table getTable() { diff --git a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java index e25f452e967..2b9c4160b0c 100644 --- a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java +++ b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java @@ -2,9 +2,7 @@ import liquibase.AbstractExtensibleObject; import liquibase.Scope; -import liquibase.configuration.ConfigurationProperty; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.logging.Logger; import liquibase.util.StringUtil; @@ -95,9 +93,8 @@ public <T> T prompt(String prompt, T defaultValue, InputHandler<T> inputHandler, */ protected ConsoleWrapper getConsole() { if (console == null) { - final ConfigurationProperty headless = LiquibaseConfiguration.getInstance().getProperty(GlobalConfiguration.class, GlobalConfiguration.HEADLESS); - boolean headlessConfigValue = headless.getValue(Boolean.class); - boolean wasHeadlessOverridden = headless.getWasOverridden(); + boolean headlessConfigValue = GlobalConfiguration.HEADLESS.getCurrentValue(); + boolean wasHeadlessOverridden = GlobalConfiguration.HEADLESS.getCurrentValueDetails().getWasOverridden(); final Logger log = Scope.getCurrentScope().getLog(getClass()); diff --git a/liquibase-core/src/main/java/liquibase/util/FileUtil.java b/liquibase-core/src/main/java/liquibase/util/FileUtil.java index 53553d23433..815fe076eb3 100644 --- a/liquibase-core/src/main/java/liquibase/util/FileUtil.java +++ b/liquibase-core/src/main/java/liquibase/util/FileUtil.java @@ -1,9 +1,7 @@ package liquibase.util; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; -import liquibase.resource.ResourceAccessor; +import liquibase.GlobalConfiguration; import java.io.*; @@ -66,7 +64,7 @@ public static void write(String contents, File file) throws IOException { try ( FileOutputStream output = new FileOutputStream(file); ){ - StreamUtil.copy(new ByteArrayInputStream(contents.getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())), output); + StreamUtil.copy(new ByteArrayInputStream(contents.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())), output); } } diff --git a/liquibase-core/src/main/java/liquibase/util/MD5Util.java b/liquibase-core/src/main/java/liquibase/util/MD5Util.java index b89924b3e16..c5d95096c41 100644 --- a/liquibase-core/src/main/java/liquibase/util/MD5Util.java +++ b/liquibase-core/src/main/java/liquibase/util/MD5Util.java @@ -1,8 +1,7 @@ package liquibase.util; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.UnexpectedLiquibaseException; import java.io.InputStream; @@ -29,7 +28,7 @@ public static String computeMD5(String input) { MessageDigest digest; try { digest = MessageDigest.getInstance("MD5"); - digest.update(input.getBytes(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + digest.update(input.getBytes(GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } catch (Exception e) { throw new UnexpectedLiquibaseException(e); } diff --git a/liquibase-core/src/main/java/liquibase/util/StreamUtil.java b/liquibase-core/src/main/java/liquibase/util/StreamUtil.java index d626f8740a6..d4c48a2ff0e 100644 --- a/liquibase-core/src/main/java/liquibase/util/StreamUtil.java +++ b/liquibase-core/src/main/java/liquibase/util/StreamUtil.java @@ -2,8 +2,7 @@ import liquibase.Scope; import liquibase.changelog.ChangeSet; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.resource.ResourceAccessor; import java.io.*; @@ -15,7 +14,7 @@ public class StreamUtil { public static String getLineSeparator() { - return LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputLineSeparator(); + return GlobalConfiguration.OUTPUT_LINE_SEPARATOR.getCurrentValue(); } public static void copy(InputStream inputStream, OutputStream outputStream) throws IOException { diff --git a/liquibase-core/src/main/java/liquibase/util/xml/DefaultXmlWriter.java b/liquibase-core/src/main/java/liquibase/util/xml/DefaultXmlWriter.java index 972e6b81493..92c7ba51ece 100644 --- a/liquibase-core/src/main/java/liquibase/util/xml/DefaultXmlWriter.java +++ b/liquibase-core/src/main/java/liquibase/util/xml/DefaultXmlWriter.java @@ -1,7 +1,6 @@ package liquibase.util.xml; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import org.w3c.dom.Document; import javax.xml.transform.OutputKeys; @@ -29,10 +28,10 @@ public void write(Document doc, OutputStream outputStream) throws IOException { Transformer transformer = factory.newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + transformer.setOutputProperty(OutputKeys.ENCODING, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); //need to nest outputStreamWriter to get around JDK 5 bug. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 - OutputStreamWriter writer = new OutputStreamWriter(outputStream, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + OutputStreamWriter writer = new OutputStreamWriter(outputStream, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); transformer.transform(new DOMSource(doc), new StreamResult(writer)); writer.flush(); writer.close(); diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations new file mode 100644 index 00000000000..f2b13f158ab --- /dev/null +++ b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations @@ -0,0 +1,4 @@ +liquibase.GlobalConfiguration +liquibase.hub.HubConfiguration +liquibase.logging.core.DefaultLoggerConfiguration +liquibase.parser.ChangeLogParserConfiguration diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider new file mode 100644 index 00000000000..9baa7f11e63 --- /dev/null +++ b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider @@ -0,0 +1,2 @@ +liquibase.configuration.core.EnvironmentVariableProvider +liquibase.configuration.core.SystemPropertyProvider diff --git a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy index becc0d64f67..34f79af0bd3 100644 --- a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy @@ -2,7 +2,7 @@ package liquibase.command.core import liquibase.Liquibase import liquibase.Scope -import liquibase.configuration.HubConfiguration +import liquibase.hub.HubConfiguration import liquibase.configuration.LiquibaseConfiguration import liquibase.database.core.MockDatabase import liquibase.hub.HubService diff --git a/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy b/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy index f12be79e3bb..b2f420fc834 100644 --- a/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy @@ -2,7 +2,7 @@ package liquibase.command.core import liquibase.Scope import liquibase.changelog.DatabaseChangeLog -import liquibase.configuration.HubConfiguration +import liquibase.hub.HubConfiguration import liquibase.configuration.LiquibaseConfiguration import liquibase.hub.HubService import liquibase.hub.HubServiceFactory diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy index 9a021f2be6e..166be50c4eb 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy @@ -1,6 +1,6 @@ package liquibase.configuration - +import liquibase.hub.HubConfiguration import spock.lang.Specification import spock.lang.Unroll diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy new file mode 100644 index 00000000000..489f1159e51 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy @@ -0,0 +1,51 @@ +package liquibase.configuration.core + +import spock.lang.Specification +import spock.lang.Unroll + +class EnvironmentVariableProviderTest extends Specification { + + @Unroll + def "GetValue"() { + when: + def env = [ + "lower" : "saw lower", + "lower_underscore": "saw lower underscore", + "lower.dot" : "saw lower dot", + "lower_under.dot" : "saw lower word dot", + "UPPER" : "saw upper", + "UPPER_UNDERSCORE": "saw upper underscore", + "UPPER.DOT" : "saw upper dot", + "UPPER_UNDER_DOT" : "saw under dot", + ] + def provider = new EnvironmentVariableProvider() { + @Override + protected String getEnvironmentVariable(String name) { + return env[name] + } + } + + then: + provider.getValue(key) == expected + + where: + key | expected + "lower" | "saw lower" + "LOWER" | "saw lower" + "upper" | "saw upper" + "UPPER" | "saw upper" + "lower_underscore" | "saw lower underscore" + "lower.underscore" | "saw lower underscore" + "lower_UNDERSCORE" | "saw lower underscore" + "upper_underscore" | "saw upper underscore" + "UPPER_UNDERSCORE" | "saw upper underscore" + "upper_dot" | null + "upper.dot" | "saw upper dot" + "UPPER.DOT" | "saw upper dot" + "lower_under.dot" | "saw lower word dot" + "LOWER.UNDER.dot" | null + "LOWER_UNDER_DOT" | null + "invalid" | null + null | null + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy b/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy index 2d137049845..6e14f61235a 100644 --- a/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy @@ -1,6 +1,6 @@ package liquibase.hub.core -import liquibase.configuration.HubConfiguration +import liquibase.hub.HubConfiguration import liquibase.configuration.LiquibaseConfiguration import liquibase.hub.model.Connection import liquibase.hub.model.OperationChangeEvent diff --git a/liquibase-core/src/test/groovy/liquibase/sqlgenerator/core/CreateProcedureGeneratorTest.groovy b/liquibase-core/src/test/groovy/liquibase/sqlgenerator/core/CreateProcedureGeneratorTest.groovy index b33962a95f8..4db63dad73c 100644 --- a/liquibase-core/src/test/groovy/liquibase/sqlgenerator/core/CreateProcedureGeneratorTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/sqlgenerator/core/CreateProcedureGeneratorTest.groovy @@ -1,11 +1,8 @@ package liquibase.sqlgenerator.core -import liquibase.configuration.LiquibaseConfiguration + import liquibase.database.core.MSSQLDatabase import liquibase.database.core.OracleDatabase -import liquibase.parser.ChangeLogParserCofiguration -import liquibase.sqlgenerator.SqlGeneratorFactory -import liquibase.statement.core.CreateProcedureStatement import spock.lang.Specification import spock.lang.Unroll diff --git a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java index cb3fc6330bd..089f37755f2 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java @@ -1,7 +1,7 @@ package liquibase.changelog; import liquibase.configuration.LiquibaseConfiguration; -import liquibase.parser.ChangeLogParserCofiguration; +import liquibase.parser.ChangeLogParserConfiguration; import org.junit.Before; import org.junit.Test; @@ -56,66 +56,73 @@ public void expandExpressions_nomatchExpression() { @Test public void expandExpressions_escapedSimple() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("${user.name}", handler.expandExpressions("${:user.name}", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("${user.name}", handler.expandExpressions("${:user.name}", null)); } @Test public void expandExpressions_escapedNonGreedy() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("${user.name}${user.name}", handler.expandExpressions("${:user.name}${:user.name}", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("${user.name}${user.name}", handler.expandExpressions("${:user.name}${:user.name}", null)); } @Test public void expandExpressions_escapedMultipleSimple() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("${user.name} and ${user.name} are literals", - handler.expandExpressions("${:user.name} and ${:user.name} are literals", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("${user.name} and ${user.name} are literals", +// handler.expandExpressions("${:user.name} and ${:user.name} are literals", null)); } @Test public void expandExpressions_escapedMultipleComplex() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("${user.name} and ${user.name} are literals but this isn't: " + System.getProperty("user.name"), - handler.expandExpressions("${:user.name} and ${:user.name} are literals but this isn't: ${user.name}", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("${user.name} and ${user.name} are literals but this isn't: " + System.getProperty("user.name"), +// handler.expandExpressions("${:user.name} and ${:user.name} are literals but this isn't: ${user.name}", null)); } @Test public void expandExpressions_escapedBeforeVariable() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("${user.name} is a literal, " + System.getProperty("user.name") + " is a variable", - handler.expandExpressions("${:user.name} is a literal, ${user.name} is a variable", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("${user.name} is a literal, " + System.getProperty("user.name") + " is a variable", +// handler.expandExpressions("${:user.name} is a literal, ${user.name} is a variable", null)); } @Test public void expandExpressions_escapedAfterVariable() { - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals(System.getProperty("user.name") + " is a variable, ${user.name} is a literal", - handler.expandExpressions("${user.name} is a variable, ${:user.name} is a literal", null)); + //TODO +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals(System.getProperty("user.name") + " is a variable, ${user.name} is a literal", +// handler.expandExpressions("${user.name} is a variable, ${:user.name} is a literal", null)); } @Test public void expandExpressions_escapedMultipleComplexVariant() { - changeLogParameters.set("a", "Value A"); - changeLogParameters.set("b", "Value B"); - - LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserCofiguration.class).setSupportPropertyEscaping(true); - this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); - - assertEquals("Value A is a variable, ${a} and ${b} are literals but this isn't: Value B", - handler.expandExpressions("${a} is a variable, ${:a} and ${:b} are literals but this isn't: ${b}", null)); + //TODO +// changeLogParameters.set("a", "Value A"); +// changeLogParameters.set("b", "Value B"); +// +// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); +// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); +// +// assertEquals("Value A is a variable, ${a} and ${b} are literals but this isn't: Value B", +// handler.expandExpressions("${a} is a variable, ${:a} and ${:b} are literals but this isn't: ${b}", null)); } } diff --git a/liquibase-core/src/test/java/liquibase/configuration/ContextTest.java b/liquibase-core/src/test/java/liquibase/configuration/ContextTest.java deleted file mode 100644 index 9a9fdd47f7d..00000000000 --- a/liquibase-core/src/test/java/liquibase/configuration/ContextTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package liquibase.configuration; - -import junit.framework.TestCase; -import liquibase.exception.UnexpectedLiquibaseException; -import org.junit.Before; -import org.junit.Test; - -import static junit.framework.TestCase.assertNull; -import static org.junit.Assert.assertEquals; - -public class ContextTest { - - private AbstractConfigurationContainer exampleConfiguration; - - @Before - public void before() { - System.clearProperty("liquibase.example.propertyBooleanNoDefault"); - System.clearProperty("liquibase.example.propertyBooleanDefaultFalse"); - System.clearProperty("liquibase.example.property.default.true"); - - exampleConfiguration = new ExampleContext(); - exampleConfiguration.init(new SystemPropertyProvider()); - } - - @Test - public void getValue() { - assertNull(exampleConfiguration.getContainer().getValue("propertyBooleanNoDefault", Boolean.class)); - assertEquals(Boolean.TRUE, exampleConfiguration.getContainer().getValue("propertyBooleanDefaultTrue", Boolean.class)); - assertEquals(Boolean.FALSE, exampleConfiguration.getContainer().getValue("propertyBooleanDefaultFalse", Boolean.class)); - - } - - @Test(expected = IllegalArgumentException.class) - public void setValue_wrongType() { - exampleConfiguration.getContainer().setValue("propertyIntegerDefaultOne", "a"); - } - - @Test - public void getValue_defaultFromSystemProperties() { - System.setProperty("liquibase.example.propertyBooleanNoDefault", "true"); - System.setProperty("liquibase.example.propertyBooleanDefaultFalse", "true"); - System.setProperty("liquibase.example.property.default.true", "false"); - ExampleContext exampleContext = new ExampleContext(); - exampleContext.init(new SystemPropertyProvider()); - - TestCase.assertEquals(Boolean.TRUE, exampleContext.getContainer().getValue("propertyBooleanNoDefault", Boolean.class)); - TestCase.assertEquals(Boolean.TRUE, exampleContext.getContainer().getValue("propertyBooleanDefaultFalse", Boolean.class)); - TestCase.assertEquals(Boolean.FALSE, exampleContext.getContainer().getValue("propertyBooleanDefaultTrue", Boolean.class)); - } - - private static class ExampleContext extends AbstractConfigurationContainer { - private ExampleContext() { - super("liquibase.example"); - - getContainer().addProperty("propertyBooleanNoDefault", Boolean.class).setDescription("An example boolean property with no default"); - getContainer().addProperty("propertyBooleanDefaultTrue", Boolean.class).setDefaultValue(true).addAlias("property.default.true"); - getContainer().addProperty("propertyBooleanDefaultFalse", Boolean.class).setDefaultValue(false); - getContainer().addProperty("propertyIntegerDefaultOne", Integer.class).setDefaultValue(1); - } - } - - -} diff --git a/liquibase-core/src/test/java/liquibase/configuration/LiquibaseConfigurationTest.java b/liquibase-core/src/test/java/liquibase/configuration/LiquibaseConfigurationTest.java deleted file mode 100644 index 85b6382c71f..00000000000 --- a/liquibase-core/src/test/java/liquibase/configuration/LiquibaseConfigurationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package liquibase.configuration; - -import org.junit.Assert; -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; - -public class LiquibaseConfigurationTest { - - @Test - public void getContext_defaultSetup() { - LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); - GlobalConfiguration globalConfiguration = liquibaseConfiguration.getConfiguration(GlobalConfiguration.class); - - assertNotNull(globalConfiguration); - - assertSame("Multiple calls to getConfiguration should return the same instance", globalConfiguration, liquibaseConfiguration.getConfiguration(GlobalConfiguration.class)); - } -} diff --git a/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java b/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java index 8842f49b09b..17aa2c19380 100644 --- a/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java +++ b/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java @@ -1,7 +1,8 @@ package liquibase.datatype; -import liquibase.configuration.GlobalConfiguration; +import liquibase.Scope; import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.core.MSSQLDatabase; import liquibase.datatype.core.ClobType; import org.junit.After; @@ -22,80 +23,62 @@ public void reset() { } @Test - public void mssqlTextToVarcharTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.TRUE); - - ClobType ct = new ClobType(); - ct.finishInitialization("Text"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("varchar (max)", dbType.getType()); + public void mssqlTextToVarcharTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), true, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("Text"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("varchar (max)", dbType.getType()); + }); } @Test - public void mssqlEscapedTextToVarcharTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.TRUE); - - ClobType ct = new ClobType(); - ct.finishInitialization("[Text]"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("varchar (max)", dbType.getType()); + public void mssqlEscapedTextToVarcharTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), true, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("[Text]"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("varchar (max)", dbType.getType()); + }); } @Test - public void mssqlTextToVarcharNoConvertTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.FALSE); - - ClobType ct = new ClobType(); - ct.finishInitialization("Text"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("varchar (max)", dbType.getType()); + public void mssqlTextToVarcharNoConvertTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("Text"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("varchar (max)", dbType.getType()); + }); } @Test - public void mssqlNTextToNVarcharNoConvertTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.FALSE); - - ClobType ct = new ClobType(); - ct.finishInitialization("NText"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("nvarchar (max)", dbType.getType()); + public void mssqlNTextToNVarcharNoConvertTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("NText"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("nvarchar (max)", dbType.getType()); + }); } @Test - public void mssqlEscapedTextToVarcharNoConvertTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.FALSE); - - ClobType ct = new ClobType(); - ct.finishInitialization("[Text]"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("varchar (max)", dbType.getType()); + public void mssqlEscapedTextToVarcharNoConvertTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("[Text]"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("varchar (max)", dbType.getType()); + }); } @Test - public void mssqlEscapedNTextToNVarcharNoConvertTest() { - LiquibaseConfiguration.getInstance() - .getConfiguration(GlobalConfiguration.class) - .getProperty(GlobalConfiguration.CONVERT_DATA_TYPES) - .setValue(Boolean.FALSE); - - ClobType ct = new ClobType(); - ct.finishInitialization("[NText]"); - DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); - assertEquals("nvarchar (max)", dbType.getType()); + public void mssqlEscapedNTextToNVarcharNoConvertTest() throws Exception { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + ClobType ct = new ClobType(); + ct.finishInitialization("[NText]"); + DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); + assertEquals("nvarchar (max)", dbType.getType()); + }); } } diff --git a/liquibase-core/src/test/java/liquibase/integration/ant/AbstractAntTaskTest.java b/liquibase-core/src/test/java/liquibase/integration/ant/AbstractAntTaskTest.java index f119e0ea8fa..b6e32cf4c88 100644 --- a/liquibase-core/src/test/java/liquibase/integration/ant/AbstractAntTaskTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/ant/AbstractAntTaskTest.java @@ -2,8 +2,7 @@ import liquibase.Scope; import liquibase.TestScopeManager; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import org.junit.BeforeClass; import java.io.UnsupportedEncodingException; @@ -22,7 +21,7 @@ protected static void setProperties() { final String resourceName = "/" + name.replace('.', '/') + ".class"; String absoluteFilePath = BaseLiquibaseTask.class.getResource(resourceName).getFile(); try { - absoluteFilePath = URLDecoder.decode(absoluteFilePath, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + absoluteFilePath = URLDecoder.decode(absoluteFilePath, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Missing UTF-8 encoding in JVM.", e); } @@ -35,7 +34,7 @@ protected static void setProperties() { final String testResourceName = "/" + testClassName.replace('.', '/') + ".class"; String testAbsoluteFilePath = AbstractAntTaskTest.class.getResource(testResourceName).getFile(); try { - testAbsoluteFilePath = URLDecoder.decode(testAbsoluteFilePath, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + testAbsoluteFilePath = URLDecoder.decode(testAbsoluteFilePath, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Missing UTF-8 encoding in JVM.", e); } diff --git a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java index d4d0284d44b..c34a29c35d1 100644 --- a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java @@ -1,7 +1,5 @@ package liquibase.integration.commandline; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.exception.CommandLineParsingException; import liquibase.util.StringUtil; import org.junit.Assert; @@ -129,15 +127,15 @@ public void startWithoutParameters() throws Exception { assertTrue("We just want to survive until this point", true); } - @Test - public void globalConfigurationSaysDoNotRun() throws Exception { - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .setValue("shouldRun", false); - int errorLevel = OldMain.run(new String[0]); - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .setValue("shouldRun", true); - assertEquals(errorLevel, 0); // If it SHOULD run, and we would call without parameters, we would get -1 - } +// @Test +// public void globalConfigurationSaysDoNotRun() throws Exception { +// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) +// .setValue("shouldRun", false); +// int errorLevel = OldMain.run(new String[0]); +// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) +// .setValue("shouldRun", true); +// assertEquals(errorLevel, 0); // If it SHOULD run, and we would call without parameters, we would get -1 +// } // @Test // public void mockedSnapshotRun() throws Exception { diff --git a/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy b/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy index 4011b180a0c..349fa44e81e 100644 --- a/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy +++ b/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy @@ -1,7 +1,6 @@ package liquibase.hub -import liquibase.configuration.HubConfiguration import liquibase.configuration.LiquibaseConfiguration import liquibase.hub.core.OnlineHubService import liquibase.hub.model.Connection diff --git a/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java b/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java index 4d4c74b795a..8d528c8ae41 100644 --- a/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java +++ b/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java @@ -3,8 +3,6 @@ import liquibase.*; import liquibase.changelog.ChangeLogHistoryServiceFactory; import liquibase.changelog.ChangeSet; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.DatabaseFactory; @@ -130,11 +128,10 @@ protected AbstractIntegrationTest(String changelogDir, Database dbms) throws Exc String testHubApiKey = integrationTestProperties.getProperty("integration.test.hub.apiKey"); if (testHubApiKey != null) { - HubConfiguration hubConfiguration = - LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - hubConfiguration.setLiquibaseHubApiKey(testHubApiKey); - String testHubUrl = integrationTestProperties.getProperty("integration.test.hub.url"); - hubConfiguration.setLiquibaseHubUrl(testHubUrl); + //TODO: +// hubConfiguration.setLiquibaseHubApiKey(testHubApiKey); +// String testHubUrl = integrationTestProperties.getProperty("integration.test.hub.url"); +// hubConfiguration.setLiquibaseHubUrl(testHubUrl); } Scope.setScopeManager(new TestScopeManager()); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java index 843768de7e3..11180a22d21 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java @@ -4,15 +4,12 @@ import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.exception.LiquibaseException; import liquibase.resource.ClassLoaderResourceAccessor; import liquibase.resource.CompositeResourceAccessor; import liquibase.resource.FileSystemResourceAccessor; import liquibase.resource.ResourceAccessor; -import liquibase.util.StringUtil; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -108,16 +105,18 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti // // Store the Hub API key and URL for later use // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - if (StringUtil.isNotEmpty(hubApiKey)) { - hubConfiguration.setLiquibaseHubApiKey(hubApiKey); - } - if (StringUtil.isNotEmpty(hubUrl)) { - hubConfiguration.setLiquibaseHubUrl(hubUrl); - } - if (StringUtil.isNotEmpty(hubMode)) { - hubConfiguration.setLiquibaseHubMode(hubMode); - } + //TODO: + throw new RuntimeException("TODO"); +// HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); +// if (StringUtil.isNotEmpty(hubApiKey)) { +// hubConfiguration.setLiquibaseHubApiKey(hubApiKey); +// } +// if (StringUtil.isNotEmpty(hubUrl)) { +// hubConfiguration.setLiquibaseHubUrl(hubUrl); +// } +// if (StringUtil.isNotEmpty(hubMode)) { +// hubConfiguration.setLiquibaseHubMode(hubMode); +// } } @Override diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java index 0c820153a61..d9214d3eba3 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java @@ -2,7 +2,7 @@ import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; +import liquibase.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.exception.DatabaseException; @@ -294,7 +294,7 @@ protected boolean hasProLicense() { protected Writer getOutputWriter(final File outputFile) throws IOException { if (outputFileEncoding == null) { getLog().info("Char encoding not set! The created file will be system dependent!"); - return new OutputStreamWriter(new FileOutputStream(outputFile), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); + return new OutputStreamWriter(new FileOutputStream(outputFile), GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue()); } getLog().debug("Writing output file with [" + outputFileEncoding + "] file encoding."); return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), outputFileEncoding)); @@ -319,9 +319,8 @@ public void execute() throws MojoExecutionException, MojoFailureException { LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); - if (!liquibaseConfiguration.getConfiguration(GlobalConfiguration.class).getShouldRun()) { - getLog().info("Liquibase did not run because " + liquibaseConfiguration.describeValueLookupLogic - (GlobalConfiguration.class, GlobalConfiguration.SHOULD_RUN) + " was set to false"); + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { + getLog().info("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getProperty() + " was set to false"); return; } if (skip) { diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDropAll.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDropAll.java index 1a81afbbb06..8e56fae897a 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDropAll.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDropAll.java @@ -2,10 +2,8 @@ import liquibase.CatalogAndSchema; import liquibase.Liquibase; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.hub.HubConfiguration; import liquibase.exception.LiquibaseException; -import liquibase.exception.UnexpectedLiquibaseException; import org.apache.maven.plugin.MojoFailureException; import java.util.ArrayList; @@ -45,9 +43,8 @@ protected void checkRequiredParametersAreSpecified() throws MojoFailureException // // Override because changeLogFile is not required // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - String liquibaseHubApiKey = hubConfiguration.getLiquibaseHubApiKey(); - String hubMode = hubConfiguration.getLiquibaseHubMode(); + String liquibaseHubApiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); + String hubMode = HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue(); if (liquibaseHubApiKey != null && ! hubMode.toLowerCase().equals("off")) { if (hubConnectionId == null && changeLogFile == null) { String errorMessage = diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java index 2f46f1f527e..ab4f08cad03 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java @@ -1,21 +1,14 @@ package org.liquibase.maven.plugins; import liquibase.Liquibase; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.diff.output.DiffOutputControl; import liquibase.diff.output.StandardObjectChangeFilter; import liquibase.exception.LiquibaseException; import liquibase.exception.UnexpectedLiquibaseException; -import liquibase.integration.commandline.CommandLineUtils; -import liquibase.util.StringUtil; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; - /** * <p>Generates a changelog based on the current database schema. Typically used when * beginning to use Liquibase on an existing project and database schema.</p> @@ -117,13 +110,15 @@ protected void performLiquibaseTask(Liquibase liquibase) // Set the global configuration option based on presence of the dataOutputDirectory // boolean b = dataDir != null; - LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); + //todo + throw new RuntimeException("TODO"); +// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); - CommandLineUtils.doGenerateChangeLog(outputChangeLogFile, database, defaultCatalogName, defaultSchemaName, StringUtil.trimToNull(diffTypes), - StringUtil.trimToNull(changeSetAuthor), StringUtil.trimToNull(changeSetContext), StringUtil.trimToNull(dataDir), diffOutputControl); - getLog().info("Output written to Change Log file, " + outputChangeLogFile); +// CommandLineUtils.doGenerateChangeLog(outputChangeLogFile, database, defaultCatalogName, defaultSchemaName, StringUtil.trimToNull(diffTypes), +// StringUtil.trimToNull(changeSetAuthor), StringUtil.trimToNull(changeSetContext), StringUtil.trimToNull(dataDir), diffOutputControl); +// getLog().info("Output written to Change Log file, " + outputChangeLogFile); } - catch (IOException | ParserConfigurationException e) { + catch (Throwable e) { throw new LiquibaseException(e); } } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseReportStatusMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseReportStatusMojo.java index 2c59f167c53..9bb57b744df 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseReportStatusMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseReportStatusMojo.java @@ -3,8 +3,7 @@ import liquibase.Contexts; import liquibase.LabelExpression; import liquibase.Liquibase; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.exception.LiquibaseException; import liquibase.exception.UnexpectedLiquibaseException; @@ -23,7 +22,7 @@ public class LiquibaseReportStatusMojo extends AbstractLiquibaseChangeLogMojo { protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { try { - liquibase.reportStatus(true, new Contexts(contexts), new LabelExpression(labels), new OutputStreamWriter(System.out, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding())); + liquibase.reportStatus(true, new Contexts(contexts), new LabelExpression(labels), new OutputStreamWriter(System.out, GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue())); } catch (UnsupportedEncodingException e) { throw new UnexpectedLiquibaseException(e); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java index 6e9122fc347..458a8a7b40d 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneChangeSetSQL.java @@ -4,8 +4,7 @@ import liquibase.Scope; import liquibase.changelog.ChangeLogParameters; import liquibase.command.*; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.exception.LiquibaseException; import org.apache.maven.plugin.MojoExecutionException; @@ -163,8 +162,7 @@ private void closeOutputWriter(Writer outputWriter) throws IOException { } private Writer createOutputWriter() throws IOException { - String charsetName = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getOutputEncoding(); + String charsetName = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); return new OutputStreamWriter(getOutputStream(), charsetName); } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java index a78b0f52a69..c752bb9d33c 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseRollbackOneUpdateSQL.java @@ -4,8 +4,7 @@ import liquibase.Scope; import liquibase.changelog.ChangeLogParameters; import liquibase.command.*; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.exception.LiquibaseException; import org.apache.maven.plugin.MojoExecutionException; @@ -121,8 +120,7 @@ private void closeOutputWriter(Writer outputWriter) throws IOException { } private Writer createOutputWriter() throws IOException { - String charsetName = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) - .getOutputEncoding(); + String charsetName = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); return new OutputStreamWriter(getOutputStream(), charsetName); } From 37f10be41753017afa388312f1db442fc0c8379d Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 2 Feb 2021 16:35:28 -0600 Subject: [PATCH 05/17] Refactoring LiquibaseConfiguration system --- .../integration/cdi/CDILiquibase.java | 4 +- .../integration/cdi/CDILiquibaseTest.java | 1 - .../java/liquibase/GlobalConfiguration.java | 8 +- .../AutoloadedConfigurations.java | 5 - .../ConfigurationDefinition.java | 151 +++++++++++++----- .../ConfigurationDefinitionHolder.java | 9 ++ .../ConfigurationValueProvider.java | 18 ++- .../liquibase/configuration/CurrentValue.java | 53 ++++++ .../configuration/CurrentValueDetails.java | 36 +++-- .../CurrentValueSourceDetails.java | 32 ++++ .../configuration/LiquibaseConfiguration.java | 84 +++++----- .../core/ScopeValueProvider.java | 38 +++++ ...va => SystemEnvironmentValueProvider.java} | 18 +-- .../core/SystemPropertyProvider.java | 44 ----- .../core/SystemPropertyValueProvider.java | 51 ++++++ .../database/AbstractJdbcDatabase.java | 4 +- .../java/liquibase/hub/HubConfiguration.java | 4 +- .../integration/ant/BaseLiquibaseTask.java | 2 +- .../integration/commandline/OldMain.java | 2 +- .../servlet/LiquibaseServletListener.java | 61 +++---- .../integration/spring/SpringLiquibase.java | 6 +- .../logging/core/DefaultLogMessageFilter.java | 5 +- .../core/DefaultLoggerConfiguration.java | 4 +- .../parser/ChangeLogParserConfiguration.java | 6 +- .../java/liquibase/ui/ConsoleUIService.java | 2 +- ...nfiguration.ConfigurationDefinitionHolder} | 0 ...e.configuration.ConfigurationValueProvider | 5 +- .../command/core/DropAllCommandTest.groovy | 3 +- .../core/RegisterChangeLogCommandTest.groovy | 1 - .../ConfigurationDefinitionTest.groovy | 122 ++++++++++++++ .../LiquibaseConfigurationTest.groovy | 37 +++++ .../EnvironmentVariableProviderTest.groovy | 51 ------ .../core/ScopeValueProviderTest.groovy | 56 +++++++ .../SystemEnvironmentValueProviderTest.groovy | 59 +++++++ .../SystemPropertyValueProviderTest.groovy | 51 ++++++ .../HubConfigurationTest.groovy | 21 ++- .../hub/core/OnlineHubServiceTest.groovy | 4 +- .../FormattedSqlChangeLogParserTest.groovy | 8 - ...XMLChangeLogSAXParser_RealFile_Test.groovy | 4 - .../changelog/ChangeLogParametersTest.java | 5 - .../changelog/ExpressionExpanderTest.java | 1 - .../java/liquibase/datatype/ClobTypeTest.java | 24 +-- .../liquibase/hub/OnlineHubServiceTest.groovy | 5 +- .../maven/plugins/AbstractLiquibaseMojo.java | 5 +- 44 files changed, 784 insertions(+), 326 deletions(-) delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java rename liquibase-core/src/main/java/liquibase/configuration/core/{EnvironmentVariableProvider.java => SystemEnvironmentValueProvider.java} (77%) delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java rename liquibase-core/src/main/resources/META-INF/services/{liquibase.configuration.AutoloadedConfigurations => liquibase.configuration.ConfigurationDefinitionHolder} (100%) create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy delete mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy rename liquibase-core/src/test/groovy/liquibase/{configuration => hub}/HubConfigurationTest.groovy (71%) diff --git a/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java b/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java index 9f8e9c3e33d..5ed40bd091f 100644 --- a/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java +++ b/liquibase-cdi/src/main/java/liquibase/integration/cdi/CDILiquibase.java @@ -5,7 +5,6 @@ import liquibase.Liquibase; import liquibase.Scope; import liquibase.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.jvm.JdbcConnection; @@ -107,11 +106,10 @@ public void onStartup() { return; } - LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { log.info(String.format("Liquibase did not run on %s because %s was set to false.", hostName, - GlobalConfiguration.SHOULD_RUN.getProperty() + GlobalConfiguration.SHOULD_RUN.getKey() )); return; } diff --git a/liquibase-cdi/src/test/java/liquibase/integration/cdi/CDILiquibaseTest.java b/liquibase-cdi/src/test/java/liquibase/integration/cdi/CDILiquibaseTest.java index e6e8a7e5b48..c88d9d1bcf7 100644 --- a/liquibase-cdi/src/test/java/liquibase/integration/cdi/CDILiquibaseTest.java +++ b/liquibase-cdi/src/test/java/liquibase/integration/cdi/CDILiquibaseTest.java @@ -21,7 +21,6 @@ public class CDILiquibaseTest { public void clearProperty() { System.clearProperty("liquibase.shouldRun"); System.clearProperty("liquibase.config.shouldRun"); - LiquibaseConfiguration.getInstance().reset(); } private void validateRunningState(boolean shouldBeRunning) { diff --git a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java index e8c865c0c50..bd6cba71ff1 100644 --- a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java @@ -1,12 +1,12 @@ package liquibase; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.AutoloadedConfigurations; +import liquibase.configuration.ConfigurationDefinitionHolder; /** * Configuration container for global properties. */ -public class GlobalConfiguration implements AutoloadedConfigurations { +public class GlobalConfiguration implements ConfigurationDefinitionHolder { public static final ConfigurationDefinition<Boolean> SHOULD_RUN; public static final ConfigurationDefinition<String> DATABASECHANGELOG_TABLE_NAME; @@ -35,7 +35,7 @@ public class GlobalConfiguration implements AutoloadedConfigurations { SHOULD_RUN = builder.define("shouldRun", Boolean.class) .setDescription("Should Liquibase commands execute") .setDefaultValue(true) - .addAlias("should.run") + .addAliasKey("should.run") .build(); DATABASECHANGELOG_TABLE_NAME = builder.define("databaseChangeLogTableName", String.class) @@ -78,7 +78,7 @@ public class GlobalConfiguration implements AutoloadedConfigurations { OUTPUT_ENCODING = builder.define("outputFileEncoding", String.class) .setDescription("Encoding to output text in. Defaults to file.encoding system property or UTF-8") .setDefaultValue("UTF-8") - .addAlias("file.encoding") + .addAliasKey("file.encoding") .setCommonlyUsed(true) .build(); diff --git a/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java b/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java deleted file mode 100644 index cbc61900eb4..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java +++ /dev/null @@ -1,5 +0,0 @@ -package liquibase.configuration; - -public interface AutoloadedConfigurations { - -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java index 768136ba065..f64f6d28771 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java @@ -3,14 +3,21 @@ import liquibase.Scope; import liquibase.util.ObjectUtil; -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; - +import java.util.*; + +/** + * A higher-level definition of a configuration. + * Provides type-safety, metadata, default values, etc. vs. what is available in the lower-level {@link LiquibaseConfiguration}. + * ConfigurationDefinitions that are registered with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)} will + * be available in generated help etc. + * <p> + * These objects are immutable, so to construct definitions, use {@link Builder} + * + */ public class ConfigurationDefinition<DataType> implements Comparable { - private String property; - private Set<String> aliases = new TreeSet<>(); + private String key; + private Set<String> aliasKeys = new TreeSet<>(); private Class<DataType> type; private String description; private DataType defaultValue; @@ -18,16 +25,23 @@ public class ConfigurationDefinition<DataType> implements Comparable { private ConfigurationValueHandler<DataType> valueHandler; private ConfigurationValueObfuscator<DataType> valueObfuscator; - public ConfigurationDefinition(String property, Class<DataType> type) { - this.property = property; + private ConfigurationDefinition(String key, Class<DataType> type) { + this.key = key; this.type = type; this.valueHandler = value -> ObjectUtil.convert(value, type); } + /** + * Convenience method around {@link #getCurrentValueDetails()} to return the value. + */ public DataType getCurrentValue() { - return getCurrentValueDetails().value; + return getCurrentValueDetails().getValue(); } + /** + * Convenience method around {@link #getCurrentValueDetails()} to return the obfuscated version of the value. + * @return the obfuscated value, or the plain-text value if no obfuscator is defined for this definition. + */ public DataType getCurrentValueObfuscated() { final DataType currentValue = getCurrentValue(); @@ -38,48 +52,91 @@ public DataType getCurrentValueObfuscated() { return this.valueObfuscator.obfuscate(currentValue); } - public CurrentValueDetails<DataType> getCurrentValueDetails() { - CurrentValueDetails<DataType> details = new CurrentValueDetails<>(); + /** + * @return Full details on the current value for this definition. + */ + public CurrentValue<DataType> getCurrentValueDetails() { + final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); + + CurrentValueDetails configurationValue = liquibaseConfiguration.getCurrentValue(this.getKey()); + for (String alias : this.aliasKeys) { + if (configurationValue != null) { + break; + } + configurationValue = liquibaseConfiguration.getCurrentValue(alias); + } + + DataType finalValue = null; + List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); + if (configurationValue != null) { + sourceHistory.addAll(configurationValue.getSourceHistory()); + + finalValue = valueHandler.convert(configurationValue.getValue()); + } + + + boolean defaultValueUsed = false; + if (finalValue == null) { + finalValue = this.getDefaultValue(); - final Object configurationValue = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getCurrentValue(this.getProperty()); - if (configurationValue == null) { - details.value = this.getDefaultValue(); - details.wasOverridden = false; - } else { - details.value = valueHandler.convert(configurationValue); - details.wasOverridden = true; + if (finalValue == null) { + sourceHistory.add(0, new CurrentValueSourceDetails(this.getDefaultValue(), "No configuration or default value found for", key)); + defaultValueUsed = false; + } else { + sourceHistory.add(0, new CurrentValueSourceDetails(this.getDefaultValue(), "Default value for", key)); + defaultValueUsed = true; + } } - return details; + return new CurrentValue<>(finalValue, sourceHistory, defaultValueUsed); } - public String getProperty() { - return property; + /** + * The standard configuration key for this definition. + */ + public String getKey() { + return key; } - public Set<String> getAliases() { - return aliases; + /** + * @return alternate configuration keys to check for values. + */ + public Set<String> getAliasKeys() { + return aliasKeys; } + /** + * @return the type of data this definition returns. + */ public Class<DataType> getType() { return type; } + /** + * A user-friendly description of this definition. + */ public String getDescription() { return description; } + /** + * The default value used by this definition of no value is currently configured. + */ public DataType getDefaultValue() { return defaultValue; } + /** + * Returns true if this is configuration users are often interested in setting. + * Used to simplify generated help by hiding less commonly used settings. + */ public boolean getCommonlyUsed() { return commonlyUsed; } @Override public int compareTo(Object o) { - return this.getProperty().compareTo(((ConfigurationDefinition) o).getProperty()); + return this.getKey().compareTo(((ConfigurationDefinition) o).getKey()); } @Override @@ -87,36 +144,46 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConfigurationDefinition<?> that = (ConfigurationDefinition<?>) o; - return Objects.equals(property, that.property); + return Objects.equals(key, that.key); } @Override public int hashCode() { - return Objects.hash(property); + return Objects.hash(key); } + /** + * Used to construct new {@link ConfigurationDefinition} instances. + */ public static class Builder { - private String namespace; + private final String defaultKeyPrefix; - public Builder(String namespace) { - this.namespace = namespace; + /** + * @param defaultKeyPrefix the prefix to add to new keys that are not fully qualified + */ + public Builder(String defaultKeyPrefix) { + this.defaultKeyPrefix = defaultKeyPrefix; } + /** + * Starts a new definition with the given key. Always adds the defaultKeyPrefix. + */ public <T> NewDefinition<T> define(String key, Class<T> dataType) { - final ConfigurationDefinition<T> definition = new ConfigurationDefinition<>(namespace + "." + key, dataType); + final ConfigurationDefinition<T> definition = new ConfigurationDefinition<>(defaultKeyPrefix + "." + key, dataType); return new NewDefinition<>(definition); } public static class NewDefinition<DataType> { - private ConfigurationDefinition<DataType> definition; + + private final ConfigurationDefinition<DataType> definition; private NewDefinition(ConfigurationDefinition<DataType> definition) { this.definition = definition; } - public NewDefinition<DataType> addAlias(String alias) { - definition.aliases.add(alias); + public NewDefinition<DataType> addAliasKey(String alias) { + definition.aliasKeys.add(alias); return this; } @@ -149,15 +216,23 @@ public NewDefinition<DataType> setCommonlyUsed(boolean commonlyUsed) { return this; } + /** + * Finishes building this definition AND registers it with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)}. + * To not register this definition, use {@link #buildTemporary()} + */ public ConfigurationDefinition<DataType> build() { - Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).addDefinition(definition); + Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).registerDefinition(definition); return definition; } - } - + /** + * Finishes building this definition WITHOUT registering it with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)}. + * To automatically register this definition, use {@link #build()} + */ + public ConfigurationDefinition<DataType> buildTemporary() { + return definition; + } + } } - - } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java new file mode 100644 index 00000000000..d6805fba754 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java @@ -0,0 +1,9 @@ +package liquibase.configuration; + +/** + * Marker interface for a class containing {@link ConfigurationDefinition} which should be auto-loaded at Liquibase startup. + * All classes that implement this interface must still be registered in the META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder file. + */ +public interface ConfigurationDefinitionHolder { + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java index 1c55683d88f..4acb5df792c 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java @@ -1,19 +1,23 @@ package liquibase.configuration; -import liquibase.configuration.core.SystemPropertyProvider; +import liquibase.configuration.core.SystemEnvironmentValueProvider; /** - * Interface for classes that are able to lookup overriding default LiquibaseConfiguration values. - * For example, {@link SystemPropertyProvider} can look up property values in system properties. + * Defines a way for {@link LiquibaseConfiguration} to find configured values. */ public interface ConfigurationValueProvider { + /** + * Returns the precedence of values returned by this provider. Higher a provider with higher precedence overrides values from lower precedence providers. + */ int getPrecedence(); - Object getValue(String property); - /** - * Generates a human consumable description of how the configured ConfigurationValueProvider(s) will attempt to set a default value. + * Lookup the given key in this source. + * It is up to the implementation to provide any "smoothing" or translation of key names. + * For example, {@link SystemEnvironmentValueProvider} will look check environment variables containing _'s rather than .'s. + * + * @return null if the key is not defined in this provider. */ - String describeValueLookupLogic(String property); + CurrentValueSourceDetails getValue(String key); } diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java new file mode 100644 index 00000000000..0b69fcf879a --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java @@ -0,0 +1,53 @@ +package liquibase.configuration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Detailed, type-safe information about the current configuration value that can be provided by {@link ConfigurationDefinition}. + */ +public class CurrentValue<DataType> { + + private final DataType value; + private final List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); + private final boolean defaultValueUsed; + + public CurrentValue(DataType value, List<CurrentValueSourceDetails> sourceHistory, boolean defaultValueUsed) { + this.value = value; + this.sourceHistory.addAll(sourceHistory); + this.defaultValueUsed = defaultValueUsed; + } + + /** + * @return the current value. Can be null if not set and no default value. + */ + public DataType getValue() { + return value; + } + + /** + * @return true if the default value is being used rather than a configuration value + */ + public boolean getDefaultValueUsed() { + return defaultValueUsed; + } + + /** + * @return Returns where/how the value was set. + */ + public CurrentValueSourceDetails getSource() { + if (sourceHistory.size()== 0) { + return null; + } + return sourceHistory.get(0); + } + + /** + * @return a full list of how the value was set and overridden. + */ + public List<CurrentValueSourceDetails> getSourceHistory() { + return Collections.unmodifiableList(sourceHistory); + } + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java index 28aa573210d..e115f92b1fa 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java +++ b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java @@ -1,19 +1,35 @@ package liquibase.configuration; -public class CurrentValueDetails<DataType> { - DataType value; - boolean wasOverridden; - String sourceDescription; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; - public DataType getValue() { - return value; +/** + * Detailed information about the current configuration value. + */ +public class CurrentValueDetails { + + private final List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); + + public CurrentValueDetails() { + } + + public Object getValue() { + if (sourceHistory.size() == 0) { + return null; + } + return sourceHistory.get(0).getValue(); } - public boolean getWasOverridden() { - return wasOverridden; + public void override(CurrentValueSourceDetails details) { + this.sourceHistory.add(0, details); } - public String getSourceDescription() { - return sourceDescription; + /** + * @return a full list of how the value was set and overridden. + */ + public List<CurrentValueSourceDetails> getSourceHistory() { + return Collections.unmodifiableList(sourceHistory); } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java new file mode 100644 index 00000000000..52a649a6c92 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java @@ -0,0 +1,32 @@ +package liquibase.configuration; + +/** + * Defines how a value was set. + */ +public class CurrentValueSourceDetails { + private final String key; + private final String source; + private final Object value; + + public CurrentValueSourceDetails(Object value, String source, String key) { + this.value = value; + this.key = key; + this.source = source; + } + + public Object getValue() { + return value; + } + + public String getKey() { + return key; + } + + public String getSource() { + return source; + } + + public String describe() { + return source + " '" + key + "'"; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index 7e119a1aa80..515ca9ada2b 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -4,20 +4,21 @@ import liquibase.SingletonObject; import liquibase.servicelocator.ServiceLocator; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; /** * Provides unified management of configuration properties within Liquibase core and in extensions. * <p> - * This class is the top level container used to access {@link AutoloadedConfigurations} implementations which contain - * the actual configuration properties. - * Normal use is to call - * LiquibaseConfiguration.getInstance().getConfiguration(NEEDED_CONFIGURATION.class).getYOUR_PROPERTY() + * 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. + * <p> + * "Registered" configuration definitions will be available for generated help. + * <p> + * 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. * <p> - * 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 implements SingletonObject { @@ -28,14 +29,11 @@ public static LiquibaseConfiguration getInstance() { return Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); } - /** - * Constructor protected to prevent construction outside getInstance() - */ public LiquibaseConfiguration() { configurationValueProviders = new TreeSet<>((o1, o2) -> { - if (o1.getPrecedence() < o1.getPrecedence()) { + if (o1.getPrecedence() < o2.getPrecedence()) { return -1; - } else if (o1.getPrecedence() > o1.getPrecedence()) { + } else if (o1.getPrecedence() > o2.getPrecedence()) { return 1; } @@ -44,50 +42,60 @@ public LiquibaseConfiguration() { } - /** - * Re-initialize the configuration with the given ConfigurationProviders. Any existing - * AbstractConfigurationContainer instances are reset to defaults. + * 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<AutoloadedConfigurations> containers = serviceLocator.findInstances(AutoloadedConfigurations.class); - for (AutoloadedConfigurations container : containers) { - Scope.getCurrentScope().getLog(getClass()).fine("Found ConfigurationDefinitions in "+container.getClass().getName()); + final List<ConfigurationDefinitionHolder> containers = serviceLocator.findInstances(ConfigurationDefinitionHolder.class); + for (ConfigurationDefinitionHolder container : containers) { + Scope.getCurrentScope().getLog(getClass()).fine("Found ConfigurationDefinitions in " + container.getClass().getName()); } configurationValueProviders.addAll(serviceLocator.findInstances(ConfigurationValueProvider.class)); } - //TODO: remove - public void reset() { - } - - public ConfigurationDefinition getDefinition(String property) { - for (ConfigurationDefinition definition : definitions) { - if (definition.getProperty().equals(property)) { - return definition; - } - } - return null; + /** + * Adds a new {@link ConfigurationValueProvider} to the active collection of providers. + */ + public void addProvider(ConfigurationValueProvider valueProvider) { + this.configurationValueProviders.add(valueProvider); } - public Object getCurrentValue(String property) { + /** + * Searches for the given key in the current providers. + * + * @return the value for the key, or null if not configured. + */ + public CurrentValueDetails getCurrentValue(String key) { + CurrentValueDetails details = null; for (ConfigurationValueProvider provider : configurationValueProviders) { - final Object value = provider.getValue(property); - if (value != null) { - return value; + final CurrentValueSourceDetails providerValue = provider.getValue(key); + + if (providerValue != null) { + if (details == null) { + details = new CurrentValueDetails(); + } + + details.override(providerValue); } } - return null; + return details; } - public void addDefinition(ConfigurationDefinition definition) { + /** + * Registers a {@link ConfigurationDefinition} so it will be returned by {@link #getRegisteredDefinitions()} + */ + public void registerDefinition(ConfigurationDefinition definition) { this.definitions.add(definition); } - public SortedSet<ConfigurationDefinition> getDefinitions() { + /** + * Returns all registered {@link ConfigurationDefinition}s. Registered definitions are used for generated help documentation. + */ + public SortedSet<ConfigurationDefinition> getRegisteredDefinitions() { return Collections.unmodifiableSortedSet(this.definitions); } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java new file mode 100644 index 00000000000..e824730a506 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java @@ -0,0 +1,38 @@ +package liquibase.configuration.core; + +import liquibase.Scope; +import liquibase.configuration.ConfigurationValueProvider; +import liquibase.configuration.CurrentValueSourceDetails; + +import java.util.Properties; + +/** + * Searches the {@link liquibase.Scope} for the given key. + * Does not perform any key smoothing/translating. + */ +public class ScopeValueProvider implements ConfigurationValueProvider { + + @Override + public int getPrecedence() { + return 50; + } + + @Override + public CurrentValueSourceDetails getValue(String key) { + if (key == null) { + return null; + } + + final Object value = Scope.getCurrentScope().get(key, Object.class); + if (value == null) { + return null; + } + + return new CurrentValueSourceDetails(value, "Scoped value", key); + } + + protected Properties getSystemProperties() { + return System.getProperties(); + } + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java similarity index 77% rename from liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java rename to liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java index c87a9ce4723..da81ab6ef8a 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/EnvironmentVariableProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java @@ -1,8 +1,9 @@ package liquibase.configuration.core; import liquibase.configuration.ConfigurationValueProvider; +import liquibase.configuration.CurrentValueDetails; +import liquibase.configuration.CurrentValueSourceDetails; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -17,9 +18,8 @@ * <li>FOO_BAR - with underscores and upper case</li> * </ul> * Any hyphen variant of the above would work as well, or even mix dot/hyphen variants. - * */ -public class EnvironmentVariableProvider implements ConfigurationValueProvider { +public class SystemEnvironmentValueProvider implements ConfigurationValueProvider { @Override public int getPrecedence() { @@ -27,14 +27,14 @@ public int getPrecedence() { } @Override - public Object getValue(String property) { - if (property == null) { + public CurrentValueSourceDetails getValue(String key) { + if (key == null) { return null; } Set<String> checked = new HashSet<>(); - for (String name : new String[]{property, property.toUpperCase(), property.toLowerCase()}) { + for (String name : new String[]{key, key.toUpperCase(), key.toLowerCase()}) { for (String variation : new String[] { name, @@ -50,7 +50,7 @@ public Object getValue(String property) { if (checked.add(variation)) { final String foundValue = getEnvironmentVariable(variation); if (foundValue != null) { - return foundValue; + return new CurrentValueSourceDetails(foundValue, "Environment variable", variation); } } @@ -65,8 +65,4 @@ protected String getEnvironmentVariable(String name) { return System.getenv(name); } - @Override - public String describeValueLookupLogic(String property) { - return "Environment variable '" + property + "'"; - } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java deleted file mode 100644 index 7909e823125..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -package liquibase.configuration.core; - -import liquibase.configuration.ConfigurationValueProvider; -import liquibase.util.StringUtil; - -import java.util.Map; -import java.util.Properties; - -/** - * A ConfigurationValueProvider implementation that looks for overriding values in system properties. - * Looks for system properties in the format "NAMESPACE.PROPERTY_NAME". - */ -public class SystemPropertyProvider implements ConfigurationValueProvider { - - @Override - public int getPrecedence() { - return 20; - } - - @Override - public Object getValue(String property) { - String propValue = System.getProperty(property); - if (StringUtil.isNotEmpty(propValue)) { - return propValue; - } - - // - // Not matching with the actual key then try case insensitive - // - Properties properties = System.getProperties(); - for (Map.Entry<Object, Object> entry : properties.entrySet()) { - String key = (String) entry.getKey(); - if (key.equalsIgnoreCase(property)) { - return entry.getValue(); - } - } - return null; - } - - @Override - public String describeValueLookupLogic(String property) { - return "System property '" + property + "'"; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java new file mode 100644 index 00000000000..4c1ec881b24 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java @@ -0,0 +1,51 @@ +package liquibase.configuration.core; + +import liquibase.configuration.ConfigurationValueProvider; +import liquibase.configuration.CurrentValueDetails; +import liquibase.configuration.CurrentValueSourceDetails; +import liquibase.util.StringUtil; + +import java.util.Map; +import java.util.Properties; + +/** + * Searches for the configuration values in the system properties {@link System#getProperties()}. + * <p> + * To improve usability, it will search for the given key case insensitively. + */ +public class SystemPropertyValueProvider implements ConfigurationValueProvider { + + @Override + public int getPrecedence() { + return 20; + } + + @Override + public CurrentValueSourceDetails getValue(String key) { + if (key == null) { + return null; + } + + final Properties systemProperties = getSystemProperties(); + + String propValue = systemProperties.getProperty(key); + if (StringUtil.isNotEmpty(propValue)) { + return new CurrentValueSourceDetails(propValue, "System property", key); + } + + // + // Not matching with the actual key then try case insensitive + // + for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) { + String foundKey = (String) entry.getKey(); + if (foundKey.equalsIgnoreCase(key)) { + return new CurrentValueSourceDetails(entry.getValue(),"System property", foundKey); + } + } + return null; + } + + protected Properties getSystemProperties() { + return System.getProperties(); + } +} diff --git a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java index ab952c83cc1..aa8b97122e5 100644 --- a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java +++ b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java @@ -672,7 +672,7 @@ public String getLiquibaseCatalogName() { return liquibaseCatalogName; } - if (GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValueDetails().getWasOverridden()) { + if (GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValueDetails() == null) { return GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValue(); } @@ -690,7 +690,7 @@ public String getLiquibaseSchemaName() { return liquibaseSchemaName; } - if (GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValueDetails().getWasOverridden()) { + if (!GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValueDetails().getDefaultValueUsed()) { return GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValue(); } diff --git a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java index 007bb1c355d..f82d06afe67 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java @@ -1,12 +1,12 @@ package liquibase.hub; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.AutoloadedConfigurations; +import liquibase.configuration.ConfigurationDefinitionHolder; /** * Configuration container for global properties. */ -public class HubConfiguration implements AutoloadedConfigurations { +public class HubConfiguration implements ConfigurationDefinitionHolder { public static final ConfigurationDefinition<String> LIQUIBASE_HUB_API_KEY; public static final ConfigurationDefinition<String> LIQUIBASE_HUB_URL; diff --git a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java index c9c17f8d98b..fa6e6c740ed 100644 --- a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java +++ b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java @@ -137,7 +137,7 @@ protected String getChangeLogFile() { protected boolean shouldRun() { LiquibaseConfiguration configuration = LiquibaseConfiguration.getInstance(); if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { - log("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getProperty() + " was set to false", Project.MSG_INFO); + log("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getKey() + " was set to false", Project.MSG_INFO); return false; } return true; diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java index 9a1dc0bd6e7..7192beb3408 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java @@ -198,7 +198,7 @@ public Integer run() throws Exception { if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getUI().sendErrorMessage(( String.format(coreBundle.getString("did.not.run.because.param.was.set.to.false"), - GlobalConfiguration.SHOULD_RUN.getProperty()))); + GlobalConfiguration.SHOULD_RUN.getKey()))); return 0; } diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java index 29e79e26b4e..dcc4cfae5bd 100644 --- a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java @@ -1,11 +1,8 @@ package liquibase.integration.servlet; -import liquibase.Contexts; -import liquibase.LabelExpression; -import liquibase.Liquibase; -import liquibase.Scope; +import liquibase.*; import liquibase.configuration.ConfigurationValueProvider; -import liquibase.GlobalConfiguration; +import liquibase.configuration.CurrentValueSourceDetails; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.core.DerbyDatabase; @@ -101,8 +98,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { ServletContext servletContext = servletContextEvent.getServletContext(); try { this.hostName = NetUtil.getLocalHostName(); - } - catch (Exception e) { + } catch (Exception e) { servletContext.log("Cannot find hostname: " + e.getMessage()); return; } @@ -115,7 +111,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { servletValueContainer = new ServletValueContainer(servletContext, ic); //TODO: LiquibaseConfiguration.getInstance().init(servletValueContainer); - failOnError = (String) servletValueContainer.getValue(LIQUIBASE_ONERROR_FAIL); + failOnError = (String) servletValueContainer.getValue(LIQUIBASE_ONERROR_FAIL).getValue(); if (checkPreconditions(servletContext, ic)) { executeUpdate(servletContext, ic); } @@ -128,8 +124,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { if (ic != null) { try { ic.close(); - } - catch (NamingException e) { + } catch (NamingException e) { // ignore } } @@ -147,13 +142,13 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { private boolean checkPreconditions(ServletContext servletContext, InitialContext ic) { if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run on " + hostName - + " because "+ GlobalConfiguration.SHOULD_RUN.getProperty() - + " was set to false"); + + " because " + GlobalConfiguration.SHOULD_RUN.getKey() + + " was set to false"); return false; } - String machineIncludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_INCLUDES); - String machineExcludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_EXCLUDES); + String machineIncludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_INCLUDES).getValue(); + String machineExcludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_EXCLUDES).getValue(); boolean shouldRun = false; if ((machineIncludes == null) && (machineExcludes == null)) { @@ -175,10 +170,10 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext } } - if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getWasOverridden()) { + if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && !GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getDefaultValueUsed()) { shouldRun = true; servletContext.log("ignoring " + LIQUIBASE_HOST_INCLUDES + " and " - + LIQUIBASE_HOST_EXCLUDES + ", since " + GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getSourceDescription() + + LIQUIBASE_HOST_EXCLUDES + ", since " + GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getSource() + "=true"); } if (!shouldRun) { @@ -194,19 +189,19 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext */ @java.lang.SuppressWarnings("squid:S2095") private void executeUpdate(ServletContext servletContext, InitialContext ic) throws NamingException, SQLException, LiquibaseException { - setDataSource((String) servletValueContainer.getValue(LIQUIBASE_DATASOURCE)); + setDataSource((String) servletValueContainer.getValue(LIQUIBASE_DATASOURCE).getValue()); if (getDataSource() == null) { throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_DATASOURCE + " is not set"); } - setChangeLogFile((String) servletValueContainer.getValue(LIQUIBASE_CHANGELOG)); + setChangeLogFile((String) servletValueContainer.getValue(LIQUIBASE_CHANGELOG).getValue()); if (getChangeLogFile() == null) { throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_CHANGELOG + " is not set"); } - setContexts((String) servletValueContainer.getValue(LIQUIBASE_CONTEXTS)); - setLabels((String) servletValueContainer.getValue(LIQUIBASE_LABELS)); - this.defaultSchema = StringUtil.trimToNull((String) servletValueContainer.getValue(LIQUIBASE_SCHEMA_DEFAULT)); + setContexts((String) servletValueContainer.getValue(LIQUIBASE_CONTEXTS).getValue()); + setLabels((String) servletValueContainer.getValue(LIQUIBASE_LABELS).getValue()); + this.defaultSchema = StringUtil.trimToNull((String) servletValueContainer.getValue(LIQUIBASE_SCHEMA_DEFAULT).getValue()); Connection connection = null; Database database = null; @@ -241,8 +236,7 @@ private void executeUpdate(ServletContext servletContext, InitialContext ic) thr if (database instanceof DerbyDatabase) { ((DerbyDatabase) database).setShutdownEmbeddedDerby(false); } - } - finally { + } finally { if (liquibase != null) { liquibase.close(); } else if (connection != null) { @@ -270,11 +264,6 @@ public ServletValueContainer(ServletContext servletContext, InitialContext initi this.initialContext = initialContext; } - @Override - public String describeValueLookupLogic(String property) { - return "JNDI, servlet container init parameter, and system property '"+property+"'"; - } - /** * Try to read the value that is stored by the given key from * <ul> @@ -284,25 +273,25 @@ public String describeValueLookupLogic(String property) { * </ul> */ @Override - public Object getValue(String prefixAndProperty) { + public CurrentValueSourceDetails getValue(String key) { // Try to get value from JNDI try { Context envCtx = (Context) initialContext.lookup(JAVA_COMP_ENV); - String valueFromJndi = (String) envCtx.lookup(prefixAndProperty); - return valueFromJndi; - } - catch (NamingException e) { + String valueFromJndi = (String) envCtx.lookup(key); + + return new CurrentValueSourceDetails(valueFromJndi, "JNDI", key); + } catch (NamingException e) { // Ignore } // Return the value from the servlet context - String valueFromServletContext = servletContext.getInitParameter(prefixAndProperty); + String valueFromServletContext = servletContext.getInitParameter(key); if (valueFromServletContext != null) { - return valueFromServletContext; + return new CurrentValueSourceDetails(valueFromServletContext, "Servlet context value", key); } // Otherwise: Return system property - return System.getProperty(prefixAndProperty); + return new CurrentValueSourceDetails(System.getProperty(key), "System property", key); } } } diff --git a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java index d3f3348508c..637f08e1a2c 100644 --- a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java +++ b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java @@ -4,7 +4,7 @@ import liquibase.LabelExpression; import liquibase.Liquibase; import liquibase.Scope; -import liquibase.configuration.CurrentValueDetails; +import liquibase.configuration.CurrentValue; import liquibase.GlobalConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; @@ -251,10 +251,10 @@ public void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) { */ @Override public void afterPropertiesSet() throws LiquibaseException { - final CurrentValueDetails<Boolean> shouldRunProperty = GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails(); + final CurrentValue<Boolean> shouldRunProperty = GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails(); if (!shouldRunProperty.getValue()) { - Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " +shouldRunProperty.getSourceDescription() + " was set to false"); + Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " +shouldRunProperty.getSource() + " was set to false"); return; } if (!shouldRun) { diff --git a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java index 6f6f45d1db6..93e6fa60ed5 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLogMessageFilter.java @@ -7,7 +7,10 @@ public class DefaultLogMessageFilter implements LogMessageFilter { @Override public String filterMessage(String message) { - final String liquibaseHubApiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); + String liquibaseHubApiKey = null; + if (HubConfiguration.LIQUIBASE_HUB_API_KEY != null) { + liquibaseHubApiKey = HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue(); + } if (liquibaseHubApiKey != null) { message = message.replace(liquibaseHubApiKey, HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValueObfuscated()); } diff --git a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java index 3a4a8af1836..204f2f0a8a8 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java @@ -1,12 +1,12 @@ package liquibase.logging.core; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.AutoloadedConfigurations; +import liquibase.configuration.ConfigurationDefinitionHolder; /** * Configuration container for {@link liquibase.logging.LogService} properties */ -public class DefaultLoggerConfiguration implements AutoloadedConfigurations { +public class DefaultLoggerConfiguration implements ConfigurationDefinitionHolder { public static ConfigurationDefinition<String> LOG_LEVEL; diff --git a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java index c316bff468a..5a49a36f77e 100644 --- a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java @@ -1,12 +1,12 @@ package liquibase.parser; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.AutoloadedConfigurations; +import liquibase.configuration.ConfigurationDefinitionHolder; /** * Configuration container for properties applicable to most {@link liquibase.parser.ChangeLogParser} implementations */ -public class ChangeLogParserConfiguration implements AutoloadedConfigurations { +public class ChangeLogParserConfiguration implements ConfigurationDefinitionHolder { public static final ConfigurationDefinition<Boolean> SUPPORT_PROPERTY_ESCAPING; public static final ConfigurationDefinition<Boolean> USE_PROCEDURE_SCHEMA; @@ -17,7 +17,7 @@ public class ChangeLogParserConfiguration implements AutoloadedConfigurations { SUPPORT_PROPERTY_ESCAPING = builder.define("supportPropertyEscaping", Boolean.class) .setDescription("Support escaping changelog parameters using a colon. Example: ${:user.name}") .setDefaultValue(false) - .addAlias("enableEscaping") + .addAliasKey("enableEscaping") .build(); USE_PROCEDURE_SCHEMA = builder.define("useProcedureSchema", Boolean.class) diff --git a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java index 2b9c4160b0c..39c43acfc5c 100644 --- a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java +++ b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java @@ -94,7 +94,7 @@ public <T> T prompt(String prompt, T defaultValue, InputHandler<T> inputHandler, protected ConsoleWrapper getConsole() { if (console == null) { boolean headlessConfigValue = GlobalConfiguration.HEADLESS.getCurrentValue(); - boolean wasHeadlessOverridden = GlobalConfiguration.HEADLESS.getCurrentValueDetails().getWasOverridden(); + boolean wasHeadlessOverridden = !GlobalConfiguration.HEADLESS.getCurrentValueDetails().getDefaultValueUsed(); final Logger log = Scope.getCurrentScope().getLog(getClass()); diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder similarity index 100% rename from liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations rename to liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider index 9baa7f11e63..239543b42e0 100644 --- a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider +++ b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider @@ -1,2 +1,3 @@ -liquibase.configuration.core.EnvironmentVariableProvider -liquibase.configuration.core.SystemPropertyProvider +liquibase.configuration.core.SystemEnvironmentValueProvider +liquibase.configuration.core.SystemPropertyValueProvider +liquibase.configuration.core.ScopeValueProvider diff --git a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy index 34f79af0bd3..5856a0d69af 100644 --- a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy @@ -63,8 +63,7 @@ class DropAllCommandTest extends Specification { BufferedLogService bufferLog = new BufferedLogService() Scope.getCurrentScope().getUI() - def hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class) - hubConfiguration.setLiquibaseHubApiKey(UUID.randomUUID().toString()) + HubConfiguration.LIQUIBASE_HUB_API_KEY.setLiquibaseHubApiKey(UUID.randomUUID().toString()) def command = new DropAllCommand() JUnitResourceAccessor testResourceAccessor = new JUnitResourceAccessor() Liquibase liquibase = new Liquibase(outputFile.getName(), testResourceAccessor, new MockDatabase()) diff --git a/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy b/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy index b2f420fc834..d0e4aa4eb0f 100644 --- a/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/command/core/RegisterChangeLogCommandTest.groovy @@ -180,7 +180,6 @@ class RegisterChangeLogCommandTest extends Specification { when: def outputStream = new ByteArrayOutputStream() - def hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class) def command = new RegisterChangeLogCommand() command.setChangeLogFile("changelog.xml") DatabaseChangeLog changeLog = new DatabaseChangeLog(".") diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy new file mode 100644 index 00000000000..e4f633434ff --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy @@ -0,0 +1,122 @@ +package liquibase.configuration + +import liquibase.Scope +import spock.lang.Specification +import spock.lang.Unroll + +class ConfigurationDefinitionTest extends Specification { + + def "Can build and register"() { + when: + def definition = new ConfigurationDefinition.Builder("test.can-build") + .define("test-property", String) + .setDefaultValue("Default Value") + .setDescription("A description here") + .build() + + then: + assert Scope.currentScope.getSingleton(LiquibaseConfiguration).getRegisteredDefinitions().contains(definition) + definition.key == "test.can-build.test-property" + definition.defaultValue == "Default Value" + definition.description == "A description here" + } + + @Unroll + def "getCurrentValueDetails"() { + when: + def definition = new ConfigurationDefinition.Builder("test") + .define(key, String) + .addAliasKey("other") + .setDefaultValue(defaultValue) + .buildTemporary() + + System.setProperty("test.current-value", "From from system") + System.setProperty("test.other", "Alias set in system") + def currentValue = Scope.child(["test.current-value": "From scope"], new Scope.ScopedRunnerWithReturn<CurrentValue>() { + @Override + CurrentValue run() throws Exception { + return definition.getCurrentValueDetails() + } + }) + + then: + currentValue.value == expectedValue + currentValue.source.describe() == expectedSource + currentValue.getDefaultValueUsed() == defaultValueUsed + + where: + key | defaultValue | expectedValue | expectedSource | defaultValueUsed + "current-value" | "Default Value" | "From scope" | "Scoped value 'test.current-value'" | false + "unset-value" | "Configured Default" | "Configured Default" | "Default value for 'test.unset-value'" | true + "unset-value" | null | null | "No configuration or default value found for 'test.unset-value'" | false + + } + + @Unroll + def "getCurrentValueDetails for aliases"() { + when: + def definition = new ConfigurationDefinition.Builder("test") + .define("actual", String) + .addAliasKey("other.prefix.key") + .addAliasKey("other") + .buildTemporary() + + def currentValue = Scope.child([(key): "From Scope"], new Scope.ScopedRunnerWithReturn<CurrentValue>() { + @Override + CurrentValue run() throws Exception { + return definition.getCurrentValueDetails() + } + }) + + then: + currentValue.value == expected + + where: + key | expected + "test.actual" | "From Scope" + "other.prefix.key" | "From Scope" + "other" | "From Scope" + + } + + def "getValueObfuscated"() { + when: + def obfuscated = new ConfigurationDefinition.Builder("test") + .define("obfuscated", String) + .setValueObfuscator(new ConfigurationValueObfuscator<String>() { + @Override + String obfuscate(String value) { + return "OBFUSCATED " + value + } + }) + .buildTemporary() + + def plainText = new ConfigurationDefinition.Builder("test") + .define("obfuscated", String) + .buildTemporary() + + def obfuscatedOutput = Scope.child(["test.obfuscated": input], new Scope.ScopedRunnerWithReturn<String>() { + @Override + String run() throws Exception { + return obfuscated.getCurrentValueObfuscated() + } + }) + + def plainOutput = Scope.child(["test.obfuscated": input], new Scope.ScopedRunnerWithReturn<String>() { + @Override + String run() throws Exception { + return plainText.getCurrentValueObfuscated() + } + }) + + then: + obfuscatedOutput == expected + plainOutput == expectedPlain + + where: + input | expected | expectedPlain + "value" | "OBFUSCATED value" | "value" + null | "OBFUSCATED null" | null + + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy new file mode 100644 index 00000000000..64057d7c8b5 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy @@ -0,0 +1,37 @@ +package liquibase.configuration + +import liquibase.Scope +import spock.lang.Specification + +class LiquibaseConfigurationTest extends Specification { + + def "getCurrentValueDetails"() { + when: + + System.setProperty("test.current-value", "From system") + def currentValue = Scope.child(["test.current-value": "From scope"], new Scope.ScopedRunnerWithReturn<CurrentValueDetails>() { + @Override + CurrentValueDetails run() throws Exception { + return Scope.currentScope.getSingleton(LiquibaseConfiguration).getCurrentValue("test.current-value") + } + }) + + then: + currentValue.value == "From scope" + currentValue.sourceHistory*.describe() == ["Scoped value 'test.current-value'", "System property 'test.current-value'"] + } + + def "autoRegisters and sorts providers"() { + expect: + Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).configurationValueProviders*.getClass()*.getName() == ["liquibase.configuration.core.SystemEnvironmentValueProvider", + "liquibase.configuration.core.SystemPropertyValueProvider", + "liquibase.configuration.core.ScopeValueProvider" + ] + } + + def "autoRegisters definitions"() { + expect: + Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).getRegisteredDefinitions().size() > 10 + } + +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy deleted file mode 100644 index 489f1159e51..00000000000 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/EnvironmentVariableProviderTest.groovy +++ /dev/null @@ -1,51 +0,0 @@ -package liquibase.configuration.core - -import spock.lang.Specification -import spock.lang.Unroll - -class EnvironmentVariableProviderTest extends Specification { - - @Unroll - def "GetValue"() { - when: - def env = [ - "lower" : "saw lower", - "lower_underscore": "saw lower underscore", - "lower.dot" : "saw lower dot", - "lower_under.dot" : "saw lower word dot", - "UPPER" : "saw upper", - "UPPER_UNDERSCORE": "saw upper underscore", - "UPPER.DOT" : "saw upper dot", - "UPPER_UNDER_DOT" : "saw under dot", - ] - def provider = new EnvironmentVariableProvider() { - @Override - protected String getEnvironmentVariable(String name) { - return env[name] - } - } - - then: - provider.getValue(key) == expected - - where: - key | expected - "lower" | "saw lower" - "LOWER" | "saw lower" - "upper" | "saw upper" - "UPPER" | "saw upper" - "lower_underscore" | "saw lower underscore" - "lower.underscore" | "saw lower underscore" - "lower_UNDERSCORE" | "saw lower underscore" - "upper_underscore" | "saw upper underscore" - "UPPER_UNDERSCORE" | "saw upper underscore" - "upper_dot" | null - "upper.dot" | "saw upper dot" - "UPPER.DOT" | "saw upper dot" - "lower_under.dot" | "saw lower word dot" - "LOWER.UNDER.dot" | null - "LOWER_UNDER_DOT" | null - "invalid" | null - null | null - } -} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy new file mode 100644 index 00000000000..b14a092ed04 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy @@ -0,0 +1,56 @@ +package liquibase.configuration.core + +import liquibase.Scope +import liquibase.configuration.CurrentValueSourceDetails +import spock.lang.Specification +import spock.lang.Unroll + +class ScopeValueProviderTest extends Specification { + + + @Unroll + def "GetValue"() { + when: + def env = [ + "lower" : "saw lower", + "lower_underscore": "saw lower underscore", + "lower.dot" : "saw lower dot", + "lower_under.dot" : "saw lower word dot", + "UPPER" : "saw upper", + "UPPER_UNDERSCORE": "saw upper underscore", + "UPPER.DOT" : "saw upper dot", + "UPPER_UNDER_DOT" : "saw under dot", + ] + + def passedKey = key + CurrentValueSourceDetails foundValue = Scope.child(env, new Scope.ScopedRunnerWithReturn() { + @Override + Object run() throws Exception { + new ScopeValueProvider().getValue(passedKey) + } + }) + + then: + if (foundValue == null) { + assert expectedValue == null + } else { + assert foundValue.value == expectedValue + assert foundValue.describe() == expectedSource + } + + + where: + key | expectedValue | expectedSource + "lower" | "saw lower" | "Scoped value 'lower'" + "LOWER" | null | null + "upper" | null | null + "UPPER" | "saw upper" | "Scoped value 'UPPER'" + "lower.underscore" | null | null + "upper.dot" | null | null + "UPPER.DOT" | "saw upper dot" | "Scoped value 'UPPER.DOT'" + "LOWER.UNDER.dot" | null | null + "LOWER_UNDER_DOT" | null | null + "invalid" | null | null + null | null | null + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy new file mode 100644 index 00000000000..d9af2b9ba33 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy @@ -0,0 +1,59 @@ +package liquibase.configuration.core + + +import spock.lang.Specification +import spock.lang.Unroll + +class SystemEnvironmentValueProviderTest extends Specification { + + @Unroll + def "GetValue"() { + when: + def env = [ + "lower" : "saw lower", + "lower_underscore": "saw lower underscore", + "lower.dot" : "saw lower dot", + "lower_under.dot" : "saw lower word dot", + "UPPER" : "saw upper", + "UPPER_UNDERSCORE": "saw upper underscore", + "UPPER.DOT" : "saw upper dot", + "UPPER_UNDER_DOT" : "saw under dot", + ] + def provider = new SystemEnvironmentValueProvider() { + @Override + protected String getEnvironmentVariable(String name) { + return env[name] + } + } + + def value = provider.getValue(key) + + then: + if (value == null) { + assert expectedValue == null + } else { + assert value.value == expectedValue + assert value.describe() == expectedDescription + } + + where: + key | expectedValue | expectedDescription + "lower" | "saw lower" | "Environment variable 'lower'" + "LOWER" | "saw lower" | "Environment variable 'lower'" + "upper" | "saw upper" | "Environment variable 'UPPER'" + "UPPER" | "saw upper" | "Environment variable 'UPPER'" + "lower_underscore" | "saw lower underscore" | "Environment variable 'lower_underscore'" + "lower.underscore" | "saw lower underscore" | "Environment variable 'lower_underscore'" + "lower_UNDERSCORE" | "saw lower underscore" | "Environment variable 'lower_underscore'" + "upper_underscore" | "saw upper underscore" | "Environment variable 'UPPER_UNDERSCORE'" + "UPPER_UNDERSCORE" | "saw upper underscore" | "Environment variable 'UPPER_UNDERSCORE'" + "upper_dot" | null | null + "upper.dot" | "saw upper dot" | "Environment variable 'UPPER.DOT'" + "UPPER.DOT" | "saw upper dot" | "Environment variable 'UPPER.DOT'" + "lower_under.dot" | "saw lower word dot" | "Environment variable 'lower_under.dot'" + "LOWER.UNDER.dot" | null | "Environment variable 'lower_under.dot'" + "LOWER_UNDER_DOT" | null | "Environment variable 'lower_under.dot'" + "invalid" | null | null + null | null | null + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy new file mode 100644 index 00000000000..a6c16c10ca0 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy @@ -0,0 +1,51 @@ +package liquibase.configuration.core + + +import spock.lang.Specification +import spock.lang.Unroll + +class SystemPropertyValueProviderTest extends Specification { + + @Unroll + def "GetValue"() { + when: + def properties = new Properties() + properties.setProperty("lower", "saw lower") + properties.setProperty("lower.dot", "saw lower dot") + properties.setProperty("lower_under.dot", "saw lower word dot") + properties.setProperty("UPPER", "saw upper") + properties.setProperty("UPPER.DOT", "saw upper dot") + properties.setProperty("Mixed.Case", "saw mixed case") + + def provider = new SystemPropertyValueProvider() { + @Override + protected Properties getSystemProperties() { + return properties + } + } + + def value = provider.getValue(key) + + then: + if (value == null) { + assert expectedValue == null + } else { + assert value.value == expectedValue + assert value.describe() == expectedSource + } + + where: + key | expectedValue | expectedSource + "lower" | "saw lower" | "System property 'lower'" + "LOWER" | "saw lower" | "System property 'lower'" + "upper" | "saw upper" | "System property 'UPPER'" + "UPPER" | "saw upper" | "System property 'UPPER'" + "lower.underscore" | null | null + "upper.dot" | "saw upper dot" | "System property 'UPPER.DOT'" + "UPPER.DOT" | "saw upper dot" | "System property 'UPPER.DOT'" + "LOWER.UNDER.dot" | null | null + "LOWER_UNDER_DOT" | null | null + "invalid" | null | null + null | null | null + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/hub/HubConfigurationTest.groovy similarity index 71% rename from liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy rename to liquibase-core/src/test/groovy/liquibase/hub/HubConfigurationTest.groovy index 166be50c4eb..b3a8c26a3ca 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/HubConfigurationTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/hub/HubConfigurationTest.groovy @@ -1,6 +1,6 @@ -package liquibase.configuration +package liquibase.hub -import liquibase.hub.HubConfiguration +import liquibase.Scope import spock.lang.Specification import spock.lang.Unroll @@ -9,10 +9,15 @@ class HubConfigurationTest extends Specification { @Unroll def "setHubUrl cleans up input"() { when: - def config = new HubConfiguration().setLiquibaseHubUrl(input) + def output = Scope.child([(HubConfiguration.LIQUIBASE_HUB_URL.key): input], new Scope.ScopedRunnerWithReturn<String>() { + @Override + String run() throws Exception { + return HubConfiguration.LIQUIBASE_HUB_URL.getCurrentValue() + } + }) then: - config.getLiquibaseHubUrl() == expected + output == expected where: input | expected @@ -29,12 +34,4 @@ class HubConfigurationTest extends Specification { "http://localhost:8080" | "http://localhost:8080" } - def setGetHubApiKey() { - when: - def config = new HubConfiguration().setLiquibaseHubApiKey("this_is_a_hub_key") - - then: - config.getLiquibaseHubApiKey() == "this_is_a_hub_key" - } - } diff --git a/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy b/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy index 6e14f61235a..1daba517568 100644 --- a/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/hub/core/OnlineHubServiceTest.groovy @@ -13,7 +13,7 @@ class OnlineHubServiceTest extends Specification { private static testUuid = UUID.fromString("3b8b6f80-1194-4a70-8cf2-30f33fd0433e") def cleanup() { - LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode("all") +// LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode("all") } @Unroll @@ -51,7 +51,7 @@ class OnlineHubServiceTest extends Specification { def operationId = UUID.randomUUID() when: - LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode(mode) +//TODO: LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode(mode) def mockHttpClient = new MockHttpClient([ "GET /api/v1/organizations" : MockHttpClient.createListResponse([ diff --git a/liquibase-core/src/test/groovy/liquibase/parser/core/formattedsql/FormattedSqlChangeLogParserTest.groovy b/liquibase-core/src/test/groovy/liquibase/parser/core/formattedsql/FormattedSqlChangeLogParserTest.groovy index 5a15fdd4d61..a0570a70b40 100644 --- a/liquibase-core/src/test/groovy/liquibase/parser/core/formattedsql/FormattedSqlChangeLogParserTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/parser/core/formattedsql/FormattedSqlChangeLogParserTest.groovy @@ -90,14 +90,6 @@ select 1 "select 1;" - def setup() { - LiquibaseConfiguration.getInstance().reset() - } - - def cleanup() { - LiquibaseConfiguration.getInstance().reset() - } - def supports() throws Exception { expect: assert new MockFormattedSqlChangeLogParser(VALID_CHANGELOG).supports("asdf.sql", new JUnitResourceAccessor()) diff --git a/liquibase-core/src/test/groovy/liquibase/parser/core/xml/XMLChangeLogSAXParser_RealFile_Test.groovy b/liquibase-core/src/test/groovy/liquibase/parser/core/xml/XMLChangeLogSAXParser_RealFile_Test.groovy index 1e05d0092cb..cbe9584a23d 100644 --- a/liquibase-core/src/test/groovy/liquibase/parser/core/xml/XMLChangeLogSAXParser_RealFile_Test.groovy +++ b/liquibase-core/src/test/groovy/liquibase/parser/core/xml/XMLChangeLogSAXParser_RealFile_Test.groovy @@ -43,10 +43,6 @@ public class XMLChangeLogSAXParser_RealFile_Test extends Specification { @Shared resourceSupplier = new ResourceSupplier() - def before() { - LiquibaseConfiguration.getInstance().reset(); - } - def "namespace configured correctly"() { expect: assert new XMLChangeLogSAXParser().saxParserFactory.isNamespaceAware() diff --git a/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java b/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java index 3e8f137d13c..a708c0975bf 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java @@ -14,11 +14,6 @@ public class ChangeLogParametersTest { - @Before - public void before() { - LiquibaseConfiguration.getInstance().reset(); - } - @Test public void setParameterValue_doubleSet() { ChangeLogParameters changeLogParameters = new ChangeLogParameters(); diff --git a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java index 089f37755f2..1f721f61113 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java @@ -15,7 +15,6 @@ public class ExpressionExpanderTest { @Before public void setup() { - LiquibaseConfiguration.getInstance().reset(); changeLogParameters = new ChangeLogParameters(); this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); } diff --git a/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java b/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java index 17aa2c19380..084307f0fee 100644 --- a/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java +++ b/liquibase-core/src/test/java/liquibase/datatype/ClobTypeTest.java @@ -1,30 +1,18 @@ package liquibase.datatype; import liquibase.Scope; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.GlobalConfiguration; import liquibase.database.core.MSSQLDatabase; import liquibase.datatype.core.ClobType; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class ClobTypeTest { - @Before - public void prepare() { - LiquibaseConfiguration.getInstance().reset(); - } - - @After - public void reset() { - LiquibaseConfiguration.getInstance().reset(); - } @Test public void mssqlTextToVarcharTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), true, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), true, () -> { ClobType ct = new ClobType(); ct.finishInitialization("Text"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); @@ -34,7 +22,7 @@ public void mssqlTextToVarcharTest() throws Exception { @Test public void mssqlEscapedTextToVarcharTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), true, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), true, () -> { ClobType ct = new ClobType(); ct.finishInitialization("[Text]"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); @@ -44,7 +32,7 @@ public void mssqlEscapedTextToVarcharTest() throws Exception { @Test public void mssqlTextToVarcharNoConvertTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), false, () -> { ClobType ct = new ClobType(); ct.finishInitialization("Text"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); @@ -54,7 +42,7 @@ public void mssqlTextToVarcharNoConvertTest() throws Exception { @Test public void mssqlNTextToNVarcharNoConvertTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), false, () -> { ClobType ct = new ClobType(); ct.finishInitialization("NText"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); @@ -64,7 +52,7 @@ public void mssqlNTextToNVarcharNoConvertTest() throws Exception { @Test public void mssqlEscapedTextToVarcharNoConvertTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), false, () -> { ClobType ct = new ClobType(); ct.finishInitialization("[Text]"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); @@ -74,7 +62,7 @@ public void mssqlEscapedTextToVarcharNoConvertTest() throws Exception { @Test public void mssqlEscapedNTextToNVarcharNoConvertTest() throws Exception { - Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getProperty(), false, () -> { + Scope.child(GlobalConfiguration.CONVERT_DATA_TYPES.getKey(), false, () -> { ClobType ct = new ClobType(); ct.finishInitialization("[NText]"); DatabaseDataType dbType = ct.toDatabaseDataType(new MSSQLDatabase()); diff --git a/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy b/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy index 349fa44e81e..bda7cdf89c5 100644 --- a/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy +++ b/liquibase-integration-tests/src/test/groovy/liquibase/hub/OnlineHubServiceTest.groovy @@ -29,9 +29,8 @@ class OnlineHubServiceTest extends Specification { def hubApiKey = integrationTestProperties.get("integration.test.hub.apikey") def hubUrl = integrationTestProperties.get("integration.test.hub.url") - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class) - hubConfiguration.setLiquibaseHubApiKey(hubApiKey) - hubConfiguration.setLiquibaseHubUrl(hubUrl) + //TODO: hubConfiguration.setLiquibaseHubApiKey(hubApiKey) + //TODO: hubConfiguration.setLiquibaseHubUrl(hubUrl) } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java index d9214d3eba3..7c729b04a08 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseMojo.java @@ -3,7 +3,6 @@ import liquibase.Liquibase; import liquibase.Scope; import liquibase.GlobalConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.exception.DatabaseException; import liquibase.exception.LiquibaseException; @@ -317,10 +316,8 @@ public void execute() throws MojoExecutionException, MojoFailureException { processSystemProperties(); - LiquibaseConfiguration liquibaseConfiguration = LiquibaseConfiguration.getInstance(); - if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { - getLog().info("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getProperty() + " was set to false"); + getLog().info("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getKey() + " was set to false"); return; } if (skip) { From 47e665fcaa106bdfb4449b00ec452df75d4a86fd Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Thu, 4 Feb 2021 16:46:40 -0600 Subject: [PATCH 06/17] Put liquibase.integration.commandline.Main class back to the original name for now --- .../commandline/{Main.java => NewMain.java} | 6 +- .../commandline/CommandLineUtils.java | 2 +- .../commandline/{OldMain.java => Main.java} | 8 +- .../{OldMainTest.java => MainTest.java} | 82 +++++++++---------- .../AbstractLiquibaseChangeLogMojo.java | 23 +++--- .../LiquibaseGenerateChangeLogMojo.java | 19 +++-- 6 files changed, 70 insertions(+), 70 deletions(-) rename liquibase-cli/src/main/java/liquibase/integration/commandline/{Main.java => NewMain.java} (74%) rename liquibase-core/src/main/java/liquibase/integration/commandline/{OldMain.java => Main.java} (99%) rename liquibase-core/src/test/java/liquibase/integration/commandline/{OldMainTest.java => MainTest.java} (94%) diff --git a/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-cli/src/main/java/liquibase/integration/commandline/NewMain.java similarity index 74% rename from liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java rename to liquibase-cli/src/main/java/liquibase/integration/commandline/NewMain.java index 95f421f3f20..4fd136cab30 100644 --- a/liquibase-cli/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-cli/src/main/java/liquibase/integration/commandline/NewMain.java @@ -6,13 +6,13 @@ import java.util.SortedSet; -public class Main { +public class NewMain { public static void main(String[] args) { System.out.println("New CLI!"); - final SortedSet<ConfigurationDefinition> definitions = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getDefinitions(); + final SortedSet<ConfigurationDefinition> definitions = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getRegisteredDefinitions(); for (ConfigurationDefinition def : definitions) { - System.out.println("See " + def.getProperty() + " = " + def.getCurrentValue() + " -- " + def.getDescription()); + System.out.println("See " + def.getKey() + " = " + def.getCurrentValue() + " -- " + def.getDescription()); } } } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java index db13ae68782..fad5c5adbde 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/CommandLineUtils.java @@ -35,7 +35,7 @@ /** * Common Utility methods used in the CommandLine application and the Maven plugin. - * These methods were originally moved from {@link OldMain} so they could be shared. + * These methods were originally moved from {@link Main} so they could be shared. * * @author Peter Murray */ diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java similarity index 99% rename from liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java rename to liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 7192beb3408..1c412172c75 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/OldMain.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -57,9 +57,9 @@ /** * Class for executing Liquibase via the command line. */ -public class OldMain { +public class Main { private static final String ERRORMSG_UNEXPECTED_PARAMETERS = "unexpected.command.parameters"; - private static final Logger LOG = Scope.getCurrentScope().getLog(OldMain.class); + private static final Logger LOG = Scope.getCurrentScope().getLog(Main.class); private static ResourceBundle coreBundle = getBundle("liquibase/i18n/liquibase-core"); private static XMLResourceBundle commandLineHelpBundle = ((XMLResourceBundle) getBundle ("liquibase/i18n/liquibase-commandline-helptext", new XmlResourceBundleControl())); @@ -192,7 +192,7 @@ public static int run(String[] args) throws Exception { return Scope.child(scopeObjects, new Scope.ScopedRunnerWithReturn<Integer>() { @Override public Integer run() throws Exception { - OldMain main = new OldMain(); + Main main = new Main(); try { if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { @@ -405,7 +405,7 @@ public Integer run() throws Exception { }); } - private static boolean setupNeeded(OldMain main) throws CommandLineParsingException { + private static boolean setupNeeded(Main main) throws CommandLineParsingException { if (main.command.toLowerCase().startsWith(COMMANDS.REGISTER_CHANGELOG.toLowerCase())) { return false; } diff --git a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java b/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java similarity index 94% rename from liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java rename to liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java index c34a29c35d1..ed80115c820 100644 --- a/liquibase-core/src/test/java/liquibase/integration/commandline/OldMainTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java @@ -16,26 +16,26 @@ /** - * Tests for {@link OldMain} + * Tests for {@link Main} */ -public class OldMainTest { +public class MainTest { @Test public void testCodePointCheck() { char badChar = 8192; char anotherBadChar = 160; - OldMain.CodePointCheck codePointCheck = OldMain.checkArg("test"); + Main.CodePointCheck codePointCheck = Main.checkArg("test"); Assert.assertTrue("This should be a valid string", codePointCheck == null); StringBuilder builder = new StringBuilder(); builder.append(badChar); - codePointCheck = OldMain.checkArg(builder.toString()); + codePointCheck = Main.checkArg(builder.toString()); Assert.assertTrue("The first character should be invalid",codePointCheck.position == 0); builder = new StringBuilder(); builder.append("A"); builder.append(badChar); - codePointCheck = OldMain.checkArg(builder.toString()); + codePointCheck = Main.checkArg(builder.toString()); Assert.assertTrue("The last character should be invalid",codePointCheck.position == builder.length()-1); builder = new StringBuilder(); @@ -43,14 +43,14 @@ public void testCodePointCheck() { builder.append(anotherBadChar); builder.append("DEF"); int pos = builder.toString().indexOf(anotherBadChar); - codePointCheck = OldMain.checkArg(builder.toString()); + codePointCheck = Main.checkArg(builder.toString()); Assert.assertTrue("The character in position " + pos + " should be invalid",codePointCheck.position == pos); } @Test public void checkSetup2() { - OldMain main = new OldMain(); + Main main = new Main(); main.command = "snapshot"; main.url = "jdbc:oracle://localhost:1521/ORCL"; main.commandParams.add("--outputSchemasAs"); @@ -75,7 +75,7 @@ public void checkSetup2() { // @Mock // private SnapshotCommand.SnapshotCommandResult snapshotCommandResult; - public OldMainTest() throws Exception { + public MainTest() throws Exception { // PowerMockito.mockStatic(CommandFactory.class); // // commandFactory = PowerMockito.mock(CommandFactory.class); @@ -111,7 +111,7 @@ public void testLocalProperties() throws Exception { "snapshot" }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertTrue("Read context from liquibase.local.properties", ((cli.contexts != null) && cli.contexts.contains @@ -123,7 +123,7 @@ public void testLocalProperties() throws Exception { @Test public void startWithoutParameters() throws Exception { // exit.expectSystemExitWithStatus(1); - OldMain.run(new String[0]); + Main.run(new String[0]); assertTrue("We just want to survive until this point", true); } @@ -187,7 +187,7 @@ public void migrateWithAllParameters() throws Exception { "update", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Option --driver was parsed correctly", "DRIVER", cli.driver); @@ -213,7 +213,7 @@ public void falseBooleanParameters() throws Exception { "update", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase=false was parsed correctly", Boolean.FALSE, cli @@ -228,7 +228,7 @@ public void convertMigrateToUpdate() throws Exception { "migrate", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase was parsed correctly", @@ -243,7 +243,7 @@ public void trueBooleanParameters() throws Exception { "update", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Option --promptForNonLocalDatabase=true was parsed correctly", @@ -259,7 +259,7 @@ public void parameterWithoutDash() throws Exception { "update", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); } @@ -271,7 +271,7 @@ public void emptyUrlParameter() throws Exception { "update", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); List<String> errMsgs = cli.checkSetup(); assertEquals("specifying an empty URL should return 1 error message.", 1, errMsgs.size()); @@ -286,7 +286,7 @@ public void misplacedDiffTypesDataOption() throws Exception { "--diffTypes=data" }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); List<String> errMsgs = cli.checkSetup(); assertEquals("the combination of --diffTypes=data and diffChangeLog must not be accepted.", 1, errMsgs.size()); @@ -302,7 +302,7 @@ public void unknownParameter() throws Exception { "migrate", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); } @@ -315,7 +315,7 @@ public void statusVerbose() throws Exception { "--verbose", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -333,7 +333,7 @@ public void statusVerboseWithValue() throws Exception { "--verbose=true", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -352,7 +352,7 @@ public void statusWithoutVerbose() throws Exception { "status", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Main command 'status' was not correctly parsed", "status", cli.command); @@ -364,14 +364,14 @@ public void statusWithoutVerbose() throws Exception { @Test(expected = CommandLineParsingException.class) public void configureNonExistantClassloaderLocation() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); cli.classpath = "badClasspathLocation"; cli.configureClassLoader(); } @Test public void windowsConfigureClassLoaderLocation() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); if (cli.isWindows()) { @@ -389,7 +389,7 @@ public void windowsConfigureClassLoaderLocation() throws Exception { @Test public void unixConfigureClassLoaderLocation() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); if (!cli.isWindows()) { @@ -408,7 +408,7 @@ public void unixConfigureClassLoaderLocation() throws Exception { @Test public void propertiesFileWithNoOtherArgs() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -438,7 +438,7 @@ public void propertiesFileWithNoOtherArgs() throws Exception { @Test public void propertiesFileWithOtherArgs() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); cli.username = "PASSED USERNAME"; cli.password = "PASSED PASSWD"; @@ -471,7 +471,7 @@ public void propertiesFileWithOtherArgs() throws Exception { @Test public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictFalseIsInFile() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -489,7 +489,7 @@ public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictFalseIsInFi @Test public void propertiesFileChangeLogParameters() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -507,7 +507,7 @@ public void propertiesFileChangeLogParameters() throws Exception { @Test public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictModeIsFalse() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); String[] args = new String[]{"--strict=false"}; cli.parseOptions(args); @@ -526,7 +526,7 @@ public void propertiesFileParsingShouldIgnoreUnknownArgumentsIfStrictModeIsFalse @Test(expected = CommandLineParsingException.class) public void propertiesFileParsingShouldFailOnUnknownArgumentsIfStrictMode() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -542,7 +542,7 @@ public void propertiesFileParsingShouldFailOnUnknownArgumentsIfStrictMode() thro @Test public void applyDefaults() { - OldMain cli = new OldMain(); + Main cli = new Main(); cli.promptForNonLocalDatabase = Boolean.TRUE; cli.applyDefaults(); @@ -560,7 +560,7 @@ public void applyDefaults() { @Test(expected = CommandLineParsingException.class) public void propertiesFileWithBadArgs() throws Exception { - OldMain cli = new OldMain(); + Main cli = new Main(); Properties props = new Properties(); props.setProperty("driver", "DRIVER"); @@ -575,7 +575,7 @@ public void propertiesFileWithBadArgs() throws Exception { @Test public void checkSetup() { - OldMain cli = new OldMain(); + Main cli = new Main(); assertTrue(!cli.checkSetup().isEmpty()); cli.driver = "driver"; @@ -683,7 +683,7 @@ public void printHelp() throws Exception { final int MAXIMUM_LENGTH = 80; ByteArrayOutputStream stream = new ByteArrayOutputStream(); - OldMain cli = new OldMain(); + Main cli = new Main(); cli.printHelp(new PrintStream(stream)); BufferedReader reader = new BufferedReader(new StringReader(new String(stream.toByteArray()))); @@ -709,7 +709,7 @@ public void tag() throws Exception { "tag", "TagHere" }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals("Command line option --driver is parsed correctly", "DRIVER", cli.driver); @@ -732,7 +732,7 @@ public void migrateWithEqualsInParams() throws Exception { "migrate", }; - OldMain cli = new OldMain(); + Main cli = new Main(); cli.parseOptions(args); assertEquals(url, cli.url); @@ -740,7 +740,7 @@ public void migrateWithEqualsInParams() throws Exception { @Test public void fixArgs() { - OldMain liquibase = new OldMain(); + Main liquibase = new Main(); String[] fixedArgs = liquibase.fixupArgs(new String[]{"--defaultsFile", "liquibase.properties", "migrate"}); assertEquals("--defaultsFile=liquibase.properties migrate", StringUtil.join(Arrays.asList(fixedArgs), " ")); @@ -766,7 +766,7 @@ public void fixArgs() { @Test public void testVersionArg() throws Exception { - OldMain.run(new String[] {"--version"}); + Main.run(new String[] {"--version"}); assertTrue(true); // Just want to test if the call goes through } @@ -774,7 +774,7 @@ public void testVersionArg() throws Exception { public void testSplitArgWithValueEndingByEqualSing() throws CommandLineParsingException { final String argName = "password"; final String argValue = "s3-cr3t="; - OldMain tested = new OldMain(); + Main tested = new Main(); tested.parseOptions(new String[] { "--" + argName + "=" + argValue }); @@ -783,7 +783,7 @@ public void testSplitArgWithValueEndingByEqualSing() throws CommandLineParsingEx @Test public void testDatabaseChangeLogTableName_Properties() throws IOException, CommandLineParsingException { - OldMain main = new OldMain(); + Main main = new Main(); Properties props = new Properties(); props.setProperty("databaseChangeLogTableName", "PROPSCHANGELOG"); props.setProperty("databaseChangeLogLockTableName", "PROPSCHANGELOGLOCK"); @@ -798,7 +798,7 @@ public void testDatabaseChangeLogTableName_Properties() throws IOException, Comm @Test public void testDatabaseChangeLogTableName_Options() throws CommandLineParsingException { - OldMain main = new OldMain(); + Main main = new Main(); String[] opts = { "--databaseChangeLogTableName=OPTSCHANGELOG", "--databaseChangeLogLockTableName=OPTSCHANGELOGLOCK"}; diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java index 11180a22d21..1ae682a991a 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java @@ -6,10 +6,12 @@ import liquibase.Scope; import liquibase.database.Database; import liquibase.exception.LiquibaseException; +import liquibase.hub.HubConfiguration; import liquibase.resource.ClassLoaderResourceAccessor; import liquibase.resource.CompositeResourceAccessor; import liquibase.resource.FileSystemResourceAccessor; import liquibase.resource.ResourceAccessor; +import liquibase.util.StringUtil; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -105,18 +107,15 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti // // Store the Hub API key and URL for later use // - //TODO: - throw new RuntimeException("TODO"); -// HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); -// if (StringUtil.isNotEmpty(hubApiKey)) { -// hubConfiguration.setLiquibaseHubApiKey(hubApiKey); -// } -// if (StringUtil.isNotEmpty(hubUrl)) { -// hubConfiguration.setLiquibaseHubUrl(hubUrl); -// } -// if (StringUtil.isNotEmpty(hubMode)) { -// hubConfiguration.setLiquibaseHubMode(hubMode); -// } + if (StringUtil.isNotEmpty(hubApiKey)) { + System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), hubApiKey); + } + if (StringUtil.isNotEmpty(hubUrl)) { + System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), hubUrl); + } + if (StringUtil.isNotEmpty(hubMode)) { + System.setProperty(HubConfiguration.LIQUIBASE_HUB_MODE.getKey(), hubMode); + } } @Override diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java index ab4f08cad03..ff0e5aa43d9 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseGenerateChangeLogMojo.java @@ -1,11 +1,15 @@ package org.liquibase.maven.plugins; +import liquibase.GlobalConfiguration; import liquibase.Liquibase; +import liquibase.Scope; import liquibase.database.Database; import liquibase.diff.output.DiffOutputControl; import liquibase.diff.output.StandardObjectChangeFilter; import liquibase.exception.LiquibaseException; import liquibase.exception.UnexpectedLiquibaseException; +import liquibase.integration.commandline.CommandLineUtils; +import liquibase.util.StringUtil; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -110,15 +114,12 @@ protected void performLiquibaseTask(Liquibase liquibase) // Set the global configuration option based on presence of the dataOutputDirectory // boolean b = dataDir != null; - //todo - throw new RuntimeException("TODO"); -// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); - -// CommandLineUtils.doGenerateChangeLog(outputChangeLogFile, database, defaultCatalogName, defaultSchemaName, StringUtil.trimToNull(diffTypes), -// StringUtil.trimToNull(changeSetAuthor), StringUtil.trimToNull(changeSetContext), StringUtil.trimToNull(dataDir), diffOutputControl); -// getLog().info("Output written to Change Log file, " + outputChangeLogFile); - } - catch (Throwable e) { + Scope.child(GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getKey(), b, () -> { + CommandLineUtils.doGenerateChangeLog(outputChangeLogFile, database, defaultCatalogName, defaultSchemaName, StringUtil.trimToNull(diffTypes), + StringUtil.trimToNull(changeSetAuthor), StringUtil.trimToNull(changeSetContext), StringUtil.trimToNull(dataDir), diffOutputControl); + getLog().info("Output written to Change Log file, " + outputChangeLogFile); + }); + } catch (Exception e) { throw new LiquibaseException(e); } } From c643e4bda69d2451c61fbf0178180e321d31d884 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Fri, 5 Feb 2021 15:01:31 -0600 Subject: [PATCH 07/17] Finished adjusting code to match new LiquibaseConfiguration pattern. --- .../src/main/java/liquibase/Liquibase.java | 13 +- .../src/main/java/liquibase/Scope.java | 4 +- .../liquibase/command/AbstractCommand.java | 2 - .../liquibase/command/CommandFactory.java | 3 + .../liquibase/command/LiquibaseCommand.java | 4 + .../command/core/SyncHubCommand.java | 2 - .../configuration/CurrentValueDetails.java | 1 - .../configuration/LiquibaseConfiguration.java | 39 ++++-- .../core/SystemPropertyValueProvider.java | 1 - .../main/java/liquibase/hub/HubUpdater.java | 22 ++-- .../java/liquibase/hub/core/HttpClient.java | 7 +- .../hub/core/StandardHubService.java | 2 +- .../integration/ant/BaseLiquibaseTask.java | 1 - .../integration/commandline/Main.java | 31 ++--- .../servlet/LiquibaseServletListener.java | 11 +- .../logging/core/AbstractLogger.java | 2 +- .../groovy/liquibase/LiquibaseTest.groovy | 42 +++--- .../command/core/DropAllCommandTest.groovy | 32 ++--- .../hub/core/StandardHubServiceTest.groovy | 69 +++++----- .../changelog/ChangeLogParametersTest.java | 2 - .../changelog/ExpressionExpanderTest.java | 124 +++++++++--------- .../integration/commandline/MainTest.java | 21 +-- .../hub/StandardHubServiceTest.groovy | 15 ++- .../dbtest/AbstractIntegrationTest.java | 8 +- 24 files changed, 238 insertions(+), 220 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/Liquibase.java b/liquibase-core/src/main/java/liquibase/Liquibase.java index 2a6f1d20b4a..f916f666aad 100644 --- a/liquibase-core/src/main/java/liquibase/Liquibase.java +++ b/liquibase-core/src/main/java/liquibase/Liquibase.java @@ -8,7 +8,6 @@ import liquibase.command.CommandExecutionException; import liquibase.command.CommandFactory; import liquibase.command.core.DropAllCommand; -import liquibase.configuration.HubConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; @@ -26,10 +25,7 @@ import liquibase.executor.Executor; import liquibase.executor.ExecutorService; import liquibase.executor.LoggingExecutor; -import liquibase.hub.HubService; -import liquibase.hub.HubServiceFactory; -import liquibase.hub.HubUpdater; -import liquibase.hub.LiquibaseHubException; +import liquibase.hub.*; import liquibase.hub.listener.HubChangeExecListener; import liquibase.hub.model.Connection; import liquibase.hub.model.HubChangeLog; @@ -315,13 +311,12 @@ public Connection getConnection(DatabaseChangeLog changeLog) throws LiquibaseHub if (executor instanceof LoggingExecutor) { return null; } - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); String changeLogId = changeLog.getChangeLogId(); HubUpdater hubUpdater = new HubUpdater(new Date(), changeLog, database); if (hubUpdater.hubIsNotAvailable(changeLogId)) { - if (StringUtil.isNotEmpty(hubConfiguration.getLiquibaseHubApiKey()) && changeLogId == null) { + if (StringUtil.isNotEmpty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()) && changeLogId == null) { String message = - "The API key '" + hubConfiguration.getLiquibaseHubApiKey() + "' was found, but no changelog ID exists.\n" + + "The API key '" + HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue() + "' was found, but no changelog ID exists.\n" + "No operations will be reported. Register this changelog with Liquibase Hub to generate free deployment reports.\n" + "Learn more at https://hub.liquibase.com."; Scope.getCurrentScope().getUI().sendMessage("WARNING: " + message); @@ -333,7 +328,7 @@ public Connection getConnection(DatabaseChangeLog changeLog) throws LiquibaseHub // // Warn about the situation where there is a changeLog ID, but no API key // - if (StringUtil.isEmpty(hubConfiguration.getLiquibaseHubApiKey()) && changeLogId != null) { + if (StringUtil.isEmpty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()) && changeLogId != null) { String message = "The changelog ID '" + changeLogId + "' was found, but no API Key exists.\n" + "No operations will be reported. Simply add a liquibase.hub.apiKey setting to generate free deployment reports.\n" + "Learn more at https://hub.liquibase.com."; diff --git a/liquibase-core/src/main/java/liquibase/Scope.java b/liquibase-core/src/main/java/liquibase/Scope.java index df3bf6ccc1b..7439869d667 100644 --- a/liquibase-core/src/main/java/liquibase/Scope.java +++ b/liquibase-core/src/main/java/liquibase/Scope.java @@ -39,7 +39,6 @@ public class Scope { public enum Attr { logService, ui, - configuration, resourceAccessor, classLoader, database, @@ -68,13 +67,12 @@ public static Scope getCurrentScope() { Scope rootScope = new Scope(); scopeManager.setCurrentScope(rootScope); - rootScope.values.put(LiquibaseConfiguration.class.getName(), new LiquibaseConfiguration()); rootScope.values.put(Attr.logService.name(), new JavaLogService()); rootScope.values.put(Attr.resourceAccessor.name(), new ClassLoaderResourceAccessor()); rootScope.values.put(Attr.serviceLocator.name(), new StandardServiceLocator()); rootScope.values.put(Attr.ui.name(), new ConsoleUIService()); - rootScope.get(LiquibaseConfiguration.class.getName(), LiquibaseConfiguration.class).init(rootScope); + rootScope.getSingleton(LiquibaseConfiguration.class).init(rootScope); LogService overrideLogService = rootScope.getSingleton(LogServiceFactory.class).getDefaultLogService(); if (overrideLogService == null) { diff --git a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java index 54902574184..2be7820f055 100644 --- a/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/AbstractCommand.java @@ -1,7 +1,5 @@ package liquibase.command; -import liquibase.servicelocator.PrioritizedService; - import java.util.SortedSet; import java.util.TreeSet; diff --git a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java index 7822c10b67f..03e2d911548 100644 --- a/liquibase-core/src/main/java/liquibase/command/CommandFactory.java +++ b/liquibase-core/src/main/java/liquibase/command/CommandFactory.java @@ -7,6 +7,9 @@ */ public class CommandFactory extends AbstractPluginFactory<LiquibaseCommand> { + protected CommandFactory() { + } + @Override protected Class<LiquibaseCommand> getPluginClass() { return LiquibaseCommand.class; diff --git a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java index 684185fdbb5..bab1d21652b 100644 --- a/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/LiquibaseCommand.java @@ -19,5 +19,9 @@ public interface LiquibaseCommand<T extends CommandResult> extends Plugin { CommandValidationErrors validate(); + /** + * Function that performs the actual logic. This should not be called directly by any code, + * only by {@link CommandFactory#execute(LiquibaseCommand)} + */ T run() throws Exception; } diff --git a/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java b/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java index a3cd14a07b0..218d77d3eb9 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/SyncHubCommand.java @@ -5,8 +5,6 @@ import liquibase.command.AbstractSelfConfiguratingCommand; import liquibase.command.CommandResult; import liquibase.command.CommandValidationErrors; -import liquibase.configuration.HubConfiguration; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.hub.HubService; import liquibase.hub.HubServiceFactory; diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java index e115f92b1fa..bd47dc0b4dd 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java +++ b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Stack; /** * Detailed information about the current configuration value. diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index 515ca9ada2b..745f7232a64 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -2,12 +2,10 @@ import liquibase.Scope; import liquibase.SingletonObject; +import liquibase.integration.servlet.LiquibaseServletListener; import liquibase.servicelocator.ServiceLocator; -import java.util.Collections; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.*; /** * Provides unified management of configuration properties within Liquibase core and in extensions. @@ -25,11 +23,7 @@ public class LiquibaseConfiguration implements SingletonObject { private final SortedSet<ConfigurationValueProvider> configurationValueProviders; private final SortedSet<ConfigurationDefinition> definitions = new TreeSet<>(); - public static LiquibaseConfiguration getInstance() { - return Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); - } - - public LiquibaseConfiguration() { + protected LiquibaseConfiguration() { configurationValueProviders = new TreeSet<>((o1, o2) -> { if (o1.getPrecedence() < o2.getPrecedence()) { return -1; @@ -63,6 +57,16 @@ public void addProvider(ConfigurationValueProvider valueProvider) { this.configurationValueProviders.add(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); + } + + /** * Searches for the given key in the current providers. * @@ -98,4 +102,21 @@ public void registerDefinition(ConfigurationDefinition definition) { public SortedSet<ConfigurationDefinition> getRegisteredDefinitions() { return Collections.unmodifiableSortedSet(this.definitions); } + + /** + * @return the registered {@link ConfigurationDefinition} asssociated with this key. Null if none match. + */ + public ConfigurationDefinition getRegisteredDefinition(String key) { + for (ConfigurationDefinition def : getRegisteredDefinitions()) { + if (def.getKey().equalsIgnoreCase(key)) { + return def; + } + final Set aliasKeys = def.getAliasKeys(); + if (aliasKeys != null && aliasKeys.contains(def.getKey())) { + return def; + } + } + + return null; + } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java index 4c1ec881b24..7ab892f3cb6 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java @@ -1,7 +1,6 @@ package liquibase.configuration.core; import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.CurrentValueDetails; import liquibase.configuration.CurrentValueSourceDetails; import liquibase.util.StringUtil; diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index dd698fb7444..f8c70367ced 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -11,9 +11,7 @@ import liquibase.command.CommandResult; import liquibase.command.core.RegisterChangeLogCommand; import liquibase.command.core.SyncHubCommand; -import liquibase.configuration.ConfigurationProperty; -import liquibase.configuration.GlobalConfiguration; -import liquibase.configuration.HubConfiguration; +import liquibase.configuration.CurrentValue; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseConnection; @@ -301,7 +299,6 @@ public void register(String changeLogFile) // // Just return if Hub is off // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); final HubService hubService = Scope.getCurrentScope().getSingleton(HubServiceFactory.class).getService(); if (!hubService.isOnline()) { return; @@ -312,7 +309,7 @@ public void register(String changeLogFile) // 1. We have a key already OR // 2. We have a changeLogId already // - if (!StringUtil.isEmpty(hubConfiguration.getLiquibaseHubApiKey()) || + if (!StringUtil.isEmpty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getCurrentValue()) || changeLog.getChangeLogId() != null) { return; } @@ -405,15 +402,15 @@ public void register(String changeLogFile) // If there is no liquibase.hub.mode setting then add one with value 'all' // Do not update liquibase.hub.mode if it is already set // - ConfigurationProperty hubModeProperty = hubConfiguration.getProperty(HubConfiguration.LIQUIBASE_HUB_MODE); - if (! hubModeProperty.getWasOverridden()) { + CurrentValue<String> hubModeProperty = HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValueDetails(); + if (hubModeProperty.getDefaultValueUsed()) { writeToPropertiesFile(defaultsFile, "\nliquibase.hub.mode=all\n"); message = "* Updated properties file " + defaultsFile + " to set liquibase.hub properties"; Scope.getCurrentScope().getUI().sendMessage(message); Scope.getCurrentScope().getLog(getClass()).info(message); } else { message = "* Updated the liquibase.hub.apiKey property."; - String message2 = "The liquibase.hub.mode is already set to " + hubConfiguration.getLiquibaseHubMode() + ". It will not be updated."; + String message2 = "The liquibase.hub.mode is already set to " + hubModeProperty.getValue() + ". It will not be updated."; Scope.getCurrentScope().getUI().sendMessage(message); Scope.getCurrentScope().getUI().sendMessage(message2); Scope.getCurrentScope().getLog(getClass()).warning(message); @@ -427,7 +424,7 @@ public void register(String changeLogFile) message = "* Registering changelog file " + changeLogFile + " with Hub"; Scope.getCurrentScope().getUI().sendMessage(message); Scope.getCurrentScope().getLog(getClass()).info(message); - hubConfiguration.setLiquibaseHubApiKey(registerResponse.getApiKey()); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), registerResponse.getApiKey()); registerChangeLog(registerResponse.getProjectId(), changeLog, changeLogFile); message = "Great! Your free operation and deployment reports will be available to you after your local Liquibase commands complete."; @@ -443,7 +440,8 @@ public void register(String changeLogFile) "No operations will be reported."; Scope.getCurrentScope().getUI().sendMessage(message); Scope.getCurrentScope().getLog(getClass()).warning(message); - hubConfiguration.setLiquibaseHubApiKey(null); + + System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), null); } } } @@ -452,7 +450,7 @@ public void register(String changeLogFile) // Write the string to a properties file // private void writeToPropertiesFile(File defaultsFile, String stringToWrite) throws IOException { - String encoding = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); try (RandomAccessFile randomAccessFile = new RandomAccessFile(defaultsFile, "rw")) { randomAccessFile.seek(defaultsFile.length()); randomAccessFile.write(stringToWrite.getBytes(encoding)); @@ -486,7 +484,7 @@ private void registerChangeLog(UUID hubProjectId, DatabaseChangeLog changeLog, S // // Execute registerChangeLog // - CommandResult result = registerChangeLogCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(registerChangeLogCommand); Scope.getCurrentScope().getUI().sendMessage(result.print()); } diff --git a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java index 65603594341..c250d25c306 100644 --- a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java +++ b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java @@ -181,11 +181,8 @@ protected <T> T doRequest(String method, String url, Object requestBodyObject, newHubUrl = newHubUrl.replaceAll(url, ""); Scope.getCurrentScope().getLog(getClass()).info("Redirecting to URL: " + newHubUrl); - //TODO - throw new RuntimeException("TODO: "); -// HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); -// hubConfiguration.setLiquibaseHubUrl(newHubUrl); -// throw new LiquibaseHubRedirectException(); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), newHubUrl); + throw new LiquibaseHubRedirectException(); } } diff --git a/liquibase-core/src/main/java/liquibase/hub/core/StandardHubService.java b/liquibase-core/src/main/java/liquibase/hub/core/StandardHubService.java index e8cd7a37c9a..b6b6573de62 100644 --- a/liquibase-core/src/main/java/liquibase/hub/core/StandardHubService.java +++ b/liquibase-core/src/main/java/liquibase/hub/core/StandardHubService.java @@ -45,7 +45,7 @@ public int getPriority() { @Override public boolean isOnline() { - return !LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).getLiquibaseHubMode().equalsIgnoreCase("OFF"); + return !HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValue().equalsIgnoreCase("OFF"); } public boolean isHubAvailable() { diff --git a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java index b2ed1d495b2..0e3c36b285f 100644 --- a/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java +++ b/liquibase-core/src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java @@ -136,7 +136,6 @@ protected String getChangeLogFile() { } protected boolean shouldRun() { - LiquibaseConfiguration configuration = LiquibaseConfiguration.getInstance(); if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { log("Liquibase did not run because " + GlobalConfiguration.SHOULD_RUN.getKey() + " was set to false", Project.MSG_INFO); return false; diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 53bcaeada58..39a5b86f740 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -10,6 +10,7 @@ import liquibase.command.LiquibaseCommand; import liquibase.command.core.*; import liquibase.GlobalConfiguration; +import liquibase.configuration.LiquibaseConfiguration; import liquibase.hub.HubConfiguration; import liquibase.database.Database; import liquibase.diff.compare.CompareControl; @@ -340,16 +341,14 @@ public Integer run() throws Exception { // Store the Hub API key for later use // if (StringUtil.isNotEmpty(main.liquibaseHubApiKey)) { - //TODO: -// hubConfiguration.setLiquibaseHubApiKey(main.liquibaseHubApiKey); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), main.liquibaseHubApiKey); } // // Store the Hub URL for later use // if (StringUtil.isNotEmpty(main.liquibaseHubUrl)) { - //TODO: -// hubConfiguration.setLiquibaseHubUrl(main.liquibaseHubUrl); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), main.liquibaseHubUrl); } main.applyDefaults(); @@ -1007,23 +1006,7 @@ protected void parsePropertiesFile(InputStream propertiesInputStream) throws IOE if (((String) entry.getKey()).startsWith("parameter.")) { changeLogParameters.put(((String) entry.getKey()).replaceFirst("^parameter.", ""), entry.getValue()); } else if (((String) entry.getKey()).contains(".")) { - // - // Determine the namespace and value keys - // then set the property value - // - final String[] splitKey = ((String) entry.getKey()).split("\\.", 3); - String namespace=""; - for (int i=0; i < splitKey.length-1; i++) { - if (! namespace.equals("")) { - namespace += "."; - } - namespace += splitKey[i]; - } - String valueKey = splitKey[splitKey.length-1]; - try { - //TODO: LiquibaseConfiguration.getInstance().getConfiguration(namespace).setValue(valueKey, entry.getValue()); - } - catch (Exception e) { + if (Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getRegisteredDefinition((String) entry.getKey()) == null) { if (strict) { throw new CommandLineParsingException( String.format(coreBundle.getString("parameter.unknown"), entry.getKey()) @@ -1034,6 +1017,9 @@ protected void parsePropertiesFile(InputStream propertiesInputStream) throws IOE ); } } + if (System.getProperty((String) entry.getKey()) == null) { + System.setProperty((String) entry.getKey(), (String) entry.getValue()); + } } else { Field field = getDeclaredField((String)entry.getKey()); Object currentValue = field.get(this); @@ -1424,8 +1410,7 @@ protected void doMigration() throws Exception { // Set the global configuration option based on presence of the dataOutputDirectory // boolean b = dataOutputDirectory != null; - //TODO: -// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).setShouldSnapshotData(b); + System.setProperty(GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getKey(), String.valueOf(b)); ObjectChangeFilter objectChangeFilter = null; CompareControl.ComputedSchemas computedSchemas = CompareControl.computeSchemas( diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java index 4327380f88a..c93730ecaf6 100644 --- a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java @@ -3,6 +3,7 @@ import liquibase.*; import liquibase.configuration.ConfigurationValueProvider; import liquibase.configuration.CurrentValueSourceDetails; +import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.core.DerbyDatabase; @@ -96,6 +97,8 @@ public String getDefaultSchema() { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { ServletContext servletContext = servletContextEvent.getServletContext(); + final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); + try { this.hostName = NetUtil.getLocalHostName(); } catch (Exception e) { @@ -110,7 +113,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { Scope.getCurrentScope().getUI().setAllowPrompt(false); servletValueContainer = new ServletValueContainer(servletContext, ic); - //TODO: LiquibaseConfiguration.getInstance().init(servletValueContainer); + liquibaseConfiguration.addProvider(servletValueContainer); failOnError = (String) servletValueContainer.getValue(LIQUIBASE_ONERROR_FAIL).getValue(); if (checkPreconditions(servletContext, ic)) { @@ -129,6 +132,9 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { // ignore } } + liquibaseConfiguration.removeProvider(servletValueContainer); + + } } @@ -254,7 +260,7 @@ protected class ServletValueContainer implements ConfigurationValueProvider { @Override public int getPrecedence() { - return 0; + return 30; } private ServletContext servletContext; @@ -291,7 +297,6 @@ public CurrentValueSourceDetails getValue(String key) { return new CurrentValueSourceDetails(valueFromServletContext, "Servlet context value", key); } - // Otherwise: Return system property return new CurrentValueSourceDetails(System.getProperty(key), "System property", key); } } diff --git a/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java b/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java index 7de09661ed7..cba68b249dd 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/AbstractLogger.java @@ -82,7 +82,7 @@ public void debug(String message, Throwable e) { protected String filterMessage(String message) { try { - if (filter == null || !GlobalConfiguration.FILTER_LOG_MESSAGES.getCurrentValue()) { + if (filter == null || GlobalConfiguration.FILTER_LOG_MESSAGES == null || !GlobalConfiguration.FILTER_LOG_MESSAGES.getCurrentValue()) { return message; } } catch (UnknownConfigurationType unknownConfigurationType) { diff --git a/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy b/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy index cb1e9fb97a1..0b9344641e5 100644 --- a/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy @@ -1,13 +1,11 @@ package liquibase - import liquibase.changelog.ChangeLogIterator import liquibase.changelog.DatabaseChangeLog -import liquibase.configuration.HubConfiguration -import liquibase.configuration.LiquibaseConfiguration import liquibase.database.Database import liquibase.database.core.MockDatabase import liquibase.exception.LiquibaseException +import liquibase.hub.HubConfiguration import liquibase.hub.HubService import liquibase.hub.HubServiceFactory import liquibase.hub.core.MockHubService @@ -19,7 +17,6 @@ import liquibase.parser.ChangeLogParserFactory import liquibase.parser.MockChangeLogParser import liquibase.sdk.resource.MockResourceAccessor import liquibase.ui.ConsoleUIService -import liquibase.ui.ConsoleUIServiceTest import spock.lang.Specification import static org.junit.Assert.* @@ -187,10 +184,12 @@ class LiquibaseTest extends Specification { def "update communicates with hub"() { given: Liquibase liquibase = new Liquibase("com/example/changelog.mock", mockResourceAccessor, mockDatabase) - LiquibaseConfiguration.instance.getConfiguration(HubConfiguration.class).setLiquibaseHubApiKey("API_KEY") when: - liquibase.update("") + Scope.child(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), "API_KEY", { + liquibase.update("") + }) + then: mockHubService.sentObjects.toString() == @@ -207,13 +206,17 @@ class LiquibaseTest extends Specification { when: Liquibase liquibase = new Liquibase("com/example/changelog.mock", mockResourceAccessor, mockDatabase) - LiquibaseConfiguration.instance.getConfiguration(HubConfiguration.class).setLiquibaseHubApiKey(null) - DatabaseChangeLog changeLog = liquibase.getDatabaseChangeLog() + Connection connection = null; + String message = null; def changeLogId = UUID.randomUUID().toString() - changeLog.setChangeLogId(changeLogId) - Connection connection = liquibase.getConnection(changeLog) - List<String> messages = uiService.getMessages() - String message = messages.get(0) + + Scope.child(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), null, { + DatabaseChangeLog changeLog = liquibase.getDatabaseChangeLog() + changeLog.setChangeLogId(changeLogId) + connection = liquibase.getConnection(changeLog) + List<String> messages = uiService.getMessages() + message = messages.get(0) + }) Scope.exit(scopeId) then: @@ -233,12 +236,15 @@ class LiquibaseTest extends Specification { when: Liquibase liquibase = new Liquibase("com/example/changelog.mock", mockResourceAccessor, mockDatabase) - LiquibaseConfiguration.instance.getConfiguration(HubConfiguration.class).setLiquibaseHubApiKey("API_KEY") - DatabaseChangeLog changeLog = liquibase.getDatabaseChangeLog() - changeLog.setChangeLogId(null) - Connection connection = liquibase.getConnection(changeLog) - List<String> messages = uiService.getMessages() - String message = messages.get(0) + Connection connection = null + String message = null + Scope.child(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), "API_KEY", { + DatabaseChangeLog changeLog = liquibase.getDatabaseChangeLog() + changeLog.setChangeLogId(null) + connection = liquibase.getConnection(changeLog) + List<String> messages = uiService.getMessages() + message = messages.get(0) + }) Scope.exit(scopeId) then: diff --git a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy index 5856a0d69af..d630c9af1a7 100644 --- a/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/command/core/DropAllCommandTest.groovy @@ -2,9 +2,9 @@ package liquibase.command.core import liquibase.Liquibase import liquibase.Scope -import liquibase.hub.HubConfiguration -import liquibase.configuration.LiquibaseConfiguration +import liquibase.command.CommandResult import liquibase.database.core.MockDatabase +import liquibase.hub.HubConfiguration import liquibase.hub.HubService import liquibase.hub.core.MockHubService import liquibase.logging.core.BufferedLogService @@ -63,22 +63,22 @@ class DropAllCommandTest extends Specification { BufferedLogService bufferLog = new BufferedLogService() Scope.getCurrentScope().getUI() - HubConfiguration.LIQUIBASE_HUB_API_KEY.setLiquibaseHubApiKey(UUID.randomUUID().toString()) - def command = new DropAllCommand() - JUnitResourceAccessor testResourceAccessor = new JUnitResourceAccessor() - Liquibase liquibase = new Liquibase(outputFile.getName(), testResourceAccessor, new MockDatabase()) - command.setLiquibase(liquibase) - command.setChangeLogFile(outputFile.getName()) - command.setDatabase(new MockDatabase()) - command.setSchemas("") - def result - CompositeLogService compositeLogService = new CompositeLogService(true, bufferLog); - Scope.child(Scope.Attr.logService.name(), compositeLogService, new Scope.ScopedRunner() { - public void run() { + CommandResult result = null + Scope.child(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), UUID.randomUUID().toString(), { + def command = new DropAllCommand() + JUnitResourceAccessor testResourceAccessor = new JUnitResourceAccessor() + Liquibase liquibase = new Liquibase(outputFile.getName(), testResourceAccessor, new MockDatabase()) + command.setLiquibase(liquibase) + command.setChangeLogFile(outputFile.getName()) + command.setDatabase(new MockDatabase()) + command.setSchemas("") + + CompositeLogService compositeLogService = new CompositeLogService(true, bufferLog); + Scope.child(Scope.Attr.logService.name(), compositeLogService, { result = command.run() - } - }); + }) + }) then: result.succeeded diff --git a/liquibase-core/src/test/groovy/liquibase/hub/core/StandardHubServiceTest.groovy b/liquibase-core/src/test/groovy/liquibase/hub/core/StandardHubServiceTest.groovy index b3d1525559b..4394d4a0892 100644 --- a/liquibase-core/src/test/groovy/liquibase/hub/core/StandardHubServiceTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/hub/core/StandardHubServiceTest.groovy @@ -1,7 +1,7 @@ package liquibase.hub.core +import liquibase.Scope import liquibase.hub.HubConfiguration -import liquibase.configuration.LiquibaseConfiguration import liquibase.hub.model.Connection import liquibase.hub.model.OperationChangeEvent import liquibase.hub.model.Project @@ -12,10 +12,6 @@ class StandardHubServiceTest extends Specification { private static testUuid = UUID.fromString("3b8b6f80-1194-4a70-8cf2-30f33fd0433e") - def cleanup() { -// LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode("all") - } - @Unroll def "toSearchString"() { expect: @@ -51,36 +47,39 @@ class StandardHubServiceTest extends Specification { def operationId = UUID.randomUUID() when: -//TODO: LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class).setLiquibaseHubMode(mode) - - def mockHttpClient = new MockHttpClient([ - "GET /api/v1/organizations" : MockHttpClient.createListResponse([ - id : orgId.toString(), - name: "Mock Org" - ]), - ("POST /api/v1/organizations/$orgId/projects/$projectId/operations/$operationId/change-events" as String): null, - ]) - - def service = new StandardHubService( - http: mockHttpClient - ) - - def event = new OperationChangeEvent( - eventType: "update", - changesetId: "1", - project: [ - id: projectId, - ], - operation: [ - id: operationId, - ], - changesetAuthor: "tester", - generatedSql: ["select sql here"], - changesetBody: "{ body }" - ) - service.sendOperationChangeEvent(event) - - def seenRequestBody = mockHttpClient.getRequestBody("POST /api/v1/organizations/$orgId/projects/$projectId/operations/$operationId/change-events") + def seenRequestBody + + Scope.child([(HubConfiguration.LIQUIBASE_HUB_MODE.getKey()): mode], { + + def mockHttpClient = new MockHttpClient([ + "GET /api/v1/organizations" : MockHttpClient.createListResponse([ + id : orgId.toString(), + name: "Mock Org" + ]), + ("POST /api/v1/organizations/$orgId/projects/$projectId/operations/$operationId/change-events" as String): null, + ]) + + def service = new StandardHubService( + http: mockHttpClient + ) + + def event = new OperationChangeEvent( + eventType: "update", + changesetId: "1", + project: [ + id: projectId, + ], + operation: [ + id: operationId, + ], + changesetAuthor: "tester", + generatedSql: ["select sql here"], + changesetBody: "{ body }" + ) + service.sendOperationChangeEvent(event) + + seenRequestBody = mockHttpClient.getRequestBody("POST /api/v1/organizations/$orgId/projects/$projectId/operations/$operationId/change-events") + } as Scope.ScopedRunner) then: seenRequestBody.changesetBody == (mode == "meta" ? null : "{ body }") diff --git a/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java b/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java index a708c0975bf..278d59b2e6a 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/ChangeLogParametersTest.java @@ -3,9 +3,7 @@ import liquibase.ContextExpression; import liquibase.Contexts; import liquibase.Labels; -import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.core.H2Database; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java index 1f721f61113..f350c923ec2 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/ExpressionExpanderTest.java @@ -1,15 +1,17 @@ package liquibase.changelog; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.Scope; import liquibase.parser.ChangeLogParserConfiguration; import org.junit.Before; import org.junit.Test; +import java.util.Collections; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; public class ExpressionExpanderTest { - + private ChangeLogParameters.ExpressionExpander handler; private ChangeLogParameters changeLogParameters; @@ -52,76 +54,80 @@ public void expandExpressions_nomatchExpression() { assertEquals("A string no expressions ${notset} set", handler.expandExpressions("A string no expressions ${notset} set", null)); assertEquals("A string no expressions ${notset.orParams} set", handler.expandExpressions("A string no expressions ${notset.orParams} set", null)); } - + @Test - public void expandExpressions_escapedSimple() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("${user.name}", handler.expandExpressions("${:user.name}", null)); + public void expandExpressions_escapedSimple() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("${user.name}", handler.expandExpressions("${:user.name}", null)); + }); } - + @Test - public void expandExpressions_escapedNonGreedy() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("${user.name}${user.name}", handler.expandExpressions("${:user.name}${:user.name}", null)); + public void expandExpressions_escapedNonGreedy() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("${user.name}${user.name}", handler.expandExpressions("${:user.name}${:user.name}", null)); + }); } - + @Test - public void expandExpressions_escapedMultipleSimple() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("${user.name} and ${user.name} are literals", -// handler.expandExpressions("${:user.name} and ${:user.name} are literals", null)); + public void expandExpressions_escapedMultipleSimple() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("${user.name} and ${user.name} are literals", + handler.expandExpressions("${:user.name} and ${:user.name} are literals", null)); + }); } - + @Test - public void expandExpressions_escapedMultipleComplex() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("${user.name} and ${user.name} are literals but this isn't: " + System.getProperty("user.name"), -// handler.expandExpressions("${:user.name} and ${:user.name} are literals but this isn't: ${user.name}", null)); + public void expandExpressions_escapedMultipleComplex() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("${user.name} and ${user.name} are literals but this isn't: " + System.getProperty("user.name"), + handler.expandExpressions("${:user.name} and ${:user.name} are literals but this isn't: ${user.name}", null)); + }); } - + @Test - public void expandExpressions_escapedBeforeVariable() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("${user.name} is a literal, " + System.getProperty("user.name") + " is a variable", -// handler.expandExpressions("${:user.name} is a literal, ${user.name} is a variable", null)); + public void expandExpressions_escapedBeforeVariable() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("${user.name} is a literal, " + System.getProperty("user.name") + " is a variable", + handler.expandExpressions("${:user.name} is a literal, ${user.name} is a variable", null)); + }); } - + @Test - public void expandExpressions_escapedAfterVariable() { - //TODO -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals(System.getProperty("user.name") + " is a variable, ${user.name} is a literal", -// handler.expandExpressions("${user.name} is a variable, ${:user.name} is a literal", null)); + public void expandExpressions_escapedAfterVariable() throws Exception { + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals(System.getProperty("user.name") + " is a variable, ${user.name} is a literal", + handler.expandExpressions("${user.name} is a variable, ${:user.name} is a literal", null)); + }); } - + @Test - public void expandExpressions_escapedMultipleComplexVariant() { - //TODO -// changeLogParameters.set("a", "Value A"); -// changeLogParameters.set("b", "Value B"); -// -// LiquibaseConfiguration.getInstance().getConfiguration(ChangeLogParserConfiguration.class).setSupportPropertyEscaping(true); -// this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); -// -// assertEquals("Value A is a variable, ${a} and ${b} are literals but this isn't: Value B", -// handler.expandExpressions("${a} is a variable, ${:a} and ${:b} are literals but this isn't: ${b}", null)); + public void expandExpressions_escapedMultipleComplexVariant() throws Exception { + changeLogParameters.set("a", "Value A"); + changeLogParameters.set("b", "Value B"); + + Scope.child(Collections.singletonMap(ChangeLogParserConfiguration.SUPPORT_PROPERTY_ESCAPING.getKey(), true), () -> { + + this.handler = new ChangeLogParameters.ExpressionExpander(changeLogParameters); + + assertEquals("Value A is a variable, ${a} and ${b} are literals but this isn't: Value B", + handler.expandExpressions("${a} is a variable, ${:a} and ${:b} are literals but this isn't: ${b}", null)); + }); } } diff --git a/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java b/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java index ed80115c820..34351daa804 100644 --- a/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/commandline/MainTest.java @@ -1,10 +1,14 @@ package liquibase.integration.commandline; +import liquibase.GlobalConfiguration; +import liquibase.Scope; import liquibase.exception.CommandLineParsingException; +import liquibase.parser.ChangeLogParserConfiguration; import liquibase.util.StringUtil; import org.junit.Assert; import org.junit.Test; +import java.util.Collections; import java.util.Properties; import java.util.Arrays; import java.util.List; @@ -127,15 +131,14 @@ public void startWithoutParameters() throws Exception { assertTrue("We just want to survive until this point", true); } -// @Test -// public void globalConfigurationSaysDoNotRun() throws Exception { -// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) -// .setValue("shouldRun", false); -// int errorLevel = OldMain.run(new String[0]); -// LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) -// .setValue("shouldRun", true); -// assertEquals(errorLevel, 0); // If it SHOULD run, and we would call without parameters, we would get -1 -// } + @Test + public void globalConfigurationSaysDoNotRun() throws Exception { + Scope.child(Collections.singletonMap(GlobalConfiguration.SHOULD_RUN.getKey(), false), () -> { + + int errorLevel = Main.run(new String[0]); + assertEquals(errorLevel, 0); // If it SHOULD run, and we would call without parameters, we would get -1 + }); + } // @Test // public void mockedSnapshotRun() throws Exception { diff --git a/liquibase-integration-tests/src/test/groovy/liquibase/hub/StandardHubServiceTest.groovy b/liquibase-integration-tests/src/test/groovy/liquibase/hub/StandardHubServiceTest.groovy index db4c110d6ee..a23ff624f97 100644 --- a/liquibase-integration-tests/src/test/groovy/liquibase/hub/StandardHubServiceTest.groovy +++ b/liquibase-integration-tests/src/test/groovy/liquibase/hub/StandardHubServiceTest.groovy @@ -1,5 +1,6 @@ package liquibase.hub +import liquibase.Scope import liquibase.configuration.LiquibaseConfiguration import liquibase.hub.core.StandardHubService import liquibase.hub.model.Connection @@ -16,6 +17,8 @@ class StandardHubServiceTest extends Specification { private UUID knownProjectId = UUID.fromString("ce1a237e-e005-4288-a243-4856823a25a6") private UUID knownConnectionId = UUID.fromString("d92e6505-cd0f-4e91-bb66-b12e6a285184") + private String testScopeId + def setup() { if (integrationTestProperties == null) { integrationTestProperties = new Properties() @@ -26,10 +29,10 @@ class StandardHubServiceTest extends Specification { integrationTestProperties.load(localFileStream) } - def hubApiKey = integrationTestProperties.get("integration.test.hub.apikey") - def hubUrl = integrationTestProperties.get("integration.test.hub.url") - //TODO: hubConfiguration.setLiquibaseHubApiKey(hubApiKey) - //TODO: hubConfiguration.setLiquibaseHubUrl(hubUrl) + testScopeId = Scope.enter([ + (HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey()):integrationTestProperties.get("integration.test.hub.apikey"), + (HubConfiguration.LIQUIBASE_HUB_URL.getKey()):integrationTestProperties.get("integration.test.hub.url"), + ]) } @@ -37,6 +40,10 @@ class StandardHubServiceTest extends Specification { assumeTrue("Liquibase Hub is not available for testing", hubService.isHubAvailable()) } + def cleanup() { + Scope.exit(testScopeId) + } + def getMe() { when: def hubUser = integrationTestProperties.get("integration.test.hub.userName") diff --git a/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java b/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java index 8d528c8ae41..d6267500940 100644 --- a/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java +++ b/liquibase-integration-tests/src/test/java/liquibase/dbtest/AbstractIntegrationTest.java @@ -22,6 +22,7 @@ import liquibase.exception.ValidationFailedException; import liquibase.executor.Executor; import liquibase.executor.ExecutorService; +import liquibase.hub.HubConfiguration; import liquibase.listener.SqlListener; import liquibase.lockservice.LockService; import liquibase.lockservice.LockServiceFactory; @@ -128,10 +129,9 @@ protected AbstractIntegrationTest(String changelogDir, Database dbms) throws Exc String testHubApiKey = integrationTestProperties.getProperty("integration.test.hub.apiKey"); if (testHubApiKey != null) { - //TODO: -// hubConfiguration.setLiquibaseHubApiKey(testHubApiKey); -// String testHubUrl = integrationTestProperties.getProperty("integration.test.hub.url"); -// hubConfiguration.setLiquibaseHubUrl(testHubUrl); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), testHubApiKey); + String testHubUrl = integrationTestProperties.getProperty("integration.test.hub.url"); + System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), testHubUrl); } Scope.setScopeManager(new TestScopeManager()); } From 1f586a45529fcb10e4f269ae7610f93d2668745a Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 16 Mar 2021 15:28:15 -0500 Subject: [PATCH 08/17] Moved SystemEnvironmentValueProvider DAT-6759 --- .../ConfigurationValueProvider.java | 4 +- .../core/SystemEnvironmentValueProvider.java | 68 ------------------- ...e.configuration.ConfigurationValueProvider | 1 - .../LiquibaseConfigurationTest.groovy | 5 +- .../SystemEnvironmentValueProviderTest.groovy | 59 ---------------- 5 files changed, 2 insertions(+), 135 deletions(-) delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java delete mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java index 4acb5df792c..57321eebcf8 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java @@ -1,7 +1,5 @@ package liquibase.configuration; -import liquibase.configuration.core.SystemEnvironmentValueProvider; - /** * Defines a way for {@link LiquibaseConfiguration} to find configured values. */ @@ -15,7 +13,7 @@ public interface ConfigurationValueProvider { /** * Lookup the given key in this source. * It is up to the implementation to provide any "smoothing" or translation of key names. - * For example, {@link SystemEnvironmentValueProvider} will look check environment variables containing _'s rather than .'s. + * For example, a SystemEnvironmentValueProvider will look check environment variables containing _'s rather than .'s. * * @return null if the key is not defined in this provider. */ diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java deleted file mode 100644 index da81ab6ef8a..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemEnvironmentValueProvider.java +++ /dev/null @@ -1,68 +0,0 @@ -package liquibase.configuration.core; - -import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.CurrentValueDetails; -import liquibase.configuration.CurrentValueSourceDetails; - -import java.util.HashSet; -import java.util.Set; - -/** - * Searches for the configuration values in the system environment variables. - * - * To handle shells that only allow underscores, it checks the following variations of a proprty: - * <ul> - * <li>foo.bar - the original name</li> - * <li>foo_bar - with underscores for periods (if any)</li> - * <li>FOO.BAR - original, with upper case</li> - * <li>FOO_BAR - with underscores and upper case</li> - * </ul> - * Any hyphen variant of the above would work as well, or even mix dot/hyphen variants. - */ -public class SystemEnvironmentValueProvider implements ConfigurationValueProvider { - - @Override - public int getPrecedence() { - return 10; - } - - @Override - public CurrentValueSourceDetails getValue(String key) { - if (key == null) { - return null; - } - - Set<String> checked = new HashSet<>(); - - for (String name : new String[]{key, key.toUpperCase(), key.toLowerCase()}) { - for (String variation : new String[] { - name, - - // Check name with just dots replaced - name.replace('.', '_'), - - // Check name with just hyphens replaced - name.replace('-', '_'), - - // Check name with dots and hyphens replaced - name.replace('.', '_').replace('-', '_') - }) { - if (checked.add(variation)) { - final String foundValue = getEnvironmentVariable(variation); - if (foundValue != null) { - return new CurrentValueSourceDetails(foundValue, "Environment variable", variation); - } - - } - - } - } - - return null; - } - - protected String getEnvironmentVariable(String name) { - return System.getenv(name); - } - -} diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider index 239543b42e0..5d078dc0980 100644 --- a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider +++ b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider @@ -1,3 +1,2 @@ -liquibase.configuration.core.SystemEnvironmentValueProvider liquibase.configuration.core.SystemPropertyValueProvider liquibase.configuration.core.ScopeValueProvider diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy index 64057d7c8b5..0944603e6e5 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy @@ -23,10 +23,7 @@ class LiquibaseConfigurationTest extends Specification { def "autoRegisters and sorts providers"() { expect: - Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).configurationValueProviders*.getClass()*.getName() == ["liquibase.configuration.core.SystemEnvironmentValueProvider", - "liquibase.configuration.core.SystemPropertyValueProvider", - "liquibase.configuration.core.ScopeValueProvider" - ] + Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).configurationValueProviders*.getClass()*.getName().contains("liquibase.configuration.core.SystemPropertyValueProvider") } def "autoRegisters definitions"() { diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy deleted file mode 100644 index d9af2b9ba33..00000000000 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemEnvironmentValueProviderTest.groovy +++ /dev/null @@ -1,59 +0,0 @@ -package liquibase.configuration.core - - -import spock.lang.Specification -import spock.lang.Unroll - -class SystemEnvironmentValueProviderTest extends Specification { - - @Unroll - def "GetValue"() { - when: - def env = [ - "lower" : "saw lower", - "lower_underscore": "saw lower underscore", - "lower.dot" : "saw lower dot", - "lower_under.dot" : "saw lower word dot", - "UPPER" : "saw upper", - "UPPER_UNDERSCORE": "saw upper underscore", - "UPPER.DOT" : "saw upper dot", - "UPPER_UNDER_DOT" : "saw under dot", - ] - def provider = new SystemEnvironmentValueProvider() { - @Override - protected String getEnvironmentVariable(String name) { - return env[name] - } - } - - def value = provider.getValue(key) - - then: - if (value == null) { - assert expectedValue == null - } else { - assert value.value == expectedValue - assert value.describe() == expectedDescription - } - - where: - key | expectedValue | expectedDescription - "lower" | "saw lower" | "Environment variable 'lower'" - "LOWER" | "saw lower" | "Environment variable 'lower'" - "upper" | "saw upper" | "Environment variable 'UPPER'" - "UPPER" | "saw upper" | "Environment variable 'UPPER'" - "lower_underscore" | "saw lower underscore" | "Environment variable 'lower_underscore'" - "lower.underscore" | "saw lower underscore" | "Environment variable 'lower_underscore'" - "lower_UNDERSCORE" | "saw lower underscore" | "Environment variable 'lower_underscore'" - "upper_underscore" | "saw upper underscore" | "Environment variable 'UPPER_UNDERSCORE'" - "UPPER_UNDERSCORE" | "saw upper underscore" | "Environment variable 'UPPER_UNDERSCORE'" - "upper_dot" | null | null - "upper.dot" | "saw upper dot" | "Environment variable 'UPPER.DOT'" - "UPPER.DOT" | "saw upper dot" | "Environment variable 'UPPER.DOT'" - "lower_under.dot" | "saw lower word dot" | "Environment variable 'lower_under.dot'" - "LOWER.UNDER.dot" | null | "Environment variable 'lower_under.dot'" - "LOWER_UNDER_DOT" | null | "Environment variable 'lower_under.dot'" - "invalid" | null | null - null | null | null - } -} From 1c2873aebce5b1cd6cff630f869c096610ce7497 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 16 Mar 2021 15:45:36 -0500 Subject: [PATCH 09/17] Merged from master --- .github/ISSUE_TEMPLATE/bug_report.md | 44 +- .github/ISSUE_TEMPLATE/config.yml | 8 + .../pull_request_template.md | 29 -- .github/pull_request_template.md | 64 +++ .travis.yml | 15 +- README.md | 2 +- base.pom.xml | 84 ++- liquibase-cdi/pom.xml | 82 +-- .../src/main/java/liquibase/Liquibase.java | 128 +++-- .../liquibase/change/core/LoadDataChange.java | 13 +- .../command/core/DropAllCommand.java | 2 +- .../database/AbstractJdbcDatabase.java | 5 +- .../java/liquibase/hub/HubConfiguration.java | 10 +- .../main/java/liquibase/hub/HubUpdater.java | 6 +- .../hub/listener/HubChangeExecListener.java | 7 +- .../integration/ant/ChangeLogSyncTask.java | 16 +- .../ant/ChangeLogSyncToTagTask.java | 47 ++ .../integration/commandline/Main.java | 35 +- .../spring/SpringResourceAccessor.java | 18 +- .../logging/core/BufferedLogService.java | 8 +- .../core/xml/LiquibaseEntityResolver.java | 4 +- .../resource/ClassLoaderResourceAccessor.java | 83 ++- .../snapshot/JdbcDatabaseSnapshot.java | 11 + .../i18n/liquibase-commandline-helptext.xml | 52 +- .../main/resources/liquibasetasks.properties | 3 +- .../groovy/liquibase/LiquibaseTest.groovy | 249 ++++++++- .../change/core/LoadDataChangeTest.groovy | 130 +++++ .../test/LiquibaseTagExistsCondition.groovy | 49 ++ .../spring/SpringResourceAccessorTest.groovy | 19 + .../core/BufferedLogServiceTest.groovy | 34 ++ .../integration/ant/ChangeLogSyncTaskTest.xml | 96 ++++ .../ant/changelog/simple-changelog.xml | 16 + .../liquibase/integration/ant/test/antlib.xml | 29 ++ .../resources/liquibase/tagged-changelog.xml | 31 ++ liquibase-dist/pom.xml | 111 ++-- .../examples/xml/liquibase.sqlplus.conf | 5 +- .../archive/lib/liquibase_autocomplete.sh | 16 +- .../src/main/install4j/liquibase.install4j | 4 +- .../docker/docker-compose.yml | 0 .../docker}/mysql-init.sql | 0 .../docker}/postgres-init.sh | 0 .../pgsql/complete/root.changelog.xml | 62 ++- ...uibase.integrationtest.circleci.properties | 2 - liquibase-maven-plugin/pom.xml | 482 +++++++++--------- .../plugins/LiquibaseChangeLogSyncMojo.java | 12 +- .../LiquibaseChangeLogSyncSQLMojo.java | 9 +- .../LiquibaseChangeLogSyncToTagMojo.java | 38 ++ .../LiquibaseChangeLogSyncToTagSQLMojo.java | 116 +++++ .../LiquibaseChangelogSyncToTagMojoTest.java | 68 +++ pom.xml | 5 + 50 files changed, 1807 insertions(+), 552 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md create mode 100644 .github/pull_request_template.md create mode 100644 liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncToTagTask.java create mode 100644 liquibase-core/src/test/groovy/liquibase/integration/ant/test/LiquibaseTagExistsCondition.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/logging/core/BufferedLogServiceTest.groovy create mode 100644 liquibase-core/src/test/resources/liquibase/tagged-changelog.xml rename .travis/databases.docker-compose.yml => liquibase-integration-tests/docker/docker-compose.yml (100%) rename {.travis => liquibase-integration-tests/docker}/mysql-init.sql (100%) rename {.travis => liquibase-integration-tests/docker}/postgres-init.sh (100%) mode change 100755 => 100644 delete mode 100644 liquibase-integration-tests/src/test/resources/liquibase/liquibase.integrationtest.circleci.properties create mode 100644 liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagMojo.java create mode 100644 liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagSQLMojo.java create mode 100644 liquibase-maven-plugin/src/test/java/org/liquibase/maven/plugins/LiquibaseChangelogSyncToTagMojoTest.java diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f6e9e6fa30f..f8463c8ff65 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,23 +7,45 @@ assignees: '' --- -**Description** -A clear and concise description of what the bug is. +<!--- This environment context section helps us quickly review your PR. + Please take a minute to fill-out this information. --> +## Environment -**To Reproduce** -Steps to reproduce the behavior. Please be as precise as possible. Ideally, include things like the files used if possible, the commands used, how the product was installed and how it is used, what database platform and version is being used, properties files/POM files/config files, extensions used... +**Liquibase Version**: -Ensure private information is redacted. +**Liquibase Integration & Version**: <Pick one: CLI, maven, gradle, spring boot, servlet, etc.> -Please specify the exact commands used, from CLI, from maven, etc. +**Liquibase Extension(s) & Version**: -Describe the actual problematic behavior. Include console outout if relevant, log files if available. Ensure private information is redacted. +**Database Vendor & Version**: -**Expected behavior** -A clear and concise description of what you expected to happen. +**Operating System Type & Version**: -**Screenshots** + +## Description + +A clear and concise description of the issue being addressed. +- Describe the actual problematic behavior. +- Ensure private information is redacted. + +## Steps To Reproduce + +List the steps to reproduce the behavior. +- Please be precise and ensure private information is redacted +- Include things like + - Files used - sql scripts, changelog file(s), property file(s), config files, POM Files + - Exact commands used - CLI, maven, gradle, spring boot, servlet, etc. + +## Actual Behavior +A clear and concise description of what happens in the software **before** this pull request. +- Include console output if relevant +- Include log files if available. + +## Expected/Desired Behavior +A clear and concise description of what happens in the software **after** this pull request. + +## Screenshots (if appropriate) If applicable, add screenshots to help explain your problem. -**Additional context** +## Additional Context Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..4fb6a0f5c44 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Liquibase Forums + url: https://forum.liquibase.org/ + about: Please use the forums to ask open-ended questions and connect with other Liquibase Users and Developers. + - name: StackOverflow + url: https://stackoverflow.com/questions/tagged/liquibase + about: For specific questions about Liquibase that will have specific answers, please use StackOverflow and tag the question `liquibase`. diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 81a7298babd..00000000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Pull Request -about: Create a report to help us improve -title: '' -labels: Status:Discovery -assignees: '' - ---- - -**Description** -A clear and concise description of what the issue being addressed is. - -**To Reproduce** -Steps to reproduce the behavior. Please be as precise as possible. Ideally, include things like the files used if possible, the commands used, how the product was installed and how it is used, what database platform and version is being used, properties files/POM files/config files, extensions used... - -Ensure private information is redacted. - -Please specify the exact commands used, from CLI, from maven, etc. - -Describe the actual problematic behavior. Include console outout if relevant, log files if available. Ensure private information is redacted. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..4b3657ddc89 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,64 @@ +<!--- This environment context section helps us quickly review your PR. + Please take a minute to fill-out this information. --> +## Environment + +**Liquibase Version**: + +**Liquibase Integration & Version**: <Pick one: CLI, maven, gradle, spring boot, servlet, etc.> + +**Liquibase Extension(s) & Version**: + +**Database Vendor & Version**: + +**Operating System Type & Version**: + +## Pull Request Type + +<!--- What types of changes does your code introduce? + Put an `x` in all the boxes that apply: + If this PR fixes an existing GH issue, edit the next line to add "closes #XXXX" to auto-link. + If this PR fixes an existing CORE Jira issue, note that as well, although there will be no auto-linking. --> +- [ ] Bug fix (non-breaking change which fixes an issue.) +- [ ] Enhancement/New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Description + +A clear and concise description of the issue being addressed. Additional guidance [here](https://liquibase.jira.com/wiki/spaces/LB/pages/1274904896/How+to+Contribute+Code+to+Liquibase+Core). +- Describe the actual problematic behavior. +- Ensure private information is redacted. + +## Steps To Reproduce + +List the steps to reproduce the behavior. +- Please be precise and ensure private information is redacted +- Include things like + - Files used - sql scripts, changelog file(s), property file(s), config files, POM Files + - Exact commands used - CLI, maven, gradle, spring boot, servlet, etc. + +## Actual Behavior +A clear and concise description of what happens in the software **before** this pull request. +- Include console output if relevant +- Include log files if available. + +## Expected/Desired Behavior +A clear and concise description of what happens in the software **after** this pull request. + +## Screenshots (if appropriate) +If applicable, add screenshots to help explain your problem. + +## Additional Context +Add any other context about the problem here. + +## Fast Track PR Acceptance Checklist: +<!--- Completing these speeds up the acceptance of your pull request --> +<!--- Put an `x` in all the boxes that apply. --> +<!--- If you're unsure about any of these, just ask us in a comment. We're here to help! --> +- [ ] Build is successful and all new and existing tests pass +- [ ] Added [Unit Test(s)](https://liquibase.jira.com/wiki/spaces/LB/pages/1274937609/How+to+Write+Liquibase+Core+Unit+Tests) +- [ ] Added [Integration Test(s)](https://liquibase.jira.com/wiki/spaces/LB/pages/1276608569/How+to+Write+Liquibase+Core+Integration+Tests) +- [ ] Added [Test Harness Test(s)](https://github.com/liquibase/liquibase-test-harness/pulls) +- [ ] Documentation Updated + +## Need Help? +Come chat with us on our [discord channel](https://discord.com/channels/700506481111597066/700506481572839505) diff --git a/.travis.yml b/.travis.yml index c4cb7e2ab52..4c1b00b9b07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: java -jdk: openjdk8 +jdk: openjdk11 env: global: #SONATYPE_USERNAME @@ -10,19 +10,16 @@ env: services: - docker -# before_install: -# - docker pull mysql:5 - install: cp ./.travis/maven.settings.xml $HOME/.m2/settings.xml -before_script: docker-compose -f ./.travis/databases.docker-compose.yml up -d +before_script: docker-compose -f ./liquibase-integration-tests/docker/docker-compose.yml up -d script: - - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent integration-test verify -Dliquibase.version.qualifier="-${TRAVIS_BRANCH}" -Dbuild.number=${TRAVIS_BUILD_NUMBER} -Dbuild.commit=${TRAVIS_COMMIT} -after_script: - - docker-compose -f ./.travis/databases.docker-compose.yml down + - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then bash -c "mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent integration-test verify -Dliquibase.version.qualifier="-${TRAVIS_BRANCH}" -Dbuild.number=${TRAVIS_BUILD_NUMBER} -Dbuild.commit=${TRAVIS_COMMIT}"; fi' + - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash -c "mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent integration-test deploy sonar:sonar -Dsonar.projectKey=liquibase_liquibase -Ddeploy.url=https://oss.sonatype.org/content/repositories/snapshots -Ddeploy.repositoryId=sonatype -Dliquibase.version.qualifier="-${TRAVIS_BRANCH}" -Dbuild.number=${TRAVIS_BUILD_NUMBER} -Dbuild.commit=${TRAVIS_COMMIT}"; fi' +after_script: docker-compose -f ./liquibase-integration-tests/docker/docker-compose.yml down cache: directories: - - "~/.m2" + - "~/.m2" addons: sonarcloud: organization: "liquibase-oss" diff --git a/README.md b/README.md index 3fd5edd90c1..5c349c7cb48 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ see [the main project website](https://www.liquibase.org/). ## Quickstart -[Get started in 5 minutes](https://www.liquibase.org/get_started/index.html). +[Get started in 5 minutes](https://www.liquibase.org/get-started/first-steps). ## Changelog diff --git a/base.pom.xml b/base.pom.xml index 38035dcd7d5..5f9ef71d786 100644 --- a/base.pom.xml +++ b/base.pom.xml @@ -50,10 +50,11 @@ </scm> <properties> - <liquibase.base.version>4.3.1</liquibase.base.version> + <liquibase.base.version>4.3.2</liquibase.base.version> <liquibase.version.qualifier>-local</liquibase.version.qualifier> <liquibase.version.snapshot>-SNAPSHOT</liquibase.version.snapshot> - <liquibase.version>${liquibase.base.version}${liquibase.version.qualifier}${liquibase.version.snapshot}</liquibase.version> + <liquibase.version>${liquibase.base.version}${liquibase.version.qualifier}${liquibase.version.snapshot} + </liquibase.version> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.enforcer.requireMavenVersion>3.6</maven.enforcer.requireMavenVersion> @@ -66,6 +67,11 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring.version>5.0.12.RELEASE</spring.version> + <sonar.projectKey>org.liquibase:liquibase-parent</sonar.projectKey> + <sonar.organization>liquibase-core</sonar.organization> + <sonar.host.url>https://sonarcloud.io</sonar.host.url> + <sonar.moduleKey>${artifactId}</sonar.moduleKey> + <gpg.passphrase>${ENV.GPG_PASSPHRASE}</gpg.passphrase> </properties> @@ -159,7 +165,7 @@ <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> <scope>test</scope> - </dependency> + </dependency> <dependency> <groupId>com.microsoft.sqlserver</groupId> @@ -169,11 +175,11 @@ </dependency> <dependency> - <groupId>org.postgresql</groupId> + <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.12</version> - <scope>test</scope> - </dependency> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -185,19 +191,6 @@ <encoding>UTF-8</encoding> </configuration> </plugin> - <plugin> - <artifactId>maven-gpg-plugin</artifactId> - <version>1.6</version> - <configuration> - <passphrase>${env.GPG_PASSPHRASE}</passphrase> - <gpgArguments> - <arg>--batch</arg> - <!-- This is necessary for gpg to not try to use the pinentry programs --> - <arg>--pinentry-mode</arg> - <arg>loopback</arg> - </gpgArguments> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> @@ -269,6 +262,13 @@ <goal>prepare-agent</goal> </goals> </execution> + <execution> + <id>report</id> + <phase>test</phase> + <goals> + <goal>report</goal> + </goals> + </execution> </executions> </plugin> @@ -301,7 +301,6 @@ <plugin> <artifactId>maven-deploy-plugin</artifactId> - <version>2.8.2</version> <configuration> <skip>true</skip> </configuration> @@ -319,12 +318,12 @@ include_relative instruction to include the generated pages in our markdown pages. --> <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-site-plugin</artifactId> - <version>3.8.2</version> - <configuration> - <templateFile>${maven.multiModuleProjectDirectory}/maven-site.vm</templateFile> - </configuration> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-site-plugin</artifactId> + <version>3.8.2</version> + <configuration> + <templateFile>${maven.multiModuleProjectDirectory}/maven-site.vm</templateFile> + </configuration> </plugin> <plugin> @@ -350,6 +349,11 @@ <version>2.5.2</version> </plugin> + <plugin> + <artifactId>maven-deploy-plugin</artifactId> + <version>2.8.2</version> + </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> @@ -370,4 +374,32 @@ </plugins> </pluginManagement> </build> + + <profiles> + <profile> + <id>gpg-sign</id> + <activation> + <property> + <name>env.GPG_PASSPHRASE</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <configuration> + <passphrase>${env.GPG_PASSPHRASE}</passphrase> + <gpgArguments> + <arg>--batch</arg> + <!-- This is necessary for gpg to not try to use the pinentry programs --> + <arg>--pinentry-mode</arg> + <arg>loopback</arg> + </gpgArguments> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> diff --git a/liquibase-cdi/pom.xml b/liquibase-cdi/pom.xml index a0d23445f31..66d6000383e 100644 --- a/liquibase-cdi/pom.xml +++ b/liquibase-cdi/pom.xml @@ -134,41 +134,55 @@ </execution> </executions> </plugin> - - <plugin> - <artifactId>maven-gpg-plugin</artifactId> - <version>1.6</version> - <configuration> - <passphrase>${env.GPG_PASSPHRASE}</passphrase> - <gpgArguments> - <!-- This is necessary for gpg to not try to use the pinentry programs --> - <arg>--batch</arg> - <arg>--no-tty</arg> - <arg>--pinentry-mode</arg> - <arg>loopback</arg> - </gpgArguments> - - <skip>false</skip> - <repositoryId>${deploy.repositoryId}</repositoryId> - <artifactId>${project.artifactId}</artifactId> - <version>${liquibase.version}</version> - <url>${deploy.url}</url> - <file>${project.build.directory}/${project.artifactId}-${liquibase.version}.jar</file> - <sources>${project.build.directory}/${project.artifactId}-${version}-sources.jar</sources> - <javadoc>${project.build.directory}/${project.artifactId}-${version}-javadoc.jar</javadoc> - <pomFile>${project.build.directory}/release.pom.xml</pomFile> - </configuration> - <executions> - <execution> - <id>custom-deploy</id> - <phase>deploy</phase> - <goals> - <goal>sign-and-deploy-file</goal> - </goals> - </execution> - </executions> - </plugin> </plugins> </build> + + <profiles> + <profile> + <id>gpg-sign</id> + <activation> + <property> + <name>env.GPG_PASSPHRASE</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <configuration> + <passphrase>${env.GPG_PASSPHRASE}</passphrase> + <gpgArguments> + <!-- This is necessary for gpg to not try to use the pinentry programs --> + <arg>--batch</arg> + <arg>--no-tty</arg> + <arg>--pinentry-mode</arg> + <arg>loopback</arg> + </gpgArguments> + + <skip>false</skip> + <repositoryId>${deploy.repositoryId}</repositoryId> + <artifactId>${project.artifactId}</artifactId> + <version>${liquibase.version}</version> + <url>${deploy.url}</url> + <file>${project.build.directory}/${project.artifactId}-${liquibase.version}.jar</file> + <sources>${project.build.directory}/${project.artifactId}-${version}-sources.jar</sources> + <javadoc>${project.build.directory}/${project.artifactId}-${version}-javadoc.jar</javadoc> + <pomFile>${project.build.directory}/release.pom.xml</pomFile> + </configuration> + <executions> + <execution> + <id>custom-deploy</id> + <phase>deploy</phase> + <goals> + <goal>sign-and-deploy-file</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> diff --git a/liquibase-core/src/main/java/liquibase/Liquibase.java b/liquibase-core/src/main/java/liquibase/Liquibase.java index 3325491cff6..a5898b6991f 100644 --- a/liquibase-core/src/main/java/liquibase/Liquibase.java +++ b/liquibase-core/src/main/java/liquibase/Liquibase.java @@ -57,6 +57,7 @@ import java.io.*; import java.text.DateFormat; import java.util.*; +import java.util.function.Supplier; import static java.util.ResourceBundle.getBundle; @@ -248,7 +249,7 @@ public void update(Contexts contexts, LabelExpression labelExpression, boolean c Connection connection = getConnection(changeLog); if (connection != null) { updateOperation = - hubUpdater.preUpdateHub("UPDATE", database, connection, changeLogFile, contexts, labelExpression, changeLogIterator); + hubUpdater.preUpdateHub("UPDATE", connection, changeLogFile, contexts, labelExpression, changeLogIterator); } // @@ -383,6 +384,28 @@ protected ChangeLogIterator getStandardChangelogIterator(Contexts contexts, Labe new IgnoreChangeSetFilter()); } + protected ChangeLogIterator buildChangeLogIterator(String tag, DatabaseChangeLog changeLog, Contexts contexts, + LabelExpression labelExpression) throws DatabaseException { + + if (tag == null) { + return new ChangeLogIterator(changeLog, + new NotRanChangeSetFilter(database.getRanChangeSetList()), + new ContextChangeSetFilter(contexts), + new LabelChangeSetFilter(labelExpression), + new IgnoreChangeSetFilter(), + new DbmsChangeSetFilter(database)); + } else { + List<RanChangeSet> ranChangeSetList = database.getRanChangeSetList(); + return new ChangeLogIterator(changeLog, + new NotRanChangeSetFilter(database.getRanChangeSetList()), + new ContextChangeSetFilter(contexts), + new LabelChangeSetFilter(labelExpression), + new IgnoreChangeSetFilter(), + new DbmsChangeSetFilter(database), + new UpToTagChangeSetFilter(tag, ranChangeSetList)); + } + } + public void update(String contexts, Writer output) throws LiquibaseException { this.update(new Contexts(contexts), output); } @@ -485,7 +508,7 @@ public void run() throws Exception { Connection connection = getConnection(changeLog); if (connection != null) { updateOperation = - hubUpdater.preUpdateHub("UPDATE", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + hubUpdater.preUpdateHub("UPDATE", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -603,7 +626,7 @@ public void run() throws Exception { Connection connection = getConnection(changeLog); if (connection != null) { updateOperation = - hubUpdater.preUpdateHub("UPDATE", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + hubUpdater.preUpdateHub("UPDATE", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -847,7 +870,7 @@ public void run() throws Exception { // Connection connection = getConnection(changeLog); if (connection != null) { - rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -1112,7 +1135,7 @@ public void run() throws Exception { // Connection connection = getConnection(changeLog); if (connection != null) { - rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -1270,7 +1293,7 @@ public void run() throws Exception { // Connection connection = getConnection(changeLog); if (connection != null) { - rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + rollbackOperation = hubUpdater.preUpdateHub("ROLLBACK", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -1332,32 +1355,10 @@ public void changeLogSync(String contexts, Writer output) throws LiquibaseExcept } public void changeLogSync(Contexts contexts, LabelExpression labelExpression, Writer output) - throws LiquibaseException { - changeLogParameters.setContexts(contexts); - changeLogParameters.setLabels(labelExpression); - - runInScope(new Scope.ScopedRunner() { - @Override - public void run() throws Exception { - - LoggingExecutor outputTemplate = new LoggingExecutor( - Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor(database), output, database - ); + throws LiquibaseException { - /* We have no other choice than to save the current Executer here. */ - @SuppressWarnings("squid:S1941") - Executor oldTemplate = getAndReplaceJdbcExecutor(output); - - outputHeader("SQL to add all changesets to database history table"); - - changeLogSync(contexts, labelExpression); - - flushOutputWriter(output); - - Scope.getCurrentScope().getSingleton(ExecutorService.class).setExecutor("jdbc", database, oldTemplate); - resetServices(); - } - }); + doChangeLogSyncSql(null, contexts, labelExpression, output, + () -> "SQL to add all changesets to database history table"); } private void flushOutputWriter(Writer output) throws LiquibaseException { @@ -1385,6 +1386,14 @@ public void changeLogSync(Contexts contexts) throws LiquibaseException { } public void changeLogSync(Contexts contexts, LabelExpression labelExpression) throws LiquibaseException { + changeLogSync(null, contexts, labelExpression); + } + + public void changeLogSync(String tag, String contexts) throws LiquibaseException { + changeLogSync(tag, new Contexts(contexts), new LabelExpression()); + } + + public void changeLogSync(String tag, Contexts contexts, LabelExpression labelExpression) throws LiquibaseException { changeLogParameters.setContexts(contexts); changeLogParameters.setLabels(labelExpression); @@ -1417,12 +1426,7 @@ public void run() throws Exception { // Create an iterator which will be used with a ListVisitor // to grab the list of change sets for the update // - ChangeLogIterator listLogIterator = new ChangeLogIterator(changeLog, - new NotRanChangeSetFilter(database.getRanChangeSetList()), - new ContextChangeSetFilter(contexts), - new LabelChangeSetFilter(labelExpression), - new IgnoreChangeSetFilter(), - new DbmsChangeSetFilter(database)); + ChangeLogIterator listLogIterator = buildChangeLogIterator(tag, changeLog, contexts, labelExpression); // // Create or retrieve the Connection @@ -1431,7 +1435,7 @@ public void run() throws Exception { Connection connection = getConnection(changeLog); if (connection != null) { changeLogSyncOperation = - hubUpdater.preUpdateHub("CHANGELOGSYNC", database, connection, changeLogFile, contexts, labelExpression, listLogIterator); + hubUpdater.preUpdateHub("CHANGELOGSYNC", connection, changeLogFile, contexts, labelExpression, listLogIterator); } // @@ -1441,16 +1445,9 @@ public void run() throws Exception { changeLogSyncListener = new HubChangeExecListener(changeLogSyncOperation, changeExecListener); } - ChangeLogIterator runChangeLogSyncIterator = new ChangeLogIterator(changeLog, - new NotRanChangeSetFilter(database.getRanChangeSetList()), - new ContextChangeSetFilter(contexts), - new LabelChangeSetFilter(labelExpression), - new IgnoreChangeSetFilter(), - new DbmsChangeSetFilter(database)); - CompositeLogService compositeLogService = new CompositeLogService(true, bufferLog); Scope.child(Scope.Attr.logService.name(), compositeLogService, () -> { - runChangeLogSyncIterator.run(new ChangeLogSyncVisitor(database, changeLogSyncListener), + listLogIterator.run(new ChangeLogSyncVisitor(database, changeLogSyncListener), new RuntimeEnvironment(database, contexts, labelExpression)); }); hubUpdater.postUpdateHub(changeLogSyncOperation, bufferLog); @@ -1474,6 +1471,45 @@ public void run() throws Exception { } + public void changeLogSync(String tag, String contexts, Writer output) throws LiquibaseException { + changeLogSync(tag, new Contexts(contexts), new LabelExpression(), output); + } + + public void changeLogSync(String tag, Contexts contexts, LabelExpression labelExpression, Writer output) + throws LiquibaseException { + + doChangeLogSyncSql(tag, contexts, labelExpression, output, + () -> "SQL to add changesets upto '" + tag + "' to database history table"); + } + + private void doChangeLogSyncSql(String tag, Contexts contexts, LabelExpression labelExpression, Writer output, + Supplier<String> header) throws LiquibaseException { + + changeLogParameters.setContexts(contexts); + changeLogParameters.setLabels(labelExpression); + + runInScope(() -> { + + LoggingExecutor outputTemplate = new LoggingExecutor( + Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor(database), output, database + ); + + /* We have no other choice than to save the current Executer here. */ + @SuppressWarnings("squid:S1941") + Executor oldTemplate = getAndReplaceJdbcExecutor(output); + + outputHeader("SQL to add all changesets to database history table"); + + changeLogSync(tag, contexts, labelExpression); + + flushOutputWriter(output); + + Scope.getCurrentScope().getSingleton(ExecutorService.class).setExecutor("jdbc", database, oldTemplate); + resetServices(); + }); + + } + public void markNextChangeSetRan(String contexts, Writer output) throws LiquibaseException { markNextChangeSetRan(new Contexts(contexts), new LabelExpression(), output); } diff --git a/liquibase-core/src/main/java/liquibase/change/core/LoadDataChange.java b/liquibase-core/src/main/java/liquibase/change/core/LoadDataChange.java index fd06f0fb0b9..4033e55d600 100644 --- a/liquibase-core/src/main/java/liquibase/change/core/LoadDataChange.java +++ b/liquibase-core/src/main/java/liquibase/change/core/LoadDataChange.java @@ -322,9 +322,9 @@ public SqlStatement[] generateStatements(Database database) { ); } - boolean needsPreparedStatement = false; - if (usePreparedStatements != null && usePreparedStatements) { - needsPreparedStatement = true; + boolean needsPreparedStatement = true; + if (usePreparedStatements != null && !usePreparedStatements) { + needsPreparedStatement = false; } List<LoadDataColumnConfig> columnsFromCsv = new ArrayList<>(); @@ -475,12 +475,13 @@ public SqlStatement[] generateStatements(Database database) { } // end of: iterate through all the columns of a CSV line - // Try to use prepared statements if any of the two following conditions apply: - // 1. There is no other option than using a prepared statement (e.g. in cases of LOBs) + // Try to use prepared statements if any of the following conditions apply: + // 1. There is no other option than using a prepared statement (e.g. in cases of LOBs) regardless + // of whether the 'usePreparedStatement' is set to false // 2. The database supports batched statements (for improved performance) AND we are not in an // "SQL" mode (i.e. we generate an SQL file instead of actually modifying the database). if - ((needsPreparedStatement || (databaseSupportsBatchUpdates && ! isLoggingExecutor(database))) && + ((needsPreparedStatement && (databaseSupportsBatchUpdates && ! isLoggingExecutor(database))) && hasPreparedStatementsImplemented()) { anyPreparedStatements = true; ExecutablePreparedStatementBase stmt = diff --git a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java index 240bf7ddae3..2d2b7538525 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DropAllCommand.java @@ -125,7 +125,7 @@ public CommandResult run() throws Exception { database.dropDatabaseObjects(schema); } if (hubUpdater != null && (doSyncHub || hubConnectionId != null)) { - hubUpdater.syncHub(changeLogFile, database, changeLog, hubConnectionId); + hubUpdater.syncHub(changeLogFile, changeLog, hubConnectionId); } } catch (DatabaseException e) { throw e; diff --git a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java index aa8b97122e5..5005eaebf43 100644 --- a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java +++ b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java @@ -753,8 +753,11 @@ public void dropDatabaseObjects(final CatalogAndSchema schemaToDrop) throws Liqu typesToInclude.remove(PrimaryKey.class); typesToInclude.remove(UniqueConstraint.class); - if (supportsForeignKeyDisable()) { + if (supportsForeignKeyDisable() || getShortName().equals("postgresql")) { //We do not remove ForeignKey because they will be disabled and removed as parts of tables. + // Postgress is treated as if we can disable foreign keys because we can't drop + // the foreign keys of a partitioned table, as discovered in + // https://github.com/liquibase/liquibase/issues/1212 typesToInclude.remove(ForeignKey.class); } diff --git a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java index bad278c2733..09eb0eb3785 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java @@ -17,7 +17,7 @@ public class HubConfiguration implements ConfigurationDefinitionHolder { public static final ConfigurationDefinition<String> LIQUIBASE_HUB_API_KEY; public static final ConfigurationDefinition<String> LIQUIBASE_HUB_URL; public static final ConfigurationDefinition<String> LIQUIBASE_HUB_MODE; - public static final ConfigurationDefinition<String> LIQUIBASE_HUB_LOGLEVEL; + public static final ConfigurationDefinition<Level> LIQUIBASE_HUB_LOGLEVEL; static { ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase.hub"); @@ -48,9 +48,9 @@ public class HubConfiguration implements ConfigurationDefinitionHolder { .setDefaultValue("all") .build(); - LIQUIBASE_HUB_LOGLEVEL = builder.define("logLevel", String.class) + LIQUIBASE_HUB_LOGLEVEL = builder.define("logLevel", Level.class) .setDescription("Log level for filtering log messages to send to Liquibase Hub during operations. Values can be any acceptable log level.") - .setDefaultValue("INFO") + .setDefaultValue(Level.INFO) .setValueHandler(value -> { if (value == null) { return null; @@ -64,14 +64,14 @@ public class HubConfiguration implements ConfigurationDefinitionHolder { logLevel = Level.parse(((String) value).toUpperCase()); } catch (IllegalArgumentException e) { String message = "An invalid liquibase.hub.logLevel value of " + value + " detected. Acceptable values are " + StringUtil.join(validValues, ","); - Scope.getCurrentScope().getLog(liquibase.configuration.HubConfiguration.class).warning(message); + Scope.getCurrentScope().getLog(liquibase.hub.HubConfiguration.class).warning(message); } value = logLevel.toString(); } } - return value.toString(); + return Level.parse(value.toString()); }) .build(); } diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index 75d88fd2df8..09e02ea298d 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -167,8 +167,7 @@ public void postUpdateHub(Operation updateOperation, BufferedLogService bufferLo // Send the COMPLETE operation event // Capture the Liquibase Hub log level to use for filtering // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - Level currentLevel = Level.parse(hubConfiguration.getLiquibaseHubLogLevel()); + Level currentLevel = HubConfiguration.LIQUIBASE_HUB_LOGLEVEL.getCurrentValue(); final HubService hubService = Scope.getCurrentScope().getSingleton(HubServiceFactory.class).getService(); hubService.sendOperationEvent(updateOperation, new OperationEvent() @@ -227,8 +226,7 @@ public void postUpdateHubExceptionHandling(Operation updateOperation, // // Capture the current log level to use for filtering // - HubConfiguration hubConfiguration = LiquibaseConfiguration.getInstance().getConfiguration(HubConfiguration.class); - Level currentLevel = Level.parse(hubConfiguration.getLiquibaseHubLogLevel()); + Level currentLevel = HubConfiguration.LIQUIBASE_HUB_LOGLEVEL.getCurrentValue(); final HubService hubService = Scope.getCurrentScope().getSingleton(HubServiceFactory.class).getService(); hubService.sendOperationEvent(updateOperation, new OperationEvent() diff --git a/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java b/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java index 8f77085f23f..8fda0a2d9ae 100644 --- a/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java +++ b/liquibase-core/src/main/java/liquibase/hub/listener/HubChangeExecListener.java @@ -310,10 +310,15 @@ else if (changeSet.hasCustomRollbackChanges()) { } private String getCurrentLog() { + // + // Capture the current log level to use for filtering + // + Level currentLevel = HubConfiguration.LIQUIBASE_HUB_LOGLEVEL.getCurrentValue(); + BufferedLogService bufferedLogService = Scope.getCurrentScope().get(BufferedLogService.class.getName(), BufferedLogService.class); if (bufferedLogService != null) { - return bufferedLogService.getLogAsString(Level.INFO); + return bufferedLogService.getLogAsString(currentLevel); } return null; } diff --git a/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncTask.java b/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncTask.java index 8cf3eb0e04a..a5dd17de8ba 100644 --- a/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncTask.java +++ b/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncTask.java @@ -12,6 +12,8 @@ import java.io.UnsupportedEncodingException; public class ChangeLogSyncTask extends AbstractChangeLogBasedTask { + private String toTag; + @Override public void executeWithLiquibaseClassloader() throws BuildException { Liquibase liquibase = getLiquibase(); @@ -20,9 +22,9 @@ public void executeWithLiquibaseClassloader() throws BuildException { FileResource outputFile = getOutputFile(); if (outputFile != null) { writer = new OutputStreamWriter(outputFile.getOutputStream(), getOutputEncoding()); - liquibase.changeLogSync(new Contexts(getContexts()), getLabels(), writer); + liquibase.changeLogSync(toTag, new Contexts(getContexts()), getLabels(), writer); } else { - liquibase.changeLogSync(new Contexts(getContexts()), getLabels()); + liquibase.changeLogSync(toTag, new Contexts(getContexts()), getLabels()); } } catch (UnsupportedEncodingException e) { throw new BuildException("Unable to generate sync SQL. Encoding [" + getOutputEncoding() + "] is not supported.", e); @@ -34,4 +36,12 @@ public void executeWithLiquibaseClassloader() throws BuildException { FileUtils.close(writer); } } -} \ No newline at end of file + + public String getToTag() { + return toTag; + } + + public void setToTag(String toTag) { + this.toTag = toTag; + } +} diff --git a/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncToTagTask.java b/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncToTagTask.java new file mode 100644 index 00000000000..09aeb0dbf39 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/integration/ant/ChangeLogSyncToTagTask.java @@ -0,0 +1,47 @@ +package liquibase.integration.ant; + +import liquibase.Contexts; +import liquibase.Liquibase; +import liquibase.exception.LiquibaseException; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.resources.FileResource; +import org.apache.tools.ant.util.FileUtils; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; + +public class ChangeLogSyncToTagTask extends AbstractChangeLogBasedTask { + private String toTag; + + @Override + public void executeWithLiquibaseClassloader() throws BuildException { + Liquibase liquibase = getLiquibase(); + OutputStreamWriter writer = null; + try { + FileResource outputFile = getOutputFile(); + if (outputFile != null) { + writer = new OutputStreamWriter(outputFile.getOutputStream(), getOutputEncoding()); + liquibase.changeLogSync(toTag, new Contexts(getContexts()), getLabels(), writer); + } else { + liquibase.changeLogSync(toTag, new Contexts(getContexts()), getLabels()); + } + } catch (UnsupportedEncodingException e) { + throw new BuildException("Unable to generate sync SQL. Encoding [" + getOutputEncoding() + "] is not supported.", e); + } catch (IOException e) { + throw new BuildException("Unable to generate sync SQL. Error creating output writer.", e); + } catch (LiquibaseException e) { + throw new BuildException("Unable to sync change log: " + e.getMessage(), e); + } finally { + FileUtils.close(writer); + } + } + + public String getToTag() { + return toTag; + } + + public void setToTag(String toTag) { + this.toTag = toTag; + } +} \ No newline at end of file diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 39a5b86f740..c5871e372f1 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -432,6 +432,12 @@ protected static void setLogLevel(LogService logService, java.util.logging.Logge handler.setLevel(level); handler.setFilter(new SecureLogFilter(logService.getFilter())); } + // + // Set the Liquibase Hub log level if logging is not OFF + // + if (level != Level.OFF) { + System.setProperty(HubConfiguration.LIQUIBASE_HUB_LOGLEVEL.getKey(), level.toString()); + } } private static Level parseLogLevel(String logLevelName, ConsoleUIService ui) { @@ -522,6 +528,7 @@ private static boolean isStandardOutputRequired(String command) { return COMMANDS.SNAPSHOT.equalsIgnoreCase(command) || COMMANDS.SNAPSHOT_REFERENCE.equalsIgnoreCase(command) || COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(command) + || COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL.equalsIgnoreCase(command) || COMMANDS.MARK_NEXT_CHANGESET_RAN_SQL.equalsIgnoreCase(command) || COMMANDS.UPDATE_COUNT_SQL.equalsIgnoreCase(command) || COMMANDS.UPDATE_TO_TAG_SQL.equalsIgnoreCase(command) @@ -551,6 +558,8 @@ private static boolean isChangeLogRequired(String command) { || COMMANDS.VALIDATE.equalsIgnoreCase(command) || COMMANDS.CHANGELOG_SYNC.equalsIgnoreCase(command) || COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(command) + || COMMANDS.CHANGELOG_SYNC_TO_TAG.equalsIgnoreCase(command) + || COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL.equalsIgnoreCase(command) || COMMANDS.GENERATE_CHANGELOG.equalsIgnoreCase(command) || COMMANDS.UNEXPECTED_CHANGESETS.equalsIgnoreCase(command) || COMMANDS.DIFF_CHANGELOG.equalsIgnoreCase(command) @@ -606,6 +615,8 @@ private static boolean isCommand(String arg) { || COMMANDS.DB_DOC.equalsIgnoreCase(arg) || COMMANDS.CHANGELOG_SYNC.equalsIgnoreCase(arg) || COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(arg) + || COMMANDS.CHANGELOG_SYNC_TO_TAG.equalsIgnoreCase(arg) + || COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL.equalsIgnoreCase(arg) || COMMANDS.MARK_NEXT_CHANGESET_RAN.equalsIgnoreCase(arg) || COMMANDS.MARK_NEXT_CHANGESET_RAN_SQL.equalsIgnoreCase(arg) || COMMANDS.ROLLBACK_ONE_CHANGE_SET.equalsIgnoreCase(arg) @@ -816,7 +827,9 @@ private void checkForUnexpectedCommandParameter(List<String> messages) { || COMMANDS.CALCULATE_CHECKSUM.equalsIgnoreCase(command) || COMMANDS.DB_DOC.equalsIgnoreCase(command) || COMMANDS.TAG.equalsIgnoreCase(command) - || COMMANDS.TAG_EXISTS.equalsIgnoreCase(command)) { + || COMMANDS.TAG_EXISTS.equalsIgnoreCase(command) + || COMMANDS.CHANGELOG_SYNC_TO_TAG.equalsIgnoreCase(command) + || COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL.equalsIgnoreCase(command)) { if ((!commandParams.isEmpty()) && commandParams.iterator().next().startsWith("-")) { messages.add(coreBundle.getString(ERRORMSG_UNEXPECTED_PARAMETERS) + commandParams); @@ -1746,6 +1759,24 @@ protected void doMigration() throws Exception { liquibase.changeLogSync(new Contexts(contexts), new LabelExpression(labels)); } else if (COMMANDS.CHANGELOG_SYNC_SQL.equalsIgnoreCase(command)) { liquibase.changeLogSync(new Contexts(contexts), new LabelExpression(labels), getOutputWriter()); + } else if (COMMANDS.CHANGELOG_SYNC_TO_TAG.equalsIgnoreCase(command)) { + if ((commandParams == null) || commandParams.isEmpty()) { + throw new CommandLineParsingException( + String.format(coreBundle.getString("command.requires.tag"), + COMMANDS.CHANGELOG_SYNC_TO_TAG)); + } + + liquibase.changeLogSync(commandParams.iterator().next(), new Contexts(contexts), + new LabelExpression(labels)); + } else if (COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL.equalsIgnoreCase(command)) { + if ((commandParams == null) || commandParams.isEmpty()) { + throw new CommandLineParsingException( + String.format(coreBundle.getString("command.requires.tag"), + COMMANDS.CHANGELOG_SYNC_TO_TAG_SQL)); + } + + liquibase.changeLogSync(commandParams.iterator().next(), new Contexts(contexts), + new LabelExpression(labels), getOutputWriter()); } else if (COMMANDS.MARK_NEXT_CHANGESET_RAN.equalsIgnoreCase(command)) { liquibase.markNextChangeSetRan(new Contexts(contexts), new LabelExpression(labels)); } else if (COMMANDS.MARK_NEXT_CHANGESET_RAN_SQL.equalsIgnoreCase(command)) { @@ -2096,6 +2127,8 @@ private enum COMMANDS { private static final String CALCULATE_CHECKSUM = "calculateCheckSum"; private static final String CHANGELOG_SYNC = "changelogSync"; private static final String CHANGELOG_SYNC_SQL = "changelogSyncSQL"; + private static final String CHANGELOG_SYNC_TO_TAG = "changelogSyncToTag"; + private static final String CHANGELOG_SYNC_TO_TAG_SQL = "changelogSyncToTagSQL"; private static final String CLEAR_CHECKSUMS = "clearCheckSums"; private static final String DB_DOC = "dbDoc"; private static final String DIFF = "diff"; diff --git a/liquibase-core/src/main/java/liquibase/integration/spring/SpringResourceAccessor.java b/liquibase-core/src/main/java/liquibase/integration/spring/SpringResourceAccessor.java index 8d6189f2cf9..722635aee82 100644 --- a/liquibase-core/src/main/java/liquibase/integration/spring/SpringResourceAccessor.java +++ b/liquibase-core/src/main/java/liquibase/integration/spring/SpringResourceAccessor.java @@ -102,10 +102,10 @@ protected String getResourcePath(Resource resource) { if (url.contains("!")) { return url.replaceFirst(".*!", ""); } else { - while (!resourceLoader.getResource("classpath:"+url).exists()) { + while (!resourceLoader.getResource("classpath:" + url).exists()) { String newUrl = url.replaceFirst("^/?.*?/", ""); if (newUrl.equals(url)) { - throw new UnexpectedLiquibaseException("Could determine path for "+resource.getURL().toExternalForm()); + throw new UnexpectedLiquibaseException("Could determine path for " + resource.getURL().toExternalForm()); } url = newUrl; } @@ -115,7 +115,7 @@ protected String getResourcePath(Resource resource) { } catch (IOException e) { //the path gets stored in the databasechangelog table, so if it gets returned incorrectly it will cause future problems. //so throw a breaking error now rather than wait for bigger problems down the line - throw new UnexpectedLiquibaseException("Cannot determine resource path for "+resource.getDescription()); + throw new UnexpectedLiquibaseException("Cannot determine resource path for " + resource.getDescription()); } } @@ -163,12 +163,12 @@ protected boolean resourceIsFile(Resource resource) throws IOException { * Default implementation adds "classpath:" and removes duplicated /'s and classpath:'s */ protected String finalizeSearchPath(String searchPath) { - searchPath = "classpath:"+searchPath; - searchPath = searchPath - .replaceAll("classpath\\*:", "classpath:") - .replace("\\", "/") - .replaceAll("//+", "/") - .replace("classpath:classpath:", "classpath:"); + searchPath = searchPath.replace("\\", "/"); + searchPath = searchPath.replaceAll("classpath\\*?:", ""); + searchPath = "/" + searchPath; + searchPath = searchPath.replaceAll("//+", "/"); + + searchPath = "classpath*:" + searchPath; return searchPath; } diff --git a/liquibase-core/src/main/java/liquibase/logging/core/BufferedLogService.java b/liquibase-core/src/main/java/liquibase/logging/core/BufferedLogService.java index fa6a5677fdf..31138a9fff6 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/BufferedLogService.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/BufferedLogService.java @@ -12,7 +12,10 @@ import java.util.logging.Level; public class BufferedLogService extends AbstractLogService { - + // + // Truncate the return value at 10MB = 10,000,000 bytes + // + public static final int MAX_LOG_LENGTH = 10000000; private List<BufferedLogMessage> log = new ArrayList<>(); @@ -55,6 +58,9 @@ public String getLogAsString(Level minimumLevel) { } } + if (returnLog.length() > MAX_LOG_LENGTH) { + returnLog.setLength(MAX_LOG_LENGTH); + } return returnLog.toString(); } diff --git a/liquibase-core/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java b/liquibase-core/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java index 15c86630015..8fecd0e2c06 100644 --- a/liquibase-core/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java +++ b/liquibase-core/src/main/java/liquibase/parser/core/xml/LiquibaseEntityResolver.java @@ -16,6 +16,8 @@ */ public class LiquibaseEntityResolver implements EntityResolver2 { + final ClassLoaderResourceAccessor fallbackResourceAccessor = new ClassLoaderResourceAccessor(); + @Override @java.lang.SuppressWarnings("squid:S2095") public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException { @@ -33,7 +35,7 @@ public InputSource resolveEntity(String name, String publicId, String baseURI, S .replaceFirst("https?://", ""); - ResourceAccessor resourceAccessor = new CompositeResourceAccessor(Scope.getCurrentScope().getResourceAccessor(), new ClassLoaderResourceAccessor()); + ResourceAccessor resourceAccessor = new CompositeResourceAccessor(Scope.getCurrentScope().getResourceAccessor(), fallbackResourceAccessor); InputStreamList streams = resourceAccessor.openStreams(null, path); if (streams.isEmpty()) { log.fine("Unable to resolve XML entity locally. Will load from network."); diff --git a/liquibase-core/src/main/java/liquibase/resource/ClassLoaderResourceAccessor.java b/liquibase-core/src/main/java/liquibase/resource/ClassLoaderResourceAccessor.java index 4b2204111f2..5d24986112e 100644 --- a/liquibase-core/src/main/java/liquibase/resource/ClassLoaderResourceAccessor.java +++ b/liquibase-core/src/main/java/liquibase/resource/ClassLoaderResourceAccessor.java @@ -10,9 +10,13 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; /** * An implementation of {@link FileSystemResourceAccessor} that builds up the file roots based on the passed {@link ClassLoader}. @@ -68,7 +72,12 @@ protected void loadRootPaths(ClassLoader classLoader) { Scope.getCurrentScope().getLog(getClass()).info("No filesystem provider for URL " + url.toExternalForm() + ". Will rely on classloader logic for listing files."); } } catch (FileSystemNotFoundException fsnfe) { - Scope.getCurrentScope().getLog(getClass()).info("Configured classpath location " + url.toString() + " does not exist"); + if (url.toExternalForm().matches(".*!.*!.*")) { + //spring sometimes sets up urls with nested urls like jar:file:/path/to/demo-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/mssql-jdbc-8.2.2.jre8.jar!/ which are not readable. + //That is expected, and will be handled by the SpringResourceAccessor + } else { + Scope.getCurrentScope().getLog(getClass()).info("Configured classpath location " + url.toString() + " does not exist"); + } } catch (Throwable e) { Scope.getCurrentScope().getLog(getClass()).warning("Cannot create filesystem for url " + url.toExternalForm() + ": " + e.getMessage(), e); } @@ -139,7 +148,7 @@ protected String getFinalPath(String relativeTo, String streamPath) { // If this is a simple file name then set the // relativeTo value as if it is a root path // - if (! relativeTo.contains("/") && relativeTo.contains(".")) { + if (!relativeTo.contains("/") && relativeTo.contains(".")) { relativeTo = "/"; } streamPath = relativeTo + "/" + streamPath; @@ -230,31 +239,67 @@ protected SortedSet<String> listFromClassLoader(String path, boolean recursive, while (resources.hasMoreElements()) { final URL url = resources.nextElement(); + final String urlExternalForm = url.toExternalForm(); try { - final InputStream inputStream = url.openStream(); - - final String fileList = StreamUtil.readStreamAsString(inputStream); - if (!fileList.isEmpty()) { - for (String childName : fileList.split("\n")) { - String childPath = (path + "/" + childName).replaceAll("//+", "/"); - - if (isDirectory(childPath)) { - if (includeDirectories) { - returnSet.add(childPath); - } - if (recursive) { - returnSet.addAll(listFromClassLoader(childPath, recursive, includeFiles, includeDirectories)); + if (urlExternalForm.startsWith("jar:file:") && urlExternalForm.contains("!")) { + //We can search the jar directly + String jarPath = url.getPath(); + jarPath = jarPath.substring(5, jarPath.indexOf("!")); + try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) { + String comparePath = path; + if (comparePath.startsWith("/")) { + comparePath = "/"+comparePath; + } + Enumeration<JarEntry> entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.startsWith(comparePath) && !comparePath.equals(name)) { + if (entry.isDirectory()) { + if (!includeDirectories) { + continue; + } + + if (recursive || !name.substring(comparePath.length()).contains("/")) { + returnSet.add(name); + } + } else { + if (includeFiles) { + if (recursive || !name.substring(comparePath.length()).contains("/")) { + returnSet.add(name); + } + } + } } - } else { - if (includeFiles) { - returnSet.add(childPath); + } + } + } else { + //fall back to seeing if the stream lists sub-directories + final InputStream inputStream = url.openStream(); + + final String fileList = StreamUtil.readStreamAsString(inputStream); + if (!fileList.isEmpty()) { + for (String childName : fileList.split("\n")) { + String childPath = (path + "/" + childName).replaceAll("//+", "/"); + + if (isDirectory(childPath)) { + if (includeDirectories) { + returnSet.add(childPath); + } + if (recursive) { + returnSet.addAll(listFromClassLoader(childPath, recursive, includeFiles, includeDirectories)); + } + } else { + if (includeFiles) { + returnSet.add(childPath); + } } } } } } catch (IOException e) { - Scope.getCurrentScope().getLog(getClass()).severe("Cannot list resources in " + url.toExternalForm() + ": " + e.getMessage(), e); + Scope.getCurrentScope().getLog(getClass()).severe("Cannot list resources in " + urlExternalForm + ": " + e.getMessage(), e); } } return returnSet; diff --git a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java index 714198b991a..d92500cf586 100644 --- a/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java +++ b/liquibase-core/src/main/java/liquibase/snapshot/JdbcDatabaseSnapshot.java @@ -971,6 +971,8 @@ public List<CachedRow> fastFetchQuery() throws SQLException, DatabaseException { return queryMssql(catalogAndSchema, table); } else if (database instanceof Db2zDatabase) { return queryDb2Zos(catalogAndSchema, table); + } else if ( database instanceof PostgresDatabase) { + return queryPostgres(catalogAndSchema, table); } String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); @@ -989,6 +991,8 @@ public List<CachedRow> bulkFetchQuery() throws SQLException, DatabaseException { return queryMssql(catalogAndSchema, null); } else if (database instanceof Db2zDatabase) { return queryDb2Zos(catalogAndSchema, null); + } else if ( database instanceof PostgresDatabase) { + return queryPostgres(catalogAndSchema, table); } String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); @@ -1073,6 +1077,13 @@ private List<CachedRow> queryDb2Zos(CatalogAndSchema catalogAndSchema, String ta return executeAndExtract(sql, database); } + private List<CachedRow> queryPostgres(CatalogAndSchema catalogAndSchema, String tableName) throws SQLException { + String catalog = ((AbstractJdbcDatabase) database).getJdbcCatalogName(catalogAndSchema); + String schema = ((AbstractJdbcDatabase) database).getJdbcSchemaName(catalogAndSchema); + return extract(databaseMetaData.getTables(catalog, schema, ((tableName == null) ? + SQL_FILTER_MATCH_ALL : tableName), new String[]{"TABLE", "PARTITIONED TABLE"})); + + } }); } diff --git a/liquibase-core/src/main/resources/liquibase/i18n/liquibase-commandline-helptext.xml b/liquibase-core/src/main/resources/liquibase/i18n/liquibase-commandline-helptext.xml index 603bc0055ce..67ff51c8565 100644 --- a/liquibase-core/src/main/resources/liquibase/i18n/liquibase-commandline-helptext.xml +++ b/liquibase-core/src/main/resources/liquibase/i18n/liquibase-commandline-helptext.xml @@ -122,28 +122,38 @@ Documentation Commands grouped by default according to their update command's "deployment_id" value. Maintenance Commands - tag <tag string> 'Tags' the current database state for future rollback - tagExists <tag string> Checks whether the given tag is already existing - status [--verbose] Outputs count (list if --verbose) of unrun changesets + tag <tag string> 'Tags' the current database state for future + rollback + tagExists <tag string> Checks whether the given tag is already existing + status [--verbose] Outputs count (list if --verbose) of unrun + changesets unexpectedChangeSets [--verbose] - Outputs count (list if --verbose) of changesets run - in the database that do not exist in the changelog. - validate Checks changelog for errors - calculateCheckSum <id> Calculates and prints a checksum for the changeset - with the given id in the format filepath::id::author. - clearCheckSums Removes all saved checksums from database log. - Useful for 'MD5Sum Check Failed' errors - changelogSync Mark all changes as executed in the database - changelogSyncSQL Writes SQL to mark all changes as executed - in the database to STDOUT - markNextChangeSetRan Mark the next change changes as executed - in the database - markNextChangeSetRanSQL Writes SQL to mark the next change - as executed in the database to STDOUT - listLocks Lists who currently has locks on the - database changelog - releaseLocks Releases all locks on the database changelog - dropAll Drop all database objects owned by user + Outputs count (list if --verbose) of changesets + run + in the database that do not exist in the + changelog. + validate Checks changelog for errors + calculateCheckSum <id> Calculates and prints a checksum for the changeset + with the given id in the format + filepath::id::author. + clearCheckSums Removes all saved checksums from database log. + Useful for 'MD5Sum Check Failed' errors + changelogSync Mark all changes as executed in the database + changelogSyncSQL Writes SQL to mark all changes as executed + in the database to STDOUT + changelogSyncToTag <tag> Mark all changes, upto and including the specified + tag, as executed in the database + changelogSyncToTagSQL <tag> Write SQL to mark all changes, upto and including + the specified tag, as executed in the database to + STDOUT + markNextChangeSetRan Mark the next change changes as executed + in the database + markNextChangeSetRanSQL Writes SQL to mark the next change + as executed in the database to STDOUT + listLocks Lists who currently has locks on the + database changelog + releaseLocks Releases all locks on the database changelog + dropAll Drop all database objects owned by user Required Parameters: --changeLogFile=<path and filename> Migration file diff --git a/liquibase-core/src/main/resources/liquibasetasks.properties b/liquibase-core/src/main/resources/liquibasetasks.properties index f71a0b22210..cb0e83df42b 100644 --- a/liquibase-core/src/main/resources/liquibasetasks.properties +++ b/liquibase-core/src/main/resources/liquibasetasks.properties @@ -10,6 +10,7 @@ diffDatabaseToChangeLog=liquibase.integration.ant.DiffDatabaseToChangeLogTask dbDoc=liquibase.integration.ant.DBDocTask tagDatabase=liquibase.integration.ant.TagDatabaseTask changeLogSync=liquibase.integration.ant.ChangeLogSyncTask +changeLogSyncToTag=liquibase.integration.ant.ChangeLogSyncToTagTask dropAllDatabaseObjects=liquibase.integration.ant.DropAllTask markNextChangeSetRan=liquibase.integration.ant.MarkNextChangeSetRanTask -updateTestingRollback=liquibase.integration.ant.DatabaseUpdateTestingRollbackTask \ No newline at end of file +updateTestingRollback=liquibase.integration.ant.DatabaseUpdateTestingRollbackTask diff --git a/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy b/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy index 0b9344641e5..1195aba0d15 100644 --- a/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/LiquibaseTest.groovy @@ -4,21 +4,32 @@ import liquibase.changelog.ChangeLogIterator import liquibase.changelog.DatabaseChangeLog import liquibase.database.Database import liquibase.database.core.MockDatabase +import liquibase.database.jvm.JdbcConnection +import liquibase.exception.DatabaseException import liquibase.exception.LiquibaseException import liquibase.hub.HubConfiguration import liquibase.hub.HubService import liquibase.hub.HubServiceFactory import liquibase.hub.core.MockHubService -import liquibase.hub.model.Connection import liquibase.lockservice.LockService import liquibase.lockservice.LockServiceFactory import liquibase.parser.ChangeLogParser import liquibase.parser.ChangeLogParserFactory import liquibase.parser.MockChangeLogParser +import liquibase.resource.ClassLoaderResourceAccessor import liquibase.sdk.resource.MockResourceAccessor +import liquibase.snapshot.SnapshotGeneratorFactory import liquibase.ui.ConsoleUIService import spock.lang.Specification +import java.sql.Connection +import java.sql.DriverManager +import java.sql.PreparedStatement +import java.sql.SQLException +import java.util.regex.Matcher +import java.util.regex.Pattern + +import static java.lang.String.format import static org.junit.Assert.* class LiquibaseTest extends Specification { @@ -35,7 +46,10 @@ class LiquibaseTest extends Specification { private DatabaseChangeLog mockChangeLog private ChangeLogIterator mockChangeLogIterator + JdbcConnection h2Connection + def setup() { + h2Connection = null; mockResourceAccessor = new MockResourceAccessor() // mockDatabase = mock(Database.class); // mockLockService = mock(LockService.class); @@ -92,6 +106,10 @@ class LiquibaseTest extends Specification { ChangeLogParserFactory.reset() Scope.exit(setupScopeId) ChangeLogParserFactory.reset() + + if (h2Connection != null) { + h2Connection.close() + } } @@ -106,20 +124,20 @@ class LiquibaseTest extends Specification { assertNotNull("change log object may not be null", liquibase.getLog()) assertEquals("correct name of the change log file is returned", - "com/example/test.xml", liquibase.getChangeLogFile()) + "com/example/test.xml", liquibase.getChangeLogFile()) assertSame("ressourceAccessor property is set as requested", - resourceAccessor, liquibase.getResourceAccessor()) + resourceAccessor, liquibase.getResourceAccessor()) assertNotNull("parameters list for the change log is not null", - liquibase.getChangeLogParameters()) + liquibase.getChangeLogParameters()) assertEquals("Standard database changelog parameters were not set", - "DATABASECHANGELOGLOCK", - liquibase.getChangeLogParameters().getValue("database.databaseChangeLogLockTableName", null) + "DATABASECHANGELOGLOCK", + liquibase.getChangeLogParameters().getValue("database.databaseChangeLogLockTableName", null) ) assertSame("database object for the change log is set as requested", - mockDatabase, liquibase.getDatabase()) + mockDatabase, liquibase.getDatabase()) } def testConstructorChangelogPathsStandardize() throws Exception { @@ -128,19 +146,19 @@ class LiquibaseTest extends Specification { then: assertEquals("Windows path separators are translated correctly", - "path/with/windows/separators.xml", liquibase.getChangeLogFile()) + "path/with/windows/separators.xml", liquibase.getChangeLogFile()) when: liquibase = new Liquibase("path/with/unix/separators.xml", mockResourceAccessor, mockDatabase) then: assertEquals("Unix path separators are left intact", - "path/with/unix/separators.xml", liquibase.getChangeLogFile()) + "path/with/unix/separators.xml", liquibase.getChangeLogFile()) when: liquibase = new Liquibase("/absolute/path/remains.xml", mockResourceAccessor, mockDatabase) then: assertEquals("An absolute path is left intact", - "/absolute/path/remains.xml", liquibase.getChangeLogFile()) + "/absolute/path/remains.xml", liquibase.getChangeLogFile()) } // @Test @@ -167,7 +185,7 @@ class LiquibaseTest extends Specification { then: assertSame("ressourceAccessor is set as requested", - liquibase.getResourceAccessor(), liquibase.getResourceAccessor()) + liquibase.getResourceAccessor(), liquibase.getResourceAccessor()) } // @Test @@ -193,7 +211,7 @@ class LiquibaseTest extends Specification { then: mockHubService.sentObjects.toString() == - "[setRanChangeSets/Connection jdbc://test ($MockHubService.randomUUID):[test/changelog.xml::1::mock-author, test/changelog.xml::2::mock-author, test/changelog.xml::3::mock-author], startOperation/$MockHubService.randomUUID:[$MockHubService.operationCreateDate]]" + "[setRanChangeSets/Connection jdbc://test ($MockHubService.randomUUID):[test/changelog.xml::1::mock-author, test/changelog.xml::2::mock-author, test/changelog.xml::3::mock-author], startOperation/$MockHubService.randomUUID:[$MockHubService.operationCreateDate]]" } @@ -250,9 +268,9 @@ class LiquibaseTest extends Specification { then: connection == null message == - "WARNING: The API key 'API_KEY' was found, but no changelog ID exists.\n" + - "No operations will be reported. Register this changelog with Liquibase Hub to generate free deployment reports.\n" + - "Learn more at https://hub.liquibase.com." + "WARNING: The API key 'API_KEY' was found, but no changelog ID exists.\n" + + "No operations will be reported. Register this changelog with Liquibase Hub to generate free deployment reports.\n" + + "Learn more at https://hub.liquibase.com." } // @Test(expected = LockException.class) @@ -315,8 +333,209 @@ class LiquibaseTest extends Specification { // }); // } + + def syncChangeLogForUnmanagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + + Liquibase liquibase = createUnmanagedDatabase(h2Connection); + assertFalse(hasDatabaseChangeLogTable(liquibase)); + + liquibase.changeLogSync(""); + + then: + assert hasDatabaseChangeLogTable(liquibase); + assertTags(liquibase, "1.0", "1.1", "2.0"); + } + + def syncChangeLogToTagForUnmanagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + + Liquibase liquibase = createUnmanagedDatabase(h2Connection); + + then: + assert !hasDatabaseChangeLogTable(liquibase) + + when: + liquibase.changeLogSync("1.1", ""); + + then: + assert hasDatabaseChangeLogTable(liquibase); + assertTags(liquibase, "1.0", "1.1"); + } + + def syncChangeLogForManagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + + Liquibase liquibase = createDatabaseAtTag(h2Connection, "1.0"); + + then: + assert hasDatabaseChangeLogTable(liquibase) + + when: + liquibase.changeLogSync(""); + + then: + assertTags(liquibase, "1.0", "1.1", "2.0"); + } + + def syncChangeLogToTagForManagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + + Liquibase liquibase = createDatabaseAtTag(h2Connection, "1.0"); + then: + assert hasDatabaseChangeLogTable(liquibase); + + when: + liquibase.changeLogSync("1.1", ""); + + then: + assertTags(liquibase, "1.0", "1.1"); + } + + def syncChangeLogSqlForUnmanagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + StringWriter writer = new StringWriter(); + + Liquibase liquibase = createUnmanagedDatabase(h2Connection); + + then: + assert !hasDatabaseChangeLogTable(liquibase); + + when: + liquibase.changeLogSync("", writer); + + then: + assert !hasDatabaseChangeLogTable(liquibase); + assertSqlOutputAppliesTags(writer.toString(), "1.0", "1.1", "2.0"); + } + + def syncChangeLogToTagSqlForUnmanagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + StringWriter writer = new StringWriter(); + + Liquibase liquibase = createUnmanagedDatabase(h2Connection); + + then: + assert !hasDatabaseChangeLogTable(liquibase); + + when: + liquibase.changeLogSync("1.1", "", writer); + + then: + !hasDatabaseChangeLogTable(liquibase); + assertSqlOutputAppliesTags(writer.toString(), "1.0", "1.1"); + } + + def syncChangeLogSqlForManagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + StringWriter writer = new StringWriter(); + + Liquibase liquibase = createDatabaseAtTag(h2Connection, "1.0"); + + then: + assert hasDatabaseChangeLogTable(liquibase); + + when: + liquibase.changeLogSync("", writer); + + then: + assertSqlOutputAppliesTags(writer.toString(), "1.1", "2.0"); + } + + def syncChangeLogToTagSqlForManagedDatabase() throws Exception { + when: + h2Connection = getInMemoryH2DatabaseConnection(); + StringWriter writer = new StringWriter(); + + Liquibase liquibase = createDatabaseAtTag(h2Connection, "1.0"); + + then: + assertTrue(hasDatabaseChangeLogTable(liquibase)); + + when: + liquibase.changeLogSync("1.1", "", writer); + + then: + assertSqlOutputAppliesTags(writer.toString(), "1.1"); + } + + private JdbcConnection getInMemoryH2DatabaseConnection() throws SQLException { + String urlFormat = "jdbc:h2:mem:%s"; + return new JdbcConnection(DriverManager.getConnection(format(urlFormat, UUID.randomUUID().toString()))); + } + + private Liquibase createUnmanagedDatabase(JdbcConnection connection) throws SQLException, LiquibaseException { + String createTableSql = "CREATE TABLE PUBLIC.TABLE_A (ID INTEGER);"; + + PreparedStatement stmt = connection.getUnderlyingConnection().prepareStatement(createTableSql) + try { + stmt.execute(); + } finally { + stmt.close() + } + + return new Liquibase("liquibase/tagged-changelog.xml", new ClassLoaderResourceAccessor(), connection); + } + + private Liquibase createDatabaseAtTag(JdbcConnection connection, String tag) throws LiquibaseException { + Liquibase liquibase = new Liquibase("liquibase/tagged-changelog.xml", new ClassLoaderResourceAccessor(), + connection); + liquibase.update(tag, ""); + return liquibase; + } + + private boolean hasDatabaseChangeLogTable(Liquibase liquibase) throws DatabaseException { + return SnapshotGeneratorFactory.getInstance().hasDatabaseChangeLogTable(liquibase.database); + } + + private void assertTags(Liquibase liquibase, String... expectedTags) throws DatabaseException { + def actualTags = [] + for (def ranChangeset : liquibase.database.getRanChangeSetList()) { + if (ranChangeset.getTag() != null) { + actualTags.add(ranChangeset.getTag()) + } + } + + assertEquals(Arrays.asList(expectedTags), actualTags); + } + + private void assertSqlOutputAppliesTags(String output, String... expectedTags) throws IOException { + String insertTagH2SqlTemplate = + "INSERT INTO PUBLIC\\.DATABASECHANGELOG \\(.*, DESCRIPTION,.*, TAG\\) VALUES \\(.*, 'tagDatabase',.*, '%s'\\);"; + + List<Pattern> patterns = [] + + for (def tag : expectedTags) { + patterns.add(Pattern.compile(String.format(insertTagH2SqlTemplate, tag))) + } + + BufferedReader reader = new BufferedReader(new StringReader(output)) + try { + String line; + int index = 0; + + while ((line = reader.readLine()) != null && index < patterns.size()) { + Matcher matcher = patterns.get(index).matcher(line); + if (matcher.matches()) { + index++; + } + } + assertTrue(index > 0 && index == patterns.size()); + } finally { + reader.close() + } + } + public static class TestConsoleUIService extends ConsoleUIService { private List<String> messages = new ArrayList<>() + @Override void sendMessage(String message) { messages.add(message) diff --git a/liquibase-core/src/test/groovy/liquibase/change/core/LoadDataChangeTest.groovy b/liquibase-core/src/test/groovy/liquibase/change/core/LoadDataChangeTest.groovy index bc4c2f8f93f..5d12267a938 100644 --- a/liquibase-core/src/test/groovy/liquibase/change/core/LoadDataChangeTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/change/core/LoadDataChangeTest.groovy @@ -11,6 +11,8 @@ import liquibase.parser.core.ParsedNodeException import liquibase.resource.ResourceAccessor import liquibase.snapshot.MockSnapshotGeneratorFactory import liquibase.snapshot.SnapshotGeneratorFactory +import liquibase.statement.ExecutablePreparedStatement +import liquibase.statement.ExecutablePreparedStatementBase import liquibase.statement.SqlStatement import liquibase.statement.core.InsertSetStatement import liquibase.statement.core.InsertStatement @@ -414,4 +416,132 @@ public class LoadDataChangeTest extends StandardChangeTest { then: assert md5sum1.equals(md5sum2) } + + def "usePreparedStatements set to false produces InsertSetStatement"() throws Exception { + when: + LoadDataChange loadDataChange = new LoadDataChange(); + loadDataChange.setSchemaName("SCHEMA_NAME"); + loadDataChange.setTableName("TABLE_NAME"); + loadDataChange.setUsePreparedStatements(Boolean.FALSE); + loadDataChange.setFile("liquibase/change/core/sample.data1.csv"); + + SqlStatement[] sqlStatement = loadDataChange.generateStatements(new MSSQLDatabase()); + + then: + sqlStatement.length == 1 + assert sqlStatement[0] instanceof InsertSetStatement + + when: + SqlStatement[] sqlStatements = ((InsertSetStatement) sqlStatement[0]).getStatementsArray(); + + then: + sqlStatements.length == 2 + assert sqlStatements[0] instanceof InsertStatement + assert sqlStatements[1] instanceof InsertStatement + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[0]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[0]).getTableName() + "Bob Johnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("name") + "bjohnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("username") + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[1]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[1]).getTableName() + "John Doe" == ((InsertStatement) sqlStatements[1]).getColumnValue("name") + "jdoe" == ((InsertStatement) sqlStatements[1]).getColumnValue("username") + } + def "usePreparedStatements set to true produces PreparedStatement"() throws Exception { + when: + LoadDataChange loadDataChange = new LoadDataChange(); + loadDataChange.setSchemaName("SCHEMA_NAME"); + loadDataChange.setTableName("TABLE_NAME"); + loadDataChange.setUsePreparedStatements(Boolean.TRUE); + loadDataChange.setFile("liquibase/change/core/sample.data1.csv"); + + SqlStatement[] sqlStatement = loadDataChange.generateStatements(new MSSQLDatabase() { public boolean supportsBatchUpdates() { return true; } }); + + then: + sqlStatement.length == 1 + assert sqlStatement[0] instanceof ExecutablePreparedStatement + + when: + SqlStatement[] sqlStatements = ((ExecutablePreparedStatement) sqlStatement[0]).getIndividualStatements(); + + then: + sqlStatements.length == 2 + assert sqlStatements[0] instanceof ExecutablePreparedStatement + assert sqlStatements[1] instanceof ExecutablePreparedStatement + + "SCHEMA_NAME" == ((ExecutablePreparedStatementBase) sqlStatements[0]).getSchemaName() + "TABLE_NAME" == ((ExecutablePreparedStatementBase) sqlStatements[0]).getTableName() + + + "SCHEMA_NAME" == ((ExecutablePreparedStatementBase) sqlStatements[1]).getSchemaName() + "TABLE_NAME" == ((ExecutablePreparedStatementBase) sqlStatements[1]).getTableName() + + } + def "DB NO Batch Update Support usePrepared True produces InsertSetStatement"() throws Exception { + when: + LoadDataChange loadDataChange = new LoadDataChange(); + loadDataChange.setSchemaName("SCHEMA_NAME"); + loadDataChange.setTableName("TABLE_NAME"); + loadDataChange.setUsePreparedStatements(Boolean.TRUE); + loadDataChange.setFile("liquibase/change/core/sample.data1.csv"); + + SqlStatement[] sqlStatement = loadDataChange.generateStatements(new MSSQLDatabase()); + + then: + sqlStatement.length == 1 + assert sqlStatement[0] instanceof InsertSetStatement + + when: + SqlStatement[] sqlStatements = ((InsertSetStatement) sqlStatement[0]).getStatementsArray(); + + then: + sqlStatements.length == 2 + assert sqlStatements[0] instanceof InsertStatement + assert sqlStatements[1] instanceof InsertStatement + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[0]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[0]).getTableName() + "Bob Johnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("name") + "bjohnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("username") + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[1]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[1]).getTableName() + "John Doe" == ((InsertStatement) sqlStatements[1]).getColumnValue("name") + "jdoe" == ((InsertStatement) sqlStatements[1]).getColumnValue("username") + } + def "DB Batch Update Support usePrepared False produces InsertSetStatement"() throws Exception { + when: + LoadDataChange loadDataChange = new LoadDataChange(); + loadDataChange.setSchemaName("SCHEMA_NAME"); + loadDataChange.setTableName("TABLE_NAME"); + loadDataChange.setUsePreparedStatements(Boolean.FALSE); + loadDataChange.setFile("liquibase/change/core/sample.data1.csv"); + + SqlStatement[] sqlStatement = loadDataChange.generateStatements(new MSSQLDatabase() { public boolean supportsBatchUpdates() { return true; } }); + + then: + sqlStatement.length == 1 + assert sqlStatement[0] instanceof InsertSetStatement + + when: + SqlStatement[] sqlStatements = ((InsertSetStatement) sqlStatement[0]).getStatementsArray(); + + then: + sqlStatements.length == 2 + assert sqlStatements[0] instanceof InsertStatement + assert sqlStatements[1] instanceof InsertStatement + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[0]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[0]).getTableName() + "Bob Johnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("name") + "bjohnson" == ((InsertStatement) sqlStatements[0]).getColumnValue("username") + + "SCHEMA_NAME" == ((InsertStatement) sqlStatements[1]).getSchemaName() + "TABLE_NAME" == ((InsertStatement) sqlStatements[1]).getTableName() + "John Doe" == ((InsertStatement) sqlStatements[1]).getColumnValue("name") + "jdoe" == ((InsertStatement) sqlStatements[1]).getColumnValue("username") + } + } diff --git a/liquibase-core/src/test/groovy/liquibase/integration/ant/test/LiquibaseTagExistsCondition.groovy b/liquibase-core/src/test/groovy/liquibase/integration/ant/test/LiquibaseTagExistsCondition.groovy new file mode 100644 index 00000000000..8b8ce19af4c --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/integration/ant/test/LiquibaseTagExistsCondition.groovy @@ -0,0 +1,49 @@ +package liquibase.integration.ant.test + +import groovy.sql.Sql +import org.apache.tools.ant.BuildException +import org.apache.tools.ant.ProjectComponent +import org.apache.tools.ant.taskdefs.condition.Condition + +class LiquibaseTagExistsCondition extends ProjectComponent implements Condition { + private String driver + private String url + private String user + private String password + private String tag + + @Override + boolean eval() throws BuildException { + Sql sql = null + try { + sql = Sql.newInstance(url, user, password, driver) + def result = false + sql.query("SELECT TAG FROM DATABASECHANGELOG WHERE TAG IS NOT NULL AND TAG = $tag;") { + result = it.next() + } + return result + } finally { + sql?.close() + } + } + + void setDriver(String driver) { + this.driver = driver + } + + void setUrl(String url) { + this.url = url + } + + void setUser(String user) { + this.user = user + } + + void setPassword(String password) { + this.password = password + } + + void setTag(String tag) { + this.tag = tag + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/integration/spring/SpringResourceAccessorTest.groovy b/liquibase-core/src/test/groovy/liquibase/integration/spring/SpringResourceAccessorTest.groovy index b620ee14d15..21fab7bd8d0 100644 --- a/liquibase-core/src/test/groovy/liquibase/integration/spring/SpringResourceAccessorTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/integration/spring/SpringResourceAccessorTest.groovy @@ -2,6 +2,7 @@ package liquibase.integration.spring import org.springframework.core.io.DefaultResourceLoader import spock.lang.Specification +import spock.lang.Unroll class SpringResourceAccessorTest extends Specification { @@ -75,5 +76,23 @@ class SpringResourceAccessorTest extends Specification { list.contains("MSSQLDatabaseTest.class,") } + @Unroll + def finalizeSearchPath() { + expect: + new SpringResourceAccessor().finalizeSearchPath(input) == expected + + where: + input | expected + "/path/to/file" | "classpath*:/path/to/file" + "//path////to/file" | "classpath*:/path/to/file" + "path/to/file" | "classpath*:/path/to/file" + "classpath:path/to/file" | "classpath*:/path/to/file" + "classpath:/path/to/file" | "classpath*:/path/to/file" + "classpath:classpath:/path/to/file" | "classpath*:/path/to/file" + "classpath*:/path/to/file" | "classpath*:/path/to/file" + "classpath*:path/to/file" | "classpath*:/path/to/file" + + } + } diff --git a/liquibase-core/src/test/groovy/liquibase/logging/core/BufferedLogServiceTest.groovy b/liquibase-core/src/test/groovy/liquibase/logging/core/BufferedLogServiceTest.groovy new file mode 100644 index 00000000000..0d22bcd5ce2 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/logging/core/BufferedLogServiceTest.groovy @@ -0,0 +1,34 @@ +package liquibase.logging.core + +import com.example.liquibase.change.CreateTableExampleChange +import liquibase.Scope +import liquibase.change.Change +import liquibase.change.core.CreateTableChange +import liquibase.util.StringUtil +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.logging.Level + +class BufferedLogServiceTest extends Specification { + def "getLogAsString truncates"() { + when: + String startMessage = "Test message" + for (int i=0; i < 1000; i++) { + startMessage += "-Test Message" + } + String message = "" + for (int i=0; i < 1000; i++) { + message += startMessage + } + BufferedLogService bufferedLogService = new BufferedLogService() + BufferedLogService.BufferedLogMessage log = + new BufferedLogService.BufferedLogMessage(Level.FINE, BufferedLogServiceTest.class, message, null) + bufferedLogService.addLog(log) + String logOutput = bufferedLogService.getLogAsString(Level.FINE) + + then: + logOutput != null + logOutput.length() == 10000000 + } +} diff --git a/liquibase-core/src/test/resources/liquibase/integration/ant/ChangeLogSyncTaskTest.xml b/liquibase-core/src/test/resources/liquibase/integration/ant/ChangeLogSyncTaskTest.xml index 367bfffd26d..41888757a1b 100644 --- a/liquibase-core/src/test/resources/liquibase/integration/ant/ChangeLogSyncTaskTest.xml +++ b/liquibase-core/src/test/resources/liquibase/integration/ant/ChangeLogSyncTaskTest.xml @@ -44,6 +44,8 @@ </lb:changeLogSync> <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> </target> <target name="testChangeLogSyncDatabaseRef"> @@ -52,6 +54,8 @@ <lb:changeLogSync databaseref="test-db" changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml"/> <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> </target> <target name="testChangeLogSyncToOutputFile"> @@ -62,6 +66,58 @@ <au:assertFileExists file="${temp.dir}/sync.sql"/> </target> + <target name="testChangeLogSyncToTag"> + <db:assertTableDoesntExist driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <lb:changeLogSyncToTag changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml" + toTag="version_1.0"> + <lb:database driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}"/> + </lb:changeLogSyncToTag> + <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + <db:assertTagNotExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> + </target> + + <target name="testChangeLogSyncToLatestTag"> + <db:assertTableDoesntExist driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <lb:changeLogSyncToTag changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml" + toTag="version_2.0"> + <lb:database driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}"/> + </lb:changeLogSyncToTag> + <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> + </target> + + <target name="testChangeLogSyncToTagDatabaseRef"> + <db:assertTableDoesntExist driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <lb:changeLogSyncToTag databaseref="test-db" changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml" + toTag="version_1.0"/> + <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + <db:assertTagNotExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> + </target> + + <target name="testChangeLogSyncToTagToOutputFile"> + <lb:changeLogSyncToTag changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml" + outputfile="${temp.dir}/sync.sql" + toTag="version_1.0"> + <lb:database driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}"/> + </lb:changeLogSyncToTag> + <au:assertFileExists file="${temp.dir}/sync.sql"/> + </target> + <target name="testChangeLogSyncMissingDatabase"> <au:expectfailure> <lb:changeLogSync changelogfile="${liquibase.test.ant.basedir}/changelog/simple-changelog.xml"/> @@ -87,6 +143,8 @@ </lb:changeLogSync> <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> </target> <target name="testChangeLogSyncChangeLogDirectoryDoesNotExist"> @@ -111,6 +169,44 @@ <lb:changeLogSync databaseref="test-db" changelogdirectory="${liquibase.test.ant.basedir}/changelog" changelogfile="simple-changelog.xml"/> <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + </target> + + <target name="testChangeLogSyncToTagChangeLogDirectory"> + <db:assertTableDoesntExist driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <lb:changeLogSyncToTag changelogdirectory="${liquibase.test.ant.basedir}/changelog" changelogfile="simple-changelog.xml" + toTag="version_1.0"> + <lb:database driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}"/> + </lb:changeLogSyncToTag> + <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + <db:assertTagNotExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> + </target> + + <target name="testChangeLogSyncToTagChangeLogDirectoryToOutputFile"> + <lb:changeLogSyncToTag changelogdirectory="${liquibase.test.ant.basedir}/changelog" changelogfile="simple-changelog.xml" + outputfile="${temp.dir}/sync.sql" toTag="version_1.0"> + <lb:database driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}"/> + </lb:changeLogSyncToTag> + <au:assertFileExists file="${temp.dir}/sync.sql"/> + </target> + + <target name="testChangeLogSyncToTagDatabaseRefChangeLogDirectory"> + <db:assertTableDoesntExist driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <lb:changeLogSyncToTag databaseref="test-db" changelogdirectory="${liquibase.test.ant.basedir}/changelog" changelogfile="simple-changelog.xml" + toTag="version_1.0"/> + <db:assertTableExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + table="DATABASECHANGELOG"/> + <db:assertTagExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_1.0"/> + <db:assertTagNotExists driver="${jdbc.driver}" url="${jdbc.url}" user="${db.user}" password="${db.password}" + tag="version_2.0"/> </target> </project> diff --git a/liquibase-core/src/test/resources/liquibase/integration/ant/changelog/simple-changelog.xml b/liquibase-core/src/test/resources/liquibase/integration/ant/changelog/simple-changelog.xml index 1f8443548b7..027053e5f51 100644 --- a/liquibase-core/src/test/resources/liquibase/integration/ant/changelog/simple-changelog.xml +++ b/liquibase-core/src/test/resources/liquibase/integration/ant/changelog/simple-changelog.xml @@ -8,4 +8,20 @@ <column name="last_name" value="name"/> </insert> </changeSet> + + <changeSet id="2" author="testuser"> + <tagDatabase tag="version_1.0"/> + </changeSet> + + <changeSet id="3" author="testuser"> + <createTable tableName="groups"> + <column name="name" type="VARCHAR(50)"> + <constraints nullable="false"/> + </column> + </createTable> + </changeSet> + + <changeSet id="4" author="testuser"> + <tagDatabase tag="version_2.0"/> + </changeSet> </databaseChangeLog> \ No newline at end of file diff --git a/liquibase-core/src/test/resources/liquibase/integration/ant/test/antlib.xml b/liquibase-core/src/test/resources/liquibase/integration/ant/test/antlib.xml index 38eb451977c..5acf300484f 100644 --- a/liquibase-core/src/test/resources/liquibase/integration/ant/test/antlib.xml +++ b/liquibase-core/src/test/resources/liquibase/integration/ant/test/antlib.xml @@ -3,6 +3,7 @@ <typedef name="tableExists" classname="liquibase.integration.ant.test.TableExistsCondition"/> <typedef name="columnExists" classname="liquibase.integration.ant.test.ColumnExistsCondition"/> <typedef name="rowCountEquals" classname="liquibase.integration.ant.test.RowCountEqualsCondition"/> + <typedef name="tagExists" classname="liquibase.integration.ant.test.LiquibaseTagExistsCondition"/> <macrodef name="assertTableExists" backtrace="false"> <attribute name="driver"/> @@ -76,4 +77,32 @@ </au:assertTrue> </sequential> </macrodef> + + <macrodef name="assertTagExists" backtrace="false"> + <attribute name="driver"/> + <attribute name="url"/> + <attribute name="user"/> + <attribute name="password"/> + <attribute name="tag"/> + <attribute name="message" default="Assertion failed"/> + <sequential> + <au:assertTrue message="@{message}"> + <current:tagExists driver="@{driver}" url="@{url}" user="@{user}" password="@{password}" tag="@{tag}"/> + </au:assertTrue> + </sequential> + </macrodef> + + <macrodef name="assertTagNotExists" backtrace="false"> + <attribute name="driver"/> + <attribute name="url"/> + <attribute name="user"/> + <attribute name="password"/> + <attribute name="tag"/> + <attribute name="message" default="Assertion failed"/> + <sequential> + <au:assertFalse message="@{message}"> + <current:tagExists driver="@{driver}" url="@{url}" user="@{user}" password="@{password}" tag="@{tag}"/> + </au:assertFalse> + </sequential> + </macrodef> </antlib> \ No newline at end of file diff --git a/liquibase-core/src/test/resources/liquibase/tagged-changelog.xml b/liquibase-core/src/test/resources/liquibase/tagged-changelog.xml new file mode 100644 index 00000000000..3a4e70dcb49 --- /dev/null +++ b/liquibase-core/src/test/resources/liquibase/tagged-changelog.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + +<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog + http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.0.xsd"> + + <changeSet id="1" author="liquibase"> + <createTable tableName="TABLE_A" schemaName="PUBLIC"> + <column name="ID" type="INTEGER"/> + </createTable> + </changeSet> + + <changeSet id="2" author="liquibase"> + <tagDatabase tag="1.0"/> + </changeSet> + + <changeSet id="3" author="liquibase"> + <addColumn tableName="TABLE_A"> + <column name="COL_1" type="VARCHAR(10)"/> + </addColumn> + </changeSet> + + <changeSet id="4" author="liquibase"> + <tagDatabase tag="1.1"/> + </changeSet> + + <changeSet id="5" author="liquibase"> + <tagDatabase tag="2.0"/> + </changeSet> +</databaseChangeLog> \ No newline at end of file diff --git a/liquibase-dist/pom.xml b/liquibase-dist/pom.xml index a330c6d13ed..6ec22d9c2d4 100644 --- a/liquibase-dist/pom.xml +++ b/liquibase-dist/pom.xml @@ -17,8 +17,8 @@ <description>Liquibase is a tool for managing and executing database changes.</description> <properties> - <deploy.repositoryId>sonatype-nexus-staging</deploy.repositoryId> - <deploy.url>https://oss.sonatype.org/content/repositories/snapshots</deploy.url> + <deploy.repositoryId>github</deploy.repositoryId> + <deploy.url>https://maven.pkg.github.com/liquibase</deploy.url> <install4j.jre.root>PASS_IN_AS_SYSTEM_PROPERTY</install4j.jre.root> </properties> @@ -157,7 +157,8 @@ <descriptor>src/main/assembly/assembly-bin.xml</descriptor> </descriptors> <archive> - <manifestFile>${project.basedir}/../liquibase-core/target/classes/META-INF/MANIFEST.MF</manifestFile> + <manifestFile>${project.basedir}/../liquibase-core/target/classes/META-INF/MANIFEST.MF + </manifestFile> </archive> </configuration> <executions> @@ -235,50 +236,6 @@ </execution> </executions> </plugin> - <plugin> - <artifactId>maven-gpg-plugin</artifactId> - <version>1.6</version> - <configuration> - <passphrase>${env.GPG_PASSPHRASE}</passphrase> - <gpgArguments> - <arg>--batch</arg> - <arg>--no-tty</arg> - <!-- This is necessary for gpg to not try to use the pinentry programs --> - <arg>--pinentry-mode</arg> - <arg>loopback</arg> - </gpgArguments> - - <skip>false</skip> - <repositoryId>${deploy.repositoryId}</repositoryId> - <artifactId>liquibase-core</artifactId> - <version>${liquibase.version}</version> - <url>${deploy.url}</url> - <file>${project.build.directory}/liquibase-${liquibase.version}.jar</file> - <files> - target/liquibase-${liquibase.version}.tar.gz,target/liquibase-${liquibase.version}.zip - </files> - <types> - tar.gz,zip - </types> - <classifiers> - <!-- need empty classifier so deployed zip/tar files do not have appended "-bin" etc. suffixes --> - , - </classifiers> - <sources>${project.basedir}/../target/liquibase-${version}-sources.jar</sources> - <javadoc>${project.basedir}/../target/liquibase-${version}-javadoc.jar</javadoc> - <pomFile>${project.build.directory}/release.pom.xml</pomFile> - </configuration> - <executions> - <execution> - <id>custom-deploy</id> - <phase>deploy</phase> - <goals> - <goal>sign-and-deploy-file</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> @@ -404,7 +361,7 @@ </goals> <configuration> <url> - ${install4j.jre.root}/adopt-openjdk-windows-amd64-13.0.1.tar.gz + ${install4j.jre.root}/adopt-openjdk-windows-amd64-jre-11.0.10.9.tar.gz </url> <unpack>false</unpack> <outputDirectory>${project.build.directory}/downloaded</outputDirectory> @@ -418,7 +375,7 @@ </goals> <configuration> <url> - ${install4j.jre.root}/adopt-openjdk-macos-amd64-13.0.1.tar.gz + ${install4j.jre.root}/adopt-openjdk-macos-amd64-jre-11.0.10.9.tar.gz </url> <unpack>false</unpack> <outputDirectory>${project.build.directory}/downloaded</outputDirectory> @@ -452,6 +409,62 @@ </plugins> </build> </profile> + + <profile> + <id>gpg-sign</id> + <activation> + <property> + <name>env.GPG_PASSPHRASE</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <configuration> + <passphrase>${env.GPG_PASSPHRASE}</passphrase> + <gpgArguments> + <arg>--batch</arg> + <arg>--no-tty</arg> + <!-- This is necessary for gpg to not try to use the pinentry programs --> + <arg>--pinentry-mode</arg> + <arg>loopback</arg> + </gpgArguments> + + <skip>false</skip> + <repositoryId>${deploy.repositoryId}</repositoryId> + <artifactId>liquibase-core</artifactId> + <version>${liquibase.version}</version> + <url>${deploy.url}</url> + <file>${project.build.directory}/liquibase-${liquibase.version}.jar</file> + <files> + target/liquibase-${liquibase.version}.tar.gz,target/liquibase-${liquibase.version}.zip + </files> + <types> + tar.gz,zip + </types> + <classifiers> + <!-- need empty classifier so deployed zip/tar files do not have appended "-bin" etc. suffixes --> + , + </classifiers> + <sources>${project.basedir}/../target/liquibase-${version}-sources.jar</sources> + <javadoc>${project.basedir}/../target/liquibase-${version}-javadoc.jar</javadoc> + <pomFile>${project.build.directory}/release.pom.xml</pomFile> + </configuration> + <executions> + <execution> + <id>custom-deploy</id> + <phase>deploy</phase> + <goals> + <goal>sign-and-deploy-file</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> </profiles> </project> diff --git a/liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf b/liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf index f340bb39abf..8027684eda2 100644 --- a/liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf +++ b/liquibase-dist/src/main/archive/examples/xml/liquibase.sqlplus.conf @@ -21,7 +21,10 @@ #### # The full path to the SQLPLUS executable. -liquibase.sqlplus.path=/apps/app/12.2.0.1.0/oracle/product/12.2.0.1.0/client_1/bin/sqlplus +# Sample linux path +# liquibase.sqlplus.path=/apps/app/12.2.0.1.0/oracle/product/12.2.0.1.0/client_1/bin/sqlplus +# Sample windows path +# liquibase.sqlplus.path=c:\\oracle\\product\\11.2.0\\client_1\\bin\\sqlplus.exe # A valid timeout value for the execution of the SQLPLUS tool liquibase.sqlplus.timeout=-1 diff --git a/liquibase-dist/src/main/archive/lib/liquibase_autocomplete.sh b/liquibase-dist/src/main/archive/lib/liquibase_autocomplete.sh index 565b46dfa47..86e65db24f0 100644 --- a/liquibase-dist/src/main/archive/lib/liquibase_autocomplete.sh +++ b/liquibase-dist/src/main/archive/lib/liquibase_autocomplete.sh @@ -7,13 +7,13 @@ _liquibase() # Liquibase options, has to be improved to be more context aware opts=" - help - update - updateSQL - updateCount - updateCountSQL - updateToTag - updateToTagSQL + help + update + updateSQL + updateCount + updateCountSQL + updateToTag + updateToTagSQL status registerChangeLog syncHub @@ -46,6 +46,8 @@ _liquibase() clearCheckSums changelogSync changelogSyncSQL +changeLogSyncToTag +changeLogSyncToTagSQL markNextChangeSetRan markNextChangeSetRanSQL listLocks diff --git a/liquibase-dist/src/main/install4j/liquibase.install4j b/liquibase-dist/src/main/install4j/liquibase.install4j index c3aeb055ba5..b25d6387bb0 100644 --- a/liquibase-dist/src/main/install4j/liquibase.install4j +++ b/liquibase-dist/src/main/install4j/liquibase.install4j @@ -496,7 +496,7 @@ return console.askYesNo(message, true); </installerGui> <mediaSets> <windows name="Windows" id="153"> - <jreBundle jreBundleSource="preCreated" includedJre="../../../target/downloaded/adopt-openjdk-windows-amd64-13.0.1.tar.gz" manualJreEntry="true"> + <jreBundle jreBundleSource="preCreated" includedJre="../../../target/downloaded/adopt-openjdk-windows-amd64-jre-11.0.10.9.tar.gz" manualJreEntry="true"> <modules> <defaultModules set="jre" /> </modules> @@ -507,7 +507,7 @@ return console.askYesNo(message, true); <launcher id="156" /> <launcher id="158" /> </excludedLaunchers> - <jreBundle jreBundleSource="preCreated" includedJre="../../../target/downloaded/adopt-openjdk-macos-amd64-13.0.1.tar.gz" manualJreEntry="true"> + <jreBundle jreBundleSource="preCreated" includedJre="../../../target/downloaded/adopt-openjdk-macos-amd64-jre-11.0.10.9.tar.gz" manualJreEntry="true"> <modules> <defaultModules set="jre" /> </modules> diff --git a/.travis/databases.docker-compose.yml b/liquibase-integration-tests/docker/docker-compose.yml similarity index 100% rename from .travis/databases.docker-compose.yml rename to liquibase-integration-tests/docker/docker-compose.yml diff --git a/.travis/mysql-init.sql b/liquibase-integration-tests/docker/mysql-init.sql similarity index 100% rename from .travis/mysql-init.sql rename to liquibase-integration-tests/docker/mysql-init.sql diff --git a/.travis/postgres-init.sh b/liquibase-integration-tests/docker/postgres-init.sh old mode 100755 new mode 100644 similarity index 100% rename from .travis/postgres-init.sh rename to liquibase-integration-tests/docker/postgres-init.sh diff --git a/liquibase-integration-tests/src/test/resources/changelogs/pgsql/complete/root.changelog.xml b/liquibase-integration-tests/src/test/resources/changelogs/pgsql/complete/root.changelog.xml index c5a140f64d6..2d0314ba986 100644 --- a/liquibase-integration-tests/src/test/resources/changelogs/pgsql/complete/root.changelog.xml +++ b/liquibase-integration-tests/src/test/resources/changelogs/pgsql/complete/root.changelog.xml @@ -15,7 +15,7 @@ You can add comments to changeSets. They can even be multiple lines if you would like. They aren't used to compute the changeSet MD5Sum, so you can update them whenever you want without causing problems. - </comment> + </comment> <createTable tableName="person"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> @@ -287,7 +287,7 @@ <changeSet id="50" author="nvoxland"> <modifyDataType tableName="address" columnName="postalcode" newDataType="varchar(20)"/> - </changeSet> + </changeSet> <include file="changelogs/pgsql/complete/included.changelog.xml"/> @@ -309,7 +309,7 @@ </changeSet> <changeSet id="58" author="nvoxland"> <customChange class="liquibase.change.custom.ExampleCustomTaskChange" helloTo="world"/> - </changeSet> + </changeSet> <changeSet id="60" author="nvoxland"> <executeCommand executable="getmac" os="Windows XP"> @@ -324,7 +324,7 @@ <column name="bigSerialColumn" type="bigserial"/> <column name="bitVarColumn" type="bit varying(10)"/> <column name="doubleColumn" type="double precision"/> - <column name="realColumn" type="real"/> + <column name="realColumn" type="real"/> </createTable> </changeSet> @@ -359,4 +359,56 @@ <comment>Auto increment the primary keys</comment> <addAutoIncrement tableName="cp1_table" columnName="id" columnDataType="int"/> </changeSet> -</databaseChangeLog> \ No newline at end of file + <!-- + Change sets to test https://github.com/liquibase/liquibase/issues/1212. + To test this, we'll need 3 things: + 0. Postgresql >= 10 + 1. A parent table to reference. + 2. A partitioned table with a foreign key to the parent table. + 3. A default partition in the table. + These tables don't need any data. We just need the structure to make sure we can + drop all the objects without having trouble with foreign keys. + --> + <changeSet id="issue-1212-parent" author="ssaliman"> + <preConditions onFail="CONTINUE"> + <sqlCheck expectedResult="t">select cast(current_setting('server_version_num') as integer) >= 100000</sqlCheck> + </preConditions> + <createTable tableName="partition_parent"> + <column name="id" type="bigint"> + <constraints primaryKey="true"/> + </column> + <column name="parent_data" type="varchar(50)"/> + </createTable> + </changeSet> + <changeSet id="issue-1212-child" author="ssaliman"> + <preConditions onFail="CONTINUE"> + <changeSetExecuted id="issue-1212-parent" author="ssaliman" changeLogFile="changelogs/pgsql/complete/root.changelog.xml"/> + </preConditions> + <createTable tableName="partitioned_child"> + <column name="partition_key" type="datetime"> + <constraints primaryKey="true"/> + </column> + <column name="parent_id" type="bigint"/> + <column name="some_data" type="varchar(2000)"/> + </createTable> + <modifySql> + <append value=" PARTITION BY RANGE (partition_key)"/> + </modifySql> + </changeSet> + <changeSet id="issue-1212-partition" author="ssaliman"> + <preConditions onFail="CONTINUE"> + <changeSetExecuted id="issue-1212-parent" author="ssaliman" changeLogFile="changelogs/pgsql/complete/root.changelog.xml"/> + </preConditions> + <sql>create table partitioned_childp partition of partitioned_child default;</sql> + </changeSet> + <changeSet id="issue-1212-constraint" author="ssaliman"> + <preConditions onFail="CONTINUE"> + <changeSetExecuted id="issue-1212-parent" author="ssaliman" changeLogFile="changelogs/pgsql/complete/root.changelog.xml"/> + </preConditions> + <addForeignKeyConstraint baseTableName="partitioned_child" + baseColumnNames="parent_id" + constraintName="fk_child_parent" + referencedTableName="partition_parent" + referencedColumnNames="id"/> + </changeSet> +</databaseChangeLog> diff --git a/liquibase-integration-tests/src/test/resources/liquibase/liquibase.integrationtest.circleci.properties b/liquibase-integration-tests/src/test/resources/liquibase/liquibase.integrationtest.circleci.properties deleted file mode 100644 index fd463637aae..00000000000 --- a/liquibase-integration-tests/src/test/resources/liquibase/liquibase.integrationtest.circleci.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Circle CI-specific defaults for the integration tests. -integration.test.mysql.url=jdbc:mysql://localhost:3306/lbcat?useSSL=false diff --git a/liquibase-maven-plugin/pom.xml b/liquibase-maven-plugin/pom.xml index 5c1faf27296..6930e4cb24b 100644 --- a/liquibase-maven-plugin/pom.xml +++ b/liquibase-maven-plugin/pom.xml @@ -1,243 +1,259 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.liquibase</groupId> - <artifactId>liquibase-base-module</artifactId> - <version>${liquibase.version}</version> - <relativePath>../base-module.pom.xml</relativePath> - </parent> - - <artifactId>liquibase-maven-plugin</artifactId> - <packaging>maven-plugin</packaging> - <description>A Maven plugin wraps up some of the functionality of Liquibase</description> - - <properties> - <targetMavenVersion>3.3.9</targetMavenVersion> - </properties> - <dependencies> - <dependency> - <groupId>javax.xml.bind</groupId> - <artifactId>jaxb-api</artifactId> - <version>2.3.0</version> - </dependency> - <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-plugin-api</artifactId> - <version>${targetMavenVersion}</version> - </dependency> - - <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-core</artifactId> - <version>${targetMavenVersion}</version> - </dependency> - - <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-artifact</artifactId> - <version>${targetMavenVersion}</version> - </dependency> - - <dependency> - <groupId>org.apache.maven</groupId> - <artifactId>maven-compat</artifactId> - <version>${targetMavenVersion}</version> - </dependency> - - - <dependency> - <groupId>org.apache.maven.plugin-testing</groupId> - <artifactId>maven-plugin-testing-harness</artifactId> - <version>3.3.0</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.apache.maven.shared</groupId> - <artifactId>maven-verifier</artifactId> - <version>1.6</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <configuration> - <author>false</author> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.liquibase</groupId> + <artifactId>liquibase-base-module</artifactId> + <version>${liquibase.version}</version> + <relativePath>../base-module.pom.xml</relativePath> + </parent> + + <artifactId>liquibase-maven-plugin</artifactId> + <packaging>maven-plugin</packaging> + <description>A Maven plugin wraps up some of the functionality of Liquibase</description> + + <properties> + <targetMavenVersion>3.3.9</targetMavenVersion> + </properties> + <dependencies> + <dependency> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + <version>2.3.0</version> + </dependency> + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-plugin-api</artifactId> + <version>${targetMavenVersion}</version> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-core</artifactId> + <version>${targetMavenVersion}</version> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-artifact</artifactId> + <version>${targetMavenVersion}</version> + </dependency> + + <dependency> + <groupId>org.apache.maven</groupId> + <artifactId>maven-compat</artifactId> + <version>${targetMavenVersion}</version> + </dependency> + + + <dependency> + <groupId>org.apache.maven.plugin-testing</groupId> + <artifactId>maven-plugin-testing-harness</artifactId> + <version>3.3.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.maven.shared</groupId> + <artifactId>maven-verifier</artifactId> + <version>1.6</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <author>false</author> <doctitle>Liquibase Maven Plugin ${project.version} API</doctitle> - <quiet>true</quiet> - <doclint>none</doclint> - <encoding>UTF-8</encoding> - <jarOutputDirectory>${project.basedir}/target</jarOutputDirectory> - </configuration> - <executions> - <execution> - <id>jar-javadoc</id> - <goals> - <goal>jar</goal> - </goals> - <phase>package</phase> - </execution> - </executions> - </plugin> - - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-plugin-plugin</artifactId> - <version>3.6.0</version> - <executions> - <execution> - <id>generated-helpmojo</id> - <goals> - <goal>helpmojo</goal> - </goals> - </execution> - </executions> - <configuration> - <mojoDependencies> - <param>org.liquibase:liquibase-maven-plugin</param> - </mojoDependencies> - </configuration> - </plugin> - - <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>flatten-maven-plugin</artifactId> - <version>1.1.0</version> - <configuration> - <updatePomFile>true</updatePomFile> - <outputDirectory>${project.build.directory}/flattened-pom</outputDirectory> + <quiet>true</quiet> + <doclint>none</doclint> + <encoding>UTF-8</encoding> + <jarOutputDirectory>${project.basedir}/target</jarOutputDirectory> + </configuration> + <executions> + <execution> + <id>jar-javadoc</id> + <goals> + <goal>jar</goal> + </goals> + <phase>package</phase> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>3.6.0</version> + <executions> + <execution> + <id>generated-helpmojo</id> + <goals> + <goal>helpmojo</goal> + </goals> + </execution> + </executions> + <configuration> + <mojoDependencies> + <param>org.liquibase:liquibase-maven-plugin</param> + </mojoDependencies> + </configuration> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>flatten-maven-plugin</artifactId> + <version>1.1.0</version> + <configuration> + <updatePomFile>true</updatePomFile> + <outputDirectory>${project.build.directory}/flattened-pom</outputDirectory> <flattenedPomFilename>release.pom.xml</flattenedPomFilename> - <pomElements> + <pomElements> <profiles>remove</profiles> - <organization/> - <issueManagement/> - </pomElements> - <flattenMode>ossrh</flattenMode> - </configuration> - <executions> - <execution> - <id>flatten</id> - <phase>process-resources</phase> - <goals> - <goal>flatten</goal> - </goals> - </execution> - <execution> - <id>flatten.clean</id> - <phase>clean</phase> - <goals> - <goal>clean</goal> - </goals> - </execution> - </executions> - </plugin> - - <plugin> - <!-- Converts the generated flattened-pom into a cleaner version for maven distribution --> - <groupId>org.codehaus.mojo</groupId> - <artifactId>xml-maven-plugin</artifactId> - <version>1.0.2</version> - <executions> - <execution> - <id>transform-deploy-pom</id> - <phase>process-resources</phase> - <goals> - <goal>transform</goal> - </goals> - </execution> - </executions> - <configuration> - <forceCreation>true</forceCreation> - <transformationSets> - <transformationSet> - <dir>${project.build.directory}/flattened-pom</dir> + <organization/> + <issueManagement/> + </pomElements> + <flattenMode>ossrh</flattenMode> + </configuration> + <executions> + <execution> + <id>flatten</id> + <phase>process-resources</phase> + <goals> + <goal>flatten</goal> + </goals> + </execution> + <execution> + <id>flatten.clean</id> + <phase>clean</phase> + <goals> + <goal>clean</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <!-- Converts the generated flattened-pom into a cleaner version for maven distribution --> + <groupId>org.codehaus.mojo</groupId> + <artifactId>xml-maven-plugin</artifactId> + <version>1.0.2</version> + <executions> + <execution> + <id>transform-deploy-pom</id> + <phase>process-resources</phase> + <goals> + <goal>transform</goal> + </goals> + </execution> + </executions> + <configuration> + <forceCreation>true</forceCreation> + <transformationSets> + <transformationSet> + <dir>${project.build.directory}/flattened-pom</dir> <includes>release.pom.xml</includes> <outputDir>${project.build.directory}</outputDir> - <stylesheet>${project.basedir}/src/main/maven/liquibase-deployment-pom.xslt</stylesheet> - </transformationSet> - </transformationSets> - </configuration> - </plugin> - - <plugin> - <artifactId>maven-install-plugin</artifactId> - <configuration> - <artifactId>${project.artifactId}</artifactId> - <file>${project.build.directory}/${project.artifactId}-${version}.jar</file> + <stylesheet>${project.basedir}/src/main/maven/liquibase-deployment-pom.xslt</stylesheet> + </transformationSet> + </transformationSets> + </configuration> + </plugin> + + <plugin> + <artifactId>maven-install-plugin</artifactId> + <configuration> + <artifactId>${project.artifactId}</artifactId> + <file>${project.build.directory}/${project.artifactId}-${version}.jar</file> <sources>${project.build.directory}/${project.artifactId}-${version}-sources.jar</sources> <javadoc>${project.build.directory}/${project.artifactId}-${version}-javadoc.jar</javadoc> - <pomFile>${project.build.directory}/release.pom.xml</pomFile> - </configuration> - <executions> - <execution> - <id>custom-install</id> - <phase>install</phase> - <goals> - <goal>install-file</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <artifactId>maven-gpg-plugin</artifactId> - <version>1.6</version> - <configuration> - <passphrase>${env.GPG_PASSPHRASE}</passphrase> - <gpgArguments> - <arg>--batch</arg> - <arg>--no-tty</arg> - <!-- This is necessary for gpg to not try to use the pinentry programs --> - <arg>--pinentry-mode</arg> - <arg>loopback</arg> - </gpgArguments> - - <skip>false</skip> - <repositoryId>${deploy.repositoryId}</repositoryId> - <artifactId>${project.artifactId}</artifactId> - <version>${liquibase.version}</version> - <url>${deploy.url}</url> - <file>${project.build.directory}/${project.artifactId}-${liquibase.version}.jar</file> - <sources>${project.build.directory}/${project.artifactId}-${version}-sources.jar</sources> - <javadoc>${project.build.directory}/${project.artifactId}-${version}-javadoc.jar</javadoc> - <pomFile>${project.build.directory}/release.pom.xml</pomFile> - </configuration> - <executions> - <execution> - <id>custom-deploy</id> - <phase>deploy</phase> - <goals> - <goal>sign-and-deploy-file</goal> - </goals> - </execution> - </executions> - </plugin> - - <plugin> - <groupId>io.snyk</groupId> - <artifactId>snyk-maven-plugin</artifactId> - <configuration> - <skip>false</skip> - </configuration> - </plugin> - - </plugins> - - </build> - - <reporting> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-plugin-plugin</artifactId> - <version>2.6</version> - </plugin> - </plugins> - </reporting> + <pomFile>${project.build.directory}/release.pom.xml</pomFile> + </configuration> + <executions> + <execution> + <id>custom-install</id> + <phase>install</phase> + <goals> + <goal>install-file</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>io.snyk</groupId> + <artifactId>snyk-maven-plugin</artifactId> + <configuration> + <skip>false</skip> + </configuration> + </plugin> + + </plugins> + + </build> + + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-plugin-plugin</artifactId> + <version>2.6</version> + </plugin> + </plugins> + </reporting> + + <profiles> + <profile> + <id>gpg-sign</id> + <activation> + <property> + <name>env.GPG_PASSPHRASE</name> + </property> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <configuration> + <passphrase>${env.GPG_PASSPHRASE}</passphrase> + <gpgArguments> + <arg>--batch</arg> + <arg>--no-tty</arg> + <!-- This is necessary for gpg to not try to use the pinentry programs --> + <arg>--pinentry-mode</arg> + <arg>loopback</arg> + </gpgArguments> + + <skip>false</skip> + <repositoryId>${deploy.repositoryId}</repositoryId> + <artifactId>${project.artifactId}</artifactId> + <version>${liquibase.version}</version> + <url>${deploy.url}</url> + <file>${project.build.directory}/${project.artifactId}-${liquibase.version}.jar</file> + <sources>${project.build.directory}/${project.artifactId}-${version}-sources.jar</sources> + <javadoc>${project.build.directory}/${project.artifactId}-${version}-javadoc.jar</javadoc> + <pomFile>${project.build.directory}/release.pom.xml</pomFile> + </configuration> + <executions> + <execution> + <id>custom-deploy</id> + <phase>deploy</phase> + <goals> + <goal>sign-and-deploy-file</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncMojo.java index c967b051a12..7fa1a86913b 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncMojo.java @@ -8,15 +8,15 @@ /** * <p>Marks all unapplied changes to the database as applied in the change log.</p> * - * @author JAmes Atwill - * @goal changelogSync + * @author James Atwill + * @goal changelogSync */ public class LiquibaseChangeLogSyncMojo extends AbstractLiquibaseChangeLogMojo { - @Override - protected void performLiquibaseTask(Liquibase liquibase) + @Override + protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { - super.performLiquibaseTask(liquibase); + super.performLiquibaseTask(liquibase); liquibase.changeLogSync(new Contexts(contexts), new LabelExpression(labels)); - } + } } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncSQLMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncSQLMojo.java index 06fa01c6a21..ae1cb8832fd 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncSQLMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncSQLMojo.java @@ -5,7 +5,6 @@ import liquibase.Liquibase; import liquibase.database.Database; import liquibase.exception.LiquibaseException; -import liquibase.resource.ResourceAccessor; import org.apache.maven.plugin.MojoExecutionException; import java.io.File; @@ -31,13 +30,19 @@ public class LiquibaseChangeLogSyncSQLMojo extends */ protected File migrationSqlOutputFile; + /** + * Update to the changeSet with the given tag command. + * @parameter property="liquibase.toTag" + */ + protected String toTag; + /** The writer for writing the migration SQL. */ private Writer outputWriter; @Override protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { - liquibase.changeLogSync(new Contexts(contexts), new LabelExpression(labels), outputWriter); + liquibase.changeLogSync(toTag, new Contexts(contexts), new LabelExpression(labels), outputWriter); } @Override diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagMojo.java new file mode 100644 index 00000000000..c30172d7dfb --- /dev/null +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagMojo.java @@ -0,0 +1,38 @@ +package org.liquibase.maven.plugins; + +import liquibase.Contexts; +import liquibase.LabelExpression; +import liquibase.Liquibase; +import liquibase.exception.LiquibaseException; +import org.apache.maven.plugin.MojoFailureException; + +/** + * + * <p>Marks all unapplied changes up to and include a specified tag to the database as applied in the change log.</p> + * + * @author James Atwill + * @goal changelogSyncToTag + * + */ +public class LiquibaseChangeLogSyncToTagMojo extends AbstractLiquibaseChangeLogMojo { + + /** + * Update to the changeSet with the given tag command. + * @parameter property="liquibase.toTag" + */ + protected String toTag; + + @Override + protected void checkRequiredParametersAreSpecified() throws MojoFailureException { + if (toTag == null || toTag.isEmpty()) { + throw new MojoFailureException("\nYou must specify a changelog tag."); + } + } + + @Override + protected void performLiquibaseTask(Liquibase liquibase) + throws LiquibaseException { + super.performLiquibaseTask(liquibase); + liquibase.changeLogSync(toTag, new Contexts(contexts), new LabelExpression(labels)); + } +} diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagSQLMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagSQLMojo.java new file mode 100644 index 00000000000..c1400b999a9 --- /dev/null +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseChangeLogSyncToTagSQLMojo.java @@ -0,0 +1,116 @@ +package org.liquibase.maven.plugins; + +import liquibase.Contexts; +import liquibase.LabelExpression; +import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.exception.LiquibaseException; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; + +/** + * + * <p>Generates SQL that marks all unapplied changes up to and including a specified tag + * as applied.</p> + * + * @author James Atwill + * @goal changelogSyncToTagSQL + * + */ +public class LiquibaseChangeLogSyncToTagSQLMojo extends + AbstractLiquibaseChangeLogMojo { + + /** + * The file to output the Migration SQL script to, if it exists it will be + * overwritten. + * + * @parameter property="liquibase.migrationSqlOutputFile" + * default-value= + * "${project.build.directory}/liquibase/migrate.sql" + */ + protected File migrationSqlOutputFile; + + /** + * Update to the changeSet with the given tag command. + * @parameter property="liquibase.toTag" + */ + protected String toTag; + + /** The writer for writing the migration SQL. */ + private Writer outputWriter; + + @Override + protected void checkRequiredParametersAreSpecified() throws MojoFailureException { + if (toTag == null || toTag.isEmpty()) { + throw new MojoFailureException("\nYou must specify a changelog tag."); + } + } + + @Override + protected void performLiquibaseTask(Liquibase liquibase) + throws LiquibaseException { + liquibase.changeLogSync(toTag, new Contexts(contexts), new LabelExpression(labels), outputWriter); + } + + @Override + protected void printSettings(String indent) { + super.printSettings(indent); + getLog().info( + indent + "migrationSQLOutputFile: " + migrationSqlOutputFile); + + } + + @Override + protected boolean isPromptOnNonLocalDatabase() { + // Always run on an non-local database as we are not actually modifying + // the database + // when run on it. + return false; + } + + @Override + protected Liquibase createLiquibase(Database db) + throws MojoExecutionException { + Liquibase liquibase = super.createLiquibase(db); + + // Setup the output file writer + try { + if (!migrationSqlOutputFile.exists()) { + // Ensure the parent directories exist + migrationSqlOutputFile.getParentFile().mkdirs(); + // Create the actual file + if (!migrationSqlOutputFile.createNewFile()) { + throw new MojoExecutionException( + "Cannot create the migration SQL file; " + + migrationSqlOutputFile.getAbsolutePath()); + } + } + outputWriter = getOutputWriter(migrationSqlOutputFile);; + } catch (IOException e) { + getLog().error(e); + throw new MojoExecutionException( + "Failed to create SQL output writer", e); + } + getLog().info( + "Output SQL Migration File: " + + migrationSqlOutputFile.getAbsolutePath()); + return liquibase; + } + + @Override + protected void cleanup(Database db) { + super.cleanup(db); + if (outputWriter != null) { + try { + outputWriter.close(); + } catch (IOException e) { + getLog().error(e); + } + } + } + +} diff --git a/liquibase-maven-plugin/src/test/java/org/liquibase/maven/plugins/LiquibaseChangelogSyncToTagMojoTest.java b/liquibase-maven-plugin/src/test/java/org/liquibase/maven/plugins/LiquibaseChangelogSyncToTagMojoTest.java new file mode 100644 index 00000000000..d57e7aa979a --- /dev/null +++ b/liquibase-maven-plugin/src/test/java/org/liquibase/maven/plugins/LiquibaseChangelogSyncToTagMojoTest.java @@ -0,0 +1,68 @@ +package org.liquibase.maven.plugins; + +import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.configuration.PlexusConfiguration; + +import java.util.HashMap; +import java.util.Map; + +/** + * Some basic tests that validate the setting of properties for the + * ChangelogSyncToTag mojo. + * + * @author Ferenc Gratzer + * @since 2.0.2 + */ +public class LiquibaseChangelogSyncToTagMojoTest extends AbstractLiquibaseMojoTest { + + private static final String CONFIG_FILE = "dropAll/plugin_config.xml"; + + private static final Map<String, Object> DEFAULT_PROPERTIES; + + private static final Map<String, Object> SCHEMAS_DEFAULT_PROPERTIES; + + static { + DEFAULT_PROPERTIES = new HashMap<String, Object>(); + DEFAULT_PROPERTIES.put("driver", "com.mysql.cj.jdbc.Driver"); + DEFAULT_PROPERTIES.put("url", "jdbc:mysql://localhost/eformat"); + DEFAULT_PROPERTIES.put("username", "root"); + DEFAULT_PROPERTIES.put("password", null); + DEFAULT_PROPERTIES.put("verbose", true); + + SCHEMAS_DEFAULT_PROPERTIES = new HashMap<String, Object>(); + SCHEMAS_DEFAULT_PROPERTIES.putAll(DEFAULT_PROPERTIES); + SCHEMAS_DEFAULT_PROPERTIES.put("schemas", "1,2,3"); + } + + public void testTag() throws Exception { + LiquibaseChangeLogSyncToTagMojo mojo = createChangelogSyncToTagMojo(); + // Clear out any settings for the property file that may be set + setVariableValueToObject(mojo, "toTag", "25-Feb-2021"); + + Map values = getVariablesAndValuesFromObject(mojo); + checkValues(DEFAULT_PROPERTIES, values); + } + + public void testNoTag() throws Exception { + LiquibaseChangeLogSyncToTagMojo mojo = createChangelogSyncToTagMojo(); + // Clear out any settings for the property file that may be set + try { + mojo.checkRequiredParametersAreSpecified(); + fail("There should be no 'toTag' property value"); + } + catch (MojoFailureException mfe) { + // Consume for success + } + } + + /*-------------------------------------------------------------------------*\ + * PRIVATE METHODS + \*-------------------------------------------------------------------------*/ + + private LiquibaseChangeLogSyncToTagMojo createChangelogSyncToTagMojo() throws Exception { + LiquibaseChangeLogSyncToTagMojo mojo = new LiquibaseChangeLogSyncToTagMojo(); + PlexusConfiguration config = loadConfiguration(CONFIG_FILE); + configureMojo(mojo, config); + return mojo; + } +} diff --git a/pom.xml b/pom.xml index d9ca96f9861..06f7a24ed6c 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,11 @@ <module>liquibase-extension-examples</module> </modules> + <ciManagement> + <system>Travis</system> + <url>https://travis-ci.com/github/liquibase/liquibase</url> + </ciManagement> + <build> <plugins> <plugin> From 4bb3d9e4ff531bc05b19e84c4a99128f017d8e4f Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Fri, 19 Mar 2021 11:59:54 -0500 Subject: [PATCH 10/17] Cleaning up liquibase.configuration refactoring, adding javadoc, adding tests LB-1222 --- .../java/liquibase/GlobalConfiguration.java | 4 +- .../AbstractConfigurationValueProvider.java | 7 + ...der.java => AutoloadedConfigurations.java} | 4 +- .../ConfigurationDefinition.java | 169 ++++++++++++++---- .../ConfigurationValueConverter.java | 17 ++ .../ConfigurationValueHandler.java | 6 - .../ConfigurationValueObfuscator.java | 6 + .../ConfigurationValueProvider.java | 2 +- .../configuration/ConfiguredValue.java | 82 +++++++++ .../liquibase/configuration/CurrentValue.java | 53 ------ .../configuration/CurrentValueDetails.java | 34 ---- .../CurrentValueSourceDetails.java | 32 ---- .../configuration/LiquibaseConfiguration.java | 18 +- .../configuration/ProvidedValue.java | 61 +++++++ .../core/ScopeValueProvider.java | 10 +- .../core/SystemPropertyValueProvider.java | 11 +- .../database/AbstractJdbcDatabase.java | 12 +- .../java/liquibase/hub/HubConfiguration.java | 4 +- .../main/java/liquibase/hub/HubUpdater.java | 8 +- .../servlet/LiquibaseServletListener.java | 84 +++------ .../ServletConfigurationValueProvider.java | 61 +++++++ .../integration/spring/SpringLiquibase.java | 14 +- .../core/DefaultLoggerConfiguration.java | 4 +- .../parser/ChangeLogParserConfiguration.java | 4 +- .../java/liquibase/ui/ConsoleUIService.java | 7 +- ...se.configuration.AutoloadedConfigurations} | 0 .../ConfigurationDefinitionTest.groovy | 85 +++++++-- .../configuration/ConfiguredValueTest.groovy | 51 ++++++ .../LiquibaseConfigurationTest.groovy | 45 ++++- .../configuration/ProvidedValueTest.groovy | 12 ++ .../core/ScopeValueProviderTest.groovy | 8 +- .../SystemPropertyValueProviderTest.groovy | 2 +- .../servlet/LiquibaseServletListenerTest.java | 3 + 33 files changed, 614 insertions(+), 306 deletions(-) create mode 100644 liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationValueProvider.java rename liquibase-core/src/main/java/liquibase/configuration/{ConfigurationDefinitionHolder.java => AutoloadedConfigurations.java} (62%) create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueConverter.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ProvidedValue.java create mode 100644 liquibase-core/src/main/java/liquibase/integration/servlet/ServletConfigurationValueProvider.java rename liquibase-core/src/main/resources/META-INF/services/{liquibase.configuration.ConfigurationDefinitionHolder => liquibase.configuration.AutoloadedConfigurations} (100%) create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/ConfiguredValueTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/ProvidedValueTest.groovy diff --git a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java index bd6cba71ff1..422cff325a2 100644 --- a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java @@ -1,12 +1,12 @@ package liquibase; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.ConfigurationDefinitionHolder; +import liquibase.configuration.AutoloadedConfigurations; /** * Configuration container for global properties. */ -public class GlobalConfiguration implements ConfigurationDefinitionHolder { +public class GlobalConfiguration implements AutoloadedConfigurations { public static final ConfigurationDefinition<Boolean> SHOULD_RUN; public static final ConfigurationDefinition<String> DATABASECHANGELOG_TABLE_NAME; diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationValueProvider.java new file mode 100644 index 00000000000..1fd7cb7f48c --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationValueProvider.java @@ -0,0 +1,7 @@ +package liquibase.configuration; + +/** + * Convenience base class for {@link ConfigurationValueProvider} implementations + */ +public abstract class AbstractConfigurationValueProvider implements ConfigurationValueProvider { +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java b/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java similarity index 62% rename from liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java rename to liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java index d6805fba754..223ea9b783f 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinitionHolder.java +++ b/liquibase-core/src/main/java/liquibase/configuration/AutoloadedConfigurations.java @@ -2,8 +2,8 @@ /** * Marker interface for a class containing {@link ConfigurationDefinition} which should be auto-loaded at Liquibase startup. - * All classes that implement this interface must still be registered in the META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder file. + * All classes that implement this interface must still be registered in the META-INF/services/liquibase.configuration.AutoloadedConfigurations file. */ -public interface ConfigurationDefinitionHolder { +public interface AutoloadedConfigurations { } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java index f64f6d28771..44dc0171238 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java @@ -3,43 +3,78 @@ import liquibase.Scope; import liquibase.util.ObjectUtil; -import java.util.*; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; /** - * A higher-level definition of a configuration. - * Provides type-safety, metadata, default values, etc. vs. what is available in the lower-level {@link LiquibaseConfiguration}. + * A higher-level/detailed definition to provide type-safety, metadata, default values, etc.. + * Any code that is working with configurations should be using an instance of this class, rather than the lower-level, generic {@link LiquibaseConfiguration} + * <p> * ConfigurationDefinitions that are registered with {@link LiquibaseConfiguration#registerDefinition(ConfigurationDefinition)} will * be available in generated help etc. * <p> * These objects are immutable, so to construct definitions, use {@link Builder} + * <p> + * The definition keys should be dot-separated, camelCased names, using a unique "namespace" as part of it. + * For example: <pre>yourCorp.yourProperty</pre> or <pre>yourCorp.sub.otherProperty</pre>. + * Liquibase uses "liquibase" as the base namespace like <pre>liquibase.shouldRun</pre> * */ -public class ConfigurationDefinition<DataType> implements Comparable { +public class ConfigurationDefinition<DataType> implements Comparable<ConfigurationDefinition<DataType>> { - private String key; - private Set<String> aliasKeys = new TreeSet<>(); - private Class<DataType> type; + private final String key; + private final Set<String> aliasKeys = new TreeSet<>(); + private final Class<DataType> type; private String description; private DataType defaultValue; private boolean commonlyUsed; - private ConfigurationValueHandler<DataType> valueHandler; + private ConfigurationValueConverter<DataType> valueHandler; private ConfigurationValueObfuscator<DataType> valueObfuscator; + private static final Pattern ALLOWED_KEY_PATTERN = Pattern.compile("[a-zA-Z0-9.]+"); + + /** + * @return if the given {@link ConfiguredValue} was set by a default value + */ + public static boolean wasDefaultValueUsed(ConfiguredValue<?> configuredValue) { + for (ProvidedValue providedValue : configuredValue.getProvidedValues()) { + if (providedValue.getProvider() != null && providedValue.getProvider() instanceof ConfigurationDefinition.DefaultValueProvider) { + return true; + } + } + + return false; + } + + /** + * Constructor private to force {@link Builder} usage + */ private ConfigurationDefinition(String key, Class<DataType> type) { + if (!ALLOWED_KEY_PATTERN.matcher(key).matches()) { + throw new IllegalArgumentException("Invalid key format: "+key); + } + this.key = key; this.type = type; this.valueHandler = value -> ObjectUtil.convert(value, type); } /** - * Convenience method around {@link #getCurrentValueDetails()} to return the value. + * Convenience method around {@link #getCurrentConfiguredValue()} to return the value. */ public DataType getCurrentValue() { - return getCurrentValueDetails().getValue(); + final Object value = getCurrentConfiguredValue().getProvidedValue().getValue(); + try { + return (DataType) value; + } catch (ClassCastException e) { + throw new IllegalArgumentException("The current value of "+key+" not the expected type: "+ e.getMessage(), e); + } } /** - * Convenience method around {@link #getCurrentValueDetails()} to return the obfuscated version of the value. + * Convenience method around {@link #getCurrentConfiguredValue()} to return the obfuscated version of the value. * @return the obfuscated value, or the plain-text value if no obfuscator is defined for this definition. */ public DataType getCurrentValueObfuscated() { @@ -54,52 +89,51 @@ public DataType getCurrentValueObfuscated() { /** * @return Full details on the current value for this definition. + * Will always return a {@link ConfiguredValue}, */ - public CurrentValue<DataType> getCurrentValueDetails() { + public ConfiguredValue<DataType> getCurrentConfiguredValue() { final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); - CurrentValueDetails configurationValue = liquibaseConfiguration.getCurrentValue(this.getKey()); + ConfiguredValue configurationValue = liquibaseConfiguration.getCurrentConfiguredValue(this.getKey()); + ConfiguredValue initialConfigurationValue = configurationValue; + for (String alias : this.aliasKeys) { - if (configurationValue != null) { + if (configurationValue.found()) { break; } - configurationValue = liquibaseConfiguration.getCurrentValue(alias); + configurationValue = liquibaseConfiguration.getCurrentConfiguredValue(alias); } - DataType finalValue = null; - List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); - if (configurationValue != null) { - sourceHistory.addAll(configurationValue.getSourceHistory()); - - finalValue = valueHandler.convert(configurationValue.getValue()); + if (!configurationValue.found()) { + //set back to initial version, not the alias + configurationValue = initialConfigurationValue; } - - boolean defaultValueUsed = false; - if (finalValue == null) { - finalValue = this.getDefaultValue(); - - if (finalValue == null) { - sourceHistory.add(0, new CurrentValueSourceDetails(this.getDefaultValue(), "No configuration or default value found for", key)); - defaultValueUsed = false; - } else { - sourceHistory.add(0, new CurrentValueSourceDetails(this.getDefaultValue(), "Default value for", key)); - defaultValueUsed = true; + if (!configurationValue.found()) { + defaultValue = this.getDefaultValue(); + if (defaultValue != null) { + configurationValue.override(new DefaultValueProvider(this.getDefaultValue()).getProvidedValue(key)); } } - return new CurrentValue<>(finalValue, sourceHistory, defaultValueUsed); + final Object providedValue = configurationValue.getProvidedValue().getValue(); + final DataType finalValue = valueHandler.convert(providedValue); + if (providedValue != finalValue) { + configurationValue.override(new ConvertedValueProvider<DataType>(finalValue).getProvidedValue(key)); + } + + return (ConfiguredValue<DataType>) configurationValue; } /** - * The standard configuration key for this definition. + * The standard configuration key for this definition. See the {@link ConfigurationDefinition} class-level docs on key format. */ public String getKey() { return key; } /** - * @return alternate configuration keys to check for values. + * @return alternate configuration keys to check for values. Used for backwards compatibility. */ public Set<String> getAliasKeys() { return aliasKeys; @@ -114,13 +148,17 @@ public Class<DataType> getType() { /** * A user-friendly description of this definition. + * This will be exposed to end-users in generated help. */ public String getDescription() { return description; } /** - * The default value used by this definition of no value is currently configured. + * The default value used by this definition if no value is currently configured. + * <p> + * NOTE: this is only used if none of the {@link ConfigurationValueProvider}s have a configuration for the property. + * Even if some return "null", that is still considered a provided value to use rather than this default. */ public DataType getDefaultValue() { return defaultValue; @@ -135,8 +173,8 @@ public boolean getCommonlyUsed() { } @Override - public int compareTo(Object o) { - return this.getKey().compareTo(((ConfigurationDefinition) o).getKey()); + public int compareTo(ConfigurationDefinition o) { + return this.getKey().compareTo(o.getKey()); } @Override @@ -162,6 +200,10 @@ public static class Builder { * @param defaultKeyPrefix the prefix to add to new keys that are not fully qualified */ public Builder(String defaultKeyPrefix) { + if (!ALLOWED_KEY_PATTERN.matcher(defaultKeyPrefix).matches()) { + throw new IllegalArgumentException("Invalid prefix format: "+defaultKeyPrefix); + } + this.defaultKeyPrefix = defaultKeyPrefix; } @@ -183,6 +225,10 @@ private NewDefinition(ConfigurationDefinition<DataType> definition) { } public NewDefinition<DataType> addAliasKey(String alias) { + if (!ALLOWED_KEY_PATTERN.matcher(alias).matches()) { + throw new IllegalArgumentException("Invalid alias format: "+alias); + } + definition.aliasKeys.add(alias); return this; @@ -198,7 +244,7 @@ public NewDefinition<DataType> setDefaultValue(DataType defaultValue) { return this; } - public NewDefinition<DataType> setValueHandler(ConfigurationValueHandler<DataType> handler) { + public NewDefinition<DataType> setValueHandler(ConfigurationValueConverter<DataType> handler) { definition.valueHandler = handler; return this; @@ -235,4 +281,49 @@ public ConfigurationDefinition<DataType> buildTemporary() { } } } + + /** + * Used to track configuration values set by a default + */ + private static final class DefaultValueProvider implements ConfigurationValueProvider { + + private final Object value; + + public DefaultValueProvider(Object value) { + this.value = value; + } + + @Override + public int getPrecedence() { + return -1; + } + + @Override + public ProvidedValue getProvidedValue(String key) { + return new ProvidedValue(key, key, value, "Default value", this); + } + } + + /** + * Used to track configuration values converted by a handler + */ + private static final class ConvertedValueProvider<DataType> implements ConfigurationValueProvider { + + private final DataType value; + + public ConvertedValueProvider(DataType value) { + this.value = value; + } + + @Override + public int getPrecedence() { + return -1; + } + + @Override + public ProvidedValue getProvidedValue(String key) { + return new ProvidedValue(key, key, value, "Parsed/processed value", this); + } + } } + diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueConverter.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueConverter.java new file mode 100644 index 00000000000..c69c5244276 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueConverter.java @@ -0,0 +1,17 @@ +package liquibase.configuration; + +/** + * Used by {@link ConfigurationDefinition#getCurrentConfiguredValue()} to translate whatever object type a {@link ConfigurationValueProvider} is returning + * into the object type the definition uses. + */ +public interface ConfigurationValueConverter<DataType> { + + /** + * Converts an arbitrary object into the correct type. + * Implementations should be able to handle <b>any</b> type passed them, often types by calling toString() on the incoming value and parsing the string. + * Normally, a null value will be returned as a null value, but that is up to the implementation. + * + * @throws IllegalArgumentException if the value cannot be parsed or is an invalid value. + */ + DataType convert(Object value) throws IllegalArgumentException; +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java deleted file mode 100644 index 082c90f5604..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java +++ /dev/null @@ -1,6 +0,0 @@ -package liquibase.configuration; - -public interface ConfigurationValueHandler<DataType> { - - DataType convert(Object value) throws IllegalArgumentException; -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java index d7e1422a8eb..533fd531d44 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueObfuscator.java @@ -1,6 +1,12 @@ package liquibase.configuration; +/** + * Used by {@link ConfigurationDefinition#getCurrentValueObfuscated()} to obfuscate the current value. + */ public interface ConfigurationValueObfuscator<DataType> { + /** + * Return an "obfuscated" version of the given value, suitable for logging or storing in non-secure environments. + */ DataType obfuscate(DataType value); } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java index 57321eebcf8..ffdc4765631 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java @@ -17,5 +17,5 @@ public interface ConfigurationValueProvider { * * @return null if the key is not defined in this provider. */ - CurrentValueSourceDetails getValue(String key); + ProvidedValue getProvidedValue(String key); } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java b/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java new file mode 100644 index 00000000000..e2aadc4ed25 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfiguredValue.java @@ -0,0 +1,82 @@ +package liquibase.configuration; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This wraps all the {@link ProvidedValue}s to return the overall value returned from the collection of {@link ConfigurationValueProvider}s. + * Returned by {@link LiquibaseConfiguration#getCurrentConfiguredValue(String)} + */ +public class ConfiguredValue<DataType> { + + private static final NoValueProvider NO_VALUE_PROVIDER = new NoValueProvider(); + + private final List<ProvidedValue> providedValues = new ArrayList<>(); + private final String key; + + protected ConfiguredValue(String key) { + this.key = key; + } + + public DataType getValue() { + final ProvidedValue providedValue = getProvidedValue(); + if (providedValue == null) { + return null; + } + + return (DataType) providedValue.getValue(); + } + + + /** + * Returns the "winning" value across all the possible {@link ConfigurationValueProvider}. + * A {@link ProvidedValue} is always returned, even if the value was not configured. + * + * @see #found() + */ + public ProvidedValue getProvidedValue() { + return getProvidedValues().get(0); + } + + + /** + * Replaces the current configured value with a higher-precedence one. + */ + protected void override(ProvidedValue details) { + this.providedValues.add(0, details); + } + + /** + * @return a full list of where the configuration value was set and/or overridden. + */ + public List<ProvidedValue> getProvidedValues() { + if (providedValues.size() == 0) { + return Collections.singletonList(NO_VALUE_PROVIDER.getProvidedValue(key)); + } + + return Collections.unmodifiableList(providedValues); + } + + /** + * @return true if a value was found across the providers. + */ + public boolean found() { + return providedValues.size() > 0; + } + + /** + * Used to track configuration with no value set + */ + private static final class NoValueProvider implements ConfigurationValueProvider { + @Override + public int getPrecedence() { + return -1; + } + + @Override + public ProvidedValue getProvidedValue(String key) { + return new ProvidedValue(key, key, null, "No configuration or default value found", this); + } + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java deleted file mode 100644 index 0b69fcf879a..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/CurrentValue.java +++ /dev/null @@ -1,53 +0,0 @@ -package liquibase.configuration; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Detailed, type-safe information about the current configuration value that can be provided by {@link ConfigurationDefinition}. - */ -public class CurrentValue<DataType> { - - private final DataType value; - private final List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); - private final boolean defaultValueUsed; - - public CurrentValue(DataType value, List<CurrentValueSourceDetails> sourceHistory, boolean defaultValueUsed) { - this.value = value; - this.sourceHistory.addAll(sourceHistory); - this.defaultValueUsed = defaultValueUsed; - } - - /** - * @return the current value. Can be null if not set and no default value. - */ - public DataType getValue() { - return value; - } - - /** - * @return true if the default value is being used rather than a configuration value - */ - public boolean getDefaultValueUsed() { - return defaultValueUsed; - } - - /** - * @return Returns where/how the value was set. - */ - public CurrentValueSourceDetails getSource() { - if (sourceHistory.size()== 0) { - return null; - } - return sourceHistory.get(0); - } - - /** - * @return a full list of how the value was set and overridden. - */ - public List<CurrentValueSourceDetails> getSourceHistory() { - return Collections.unmodifiableList(sourceHistory); - } - -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java deleted file mode 100644 index bd47dc0b4dd..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueDetails.java +++ /dev/null @@ -1,34 +0,0 @@ -package liquibase.configuration; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Detailed information about the current configuration value. - */ -public class CurrentValueDetails { - - private final List<CurrentValueSourceDetails> sourceHistory = new ArrayList<>(); - - public CurrentValueDetails() { - } - - public Object getValue() { - if (sourceHistory.size() == 0) { - return null; - } - return sourceHistory.get(0).getValue(); - } - - public void override(CurrentValueSourceDetails details) { - this.sourceHistory.add(0, details); - } - - /** - * @return a full list of how the value was set and overridden. - */ - public List<CurrentValueSourceDetails> getSourceHistory() { - return Collections.unmodifiableList(sourceHistory); - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java b/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java deleted file mode 100644 index 52a649a6c92..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/CurrentValueSourceDetails.java +++ /dev/null @@ -1,32 +0,0 @@ -package liquibase.configuration; - -/** - * Defines how a value was set. - */ -public class CurrentValueSourceDetails { - private final String key; - private final String source; - private final Object value; - - public CurrentValueSourceDetails(Object value, String source, String key) { - this.value = value; - this.key = key; - this.source = source; - } - - public Object getValue() { - return value; - } - - public String getKey() { - return key; - } - - public String getSource() { - return source; - } - - public String describe() { - return source + " '" + key + "'"; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index 745f7232a64..c02553bcf90 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -2,7 +2,6 @@ import liquibase.Scope; import liquibase.SingletonObject; -import liquibase.integration.servlet.LiquibaseServletListener; import liquibase.servicelocator.ServiceLocator; import java.util.*; @@ -42,8 +41,8 @@ protected LiquibaseConfiguration() { public void init(Scope scope) { configurationValueProviders.clear(); ServiceLocator serviceLocator = scope.getServiceLocator(); - final List<ConfigurationDefinitionHolder> containers = serviceLocator.findInstances(ConfigurationDefinitionHolder.class); - for (ConfigurationDefinitionHolder container : containers) { + final List<AutoloadedConfigurations> containers = serviceLocator.findInstances(AutoloadedConfigurations.class); + for (AutoloadedConfigurations container : containers) { Scope.getCurrentScope().getLog(getClass()).fine("Found ConfigurationDefinitions in " + container.getClass().getName()); } @@ -53,7 +52,7 @@ public void init(Scope scope) { /** * Adds a new {@link ConfigurationValueProvider} to the active collection of providers. */ - public void addProvider(ConfigurationValueProvider valueProvider) { + public void registerProvider(ConfigurationValueProvider valueProvider) { this.configurationValueProviders.add(valueProvider); } @@ -72,16 +71,13 @@ public boolean removeProvider(ConfigurationValueProvider provider) { * * @return the value for the key, or null if not configured. */ - public CurrentValueDetails getCurrentValue(String key) { - CurrentValueDetails details = null; + public ConfiguredValue getCurrentConfiguredValue(String key) { + ConfiguredValue details = new ConfiguredValue(key); + for (ConfigurationValueProvider provider : configurationValueProviders) { - final CurrentValueSourceDetails providerValue = provider.getValue(key); + final ProvidedValue providerValue = provider.getProvidedValue(key); if (providerValue != null) { - if (details == null) { - details = new CurrentValueDetails(); - } - details.override(providerValue); } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ProvidedValue.java b/liquibase-core/src/main/java/liquibase/configuration/ProvidedValue.java new file mode 100644 index 00000000000..35426dd8f2b --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ProvidedValue.java @@ -0,0 +1,61 @@ +package liquibase.configuration; + +/** + * Describes a value found from a provider. This is the most basic level at which a configuration value is defined. + */ +public class ProvidedValue { + private final String requestedKey; + private final String actualKey; + private final String sourceDescription; + private final ConfigurationValueProvider provider; + private final Object value; + + public ProvidedValue(String requestedKey, String actualKey, Object value, String sourceDescription, ConfigurationValueProvider provider) { + this.requestedKey = requestedKey; + this.actualKey = actualKey; + this.value = value; + this.sourceDescription = sourceDescription; + this.provider = provider; + } + + /** + * The value found by the provider. + */ + public Object getValue() { + return value; + } + + /** + * The configuration key the code asked the provider for. + * May be different than {@link #getActualKey()} if the provider does fuzzy matching such as case-insensitive lookups or . -> _ conversions etc. + */ + public String getRequestedKey() { + return requestedKey; + } + + /** + * The actual key/source for the value. + * This may be different than {@link #getRequestedKey()} if the provider does fuzzy matching such as case-insensitive lookups or . -> _ conversions etc. + */ + public String getActualKey() { + return actualKey; + } + + /** + * A description of where the value came from. + */ + public String getSourceDescription() { + return sourceDescription; + } + + /** + * The provider for this value + */ + public ConfigurationValueProvider getProvider() { + return provider; + } + + public String describe() { + return sourceDescription + " '" + actualKey + "'"; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java index e824730a506..2fbd31ae6a7 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java @@ -1,8 +1,8 @@ package liquibase.configuration.core; import liquibase.Scope; -import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.CurrentValueSourceDetails; +import liquibase.configuration.AbstractConfigurationValueProvider; +import liquibase.configuration.ProvidedValue; import java.util.Properties; @@ -10,7 +10,7 @@ * Searches the {@link liquibase.Scope} for the given key. * Does not perform any key smoothing/translating. */ -public class ScopeValueProvider implements ConfigurationValueProvider { +public class ScopeValueProvider extends AbstractConfigurationValueProvider { @Override public int getPrecedence() { @@ -18,7 +18,7 @@ public int getPrecedence() { } @Override - public CurrentValueSourceDetails getValue(String key) { + public ProvidedValue getProvidedValue(String key) { if (key == null) { return null; } @@ -28,7 +28,7 @@ public CurrentValueSourceDetails getValue(String key) { return null; } - return new CurrentValueSourceDetails(value, "Scoped value", key); + return new ProvidedValue(key, key, value, "Scoped value", this); } protected Properties getSystemProperties() { diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java index 7ab892f3cb6..fb5473592f1 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java @@ -1,7 +1,8 @@ package liquibase.configuration.core; +import liquibase.configuration.AbstractConfigurationValueProvider; import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.CurrentValueSourceDetails; +import liquibase.configuration.ProvidedValue; import liquibase.util.StringUtil; import java.util.Map; @@ -12,7 +13,7 @@ * <p> * To improve usability, it will search for the given key case insensitively. */ -public class SystemPropertyValueProvider implements ConfigurationValueProvider { +public class SystemPropertyValueProvider extends AbstractConfigurationValueProvider { @Override public int getPrecedence() { @@ -20,7 +21,7 @@ public int getPrecedence() { } @Override - public CurrentValueSourceDetails getValue(String key) { + public ProvidedValue getProvidedValue(String key) { if (key == null) { return null; } @@ -29,7 +30,7 @@ public CurrentValueSourceDetails getValue(String key) { String propValue = systemProperties.getProperty(key); if (StringUtil.isNotEmpty(propValue)) { - return new CurrentValueSourceDetails(propValue, "System property", key); + return new ProvidedValue(key, key, propValue, "System property", this); } // @@ -38,7 +39,7 @@ public CurrentValueSourceDetails getValue(String key) { for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) { String foundKey = (String) entry.getKey(); if (foundKey.equalsIgnoreCase(key)) { - return new CurrentValueSourceDetails(entry.getValue(),"System property", foundKey); + return new ProvidedValue(key, foundKey, entry.getValue(),"System property", this); } } return null; diff --git a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java index 5005eaebf43..0113dbb267b 100644 --- a/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java +++ b/liquibase-core/src/main/java/liquibase/database/AbstractJdbcDatabase.java @@ -10,6 +10,8 @@ import liquibase.changelog.RanChangeSet; import liquibase.changelog.StandardChangeLogHistoryService; import liquibase.GlobalConfiguration; +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.ConfiguredValue; import liquibase.database.core.OracleDatabase; import liquibase.database.core.PostgresDatabase; import liquibase.database.core.SQLiteDatabase; @@ -672,8 +674,9 @@ public String getLiquibaseCatalogName() { return liquibaseCatalogName; } - if (GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValueDetails() == null) { - return GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValue(); + final String configuredCatalogName = GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValue(); + if (configuredCatalogName != null) { + return configuredCatalogName; } return getDefaultCatalogName(); @@ -690,8 +693,9 @@ public String getLiquibaseSchemaName() { return liquibaseSchemaName; } - if (!GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValueDetails().getDefaultValueUsed()) { - return GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValue(); + final ConfiguredValue<String> configuredValue = GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentConfiguredValue(); + if (!ConfigurationDefinition.wasDefaultValueUsed(configuredValue)) { + return configuredValue.getValue(); } return getDefaultSchemaName(); diff --git a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java index 09eb0eb3785..24a471aff93 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubConfiguration.java @@ -2,7 +2,7 @@ import liquibase.Scope; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.ConfigurationDefinitionHolder; +import liquibase.configuration.AutoloadedConfigurations; import liquibase.util.StringUtil; import java.util.Arrays; @@ -12,7 +12,7 @@ /** * Configuration container for global properties. */ -public class HubConfiguration implements ConfigurationDefinitionHolder { +public class HubConfiguration implements AutoloadedConfigurations { public static final ConfigurationDefinition<String> LIQUIBASE_HUB_API_KEY; public static final ConfigurationDefinition<String> LIQUIBASE_HUB_URL; diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index 09e02ea298d..4f6169d27ac 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -11,8 +11,8 @@ import liquibase.command.CommandResult; import liquibase.command.core.RegisterChangeLogCommand; import liquibase.command.core.SyncHubCommand; -import liquibase.configuration.CurrentValue; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.ConfiguredValue; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.jvm.JdbcConnection; @@ -409,8 +409,8 @@ public void register(String changeLogFile) // If there is no liquibase.hub.mode setting then add one with value 'all' // Do not update liquibase.hub.mode if it is already set // - CurrentValue<String> hubModeProperty = HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentValueDetails(); - if (hubModeProperty.getDefaultValueUsed()) { + ConfiguredValue<String> hubModeProperty = HubConfiguration.LIQUIBASE_HUB_MODE.getCurrentConfiguredValue(); + if (ConfigurationDefinition.wasDefaultValueUsed(hubModeProperty)) { writeToPropertiesFile(defaultsFile, "\nliquibase.hub.mode=all\n"); message = "* Updated properties file " + defaultsFile + " to set liquibase.hub properties"; Scope.getCurrentScope().getUI().sendMessage(message); diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java index c93730ecaf6..31a61107330 100644 --- a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java @@ -1,9 +1,7 @@ package liquibase.integration.servlet; import liquibase.*; -import liquibase.configuration.ConfigurationValueProvider; -import liquibase.configuration.CurrentValueSourceDetails; -import liquibase.configuration.LiquibaseConfiguration; +import liquibase.configuration.*; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.database.core.DerbyDatabase; @@ -16,7 +14,6 @@ import liquibase.util.NetUtil; import liquibase.util.StringUtil; -import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletContext; @@ -36,7 +33,6 @@ */ public class LiquibaseServletListener implements ServletContextListener { - private static final String JAVA_COMP_ENV = "java:comp/env"; private static final String LIQUIBASE_CHANGELOG = "liquibase.changelog"; private static final String LIQUIBASE_CONTEXTS = "liquibase.contexts"; private static final String LIQUIBASE_LABELS = "liquibase.labels"; @@ -53,7 +49,6 @@ public class LiquibaseServletListener implements ServletContextListener { private String labels; private String defaultSchema; private String hostName; - private ServletValueContainer servletValueContainer; //temporarily saved separately until all lookup moves to liquibaseConfiguration public String getChangeLogFile() { return changeLogFile; @@ -108,14 +103,14 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { InitialContext ic = null; String failOnError = null; + final ServletConfigurationValueProvider servletConfigurationValueProvider = new ServletConfigurationValueProvider(servletContext, ic); try { ic = new InitialContext(); Scope.getCurrentScope().getUI().setAllowPrompt(false); - servletValueContainer = new ServletValueContainer(servletContext, ic); - liquibaseConfiguration.addProvider(servletValueContainer); + liquibaseConfiguration.registerProvider(servletConfigurationValueProvider); - failOnError = (String) servletValueContainer.getValue(LIQUIBASE_ONERROR_FAIL).getValue(); + failOnError = (String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_ONERROR_FAIL).getValue(); if (checkPreconditions(servletContext, ic)) { executeUpdate(servletContext, ic); } @@ -132,7 +127,7 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { // ignore } } - liquibaseConfiguration.removeProvider(servletValueContainer); + liquibaseConfiguration.removeProvider(servletConfigurationValueProvider); } @@ -154,8 +149,10 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext return false; } - String machineIncludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_INCLUDES).getValue(); - String machineExcludes = (String) servletValueContainer.getValue(LIQUIBASE_HOST_EXCLUDES).getValue(); + final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); + + String machineIncludes = (String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_HOST_INCLUDES).getValue(); + String machineExcludes = (String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_HOST_EXCLUDES).getValue(); boolean shouldRun = false; if ((machineIncludes == null) && (machineExcludes == null)) { @@ -177,10 +174,11 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext } } - if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && !GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getDefaultValueUsed()) { + final ConfiguredValue<Boolean> shouldRunValue = GlobalConfiguration.SHOULD_RUN.getCurrentConfiguredValue(); + if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && !ConfigurationDefinition.wasDefaultValueUsed(shouldRunValue)) { shouldRun = true; servletContext.log("ignoring " + LIQUIBASE_HOST_INCLUDES + " and " - + LIQUIBASE_HOST_EXCLUDES + ", since " + GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails().getSource() + + LIQUIBASE_HOST_EXCLUDES + ", since " + shouldRunValue.getProvidedValue().describe() + "=true"); } if (!shouldRun) { @@ -196,19 +194,21 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext */ @java.lang.SuppressWarnings("squid:S2095") private void executeUpdate(ServletContext servletContext, InitialContext ic) throws NamingException, SQLException, LiquibaseException { - setDataSource((String) servletValueContainer.getValue(LIQUIBASE_DATASOURCE).getValue()); + final LiquibaseConfiguration liquibaseConfiguration = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class); + + setDataSource((String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_DATASOURCE).getValue()); if (getDataSource() == null) { throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_DATASOURCE + " is not set"); } - setChangeLogFile((String) servletValueContainer.getValue(LIQUIBASE_CHANGELOG).getValue()); + setChangeLogFile((String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_CHANGELOG).getValue()); if (getChangeLogFile() == null) { throw new RuntimeException("Cannot run Liquibase, " + LIQUIBASE_CHANGELOG + " is not set"); } - setContexts((String) servletValueContainer.getValue(LIQUIBASE_CONTEXTS).getValue()); - setLabels((String) servletValueContainer.getValue(LIQUIBASE_LABELS).getValue()); - this.defaultSchema = StringUtil.trimToNull((String) servletValueContainer.getValue(LIQUIBASE_SCHEMA_DEFAULT).getValue()); + setContexts((String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_CONTEXTS).getValue()); + setLabels((String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_LABELS).getValue()); + this.defaultSchema = StringUtil.trimToNull((String) liquibaseConfiguration.getCurrentConfiguredValue(LIQUIBASE_SCHEMA_DEFAULT).getValue()); Connection connection = null; Database database = null; @@ -235,7 +235,7 @@ private void executeUpdate(ServletContext servletContext, InitialContext ic) thr while (initParameters.hasMoreElements()) { String name = initParameters.nextElement().trim(); if (name.startsWith(LIQUIBASE_PARAMETER + ".")) { - liquibase.setChangeLogParameter(name.substring(LIQUIBASE_PARAMETER.length() + 1), servletValueContainer.getValue(name)); + liquibase.setChangeLogParameter(name.substring(LIQUIBASE_PARAMETER.length() + 1), liquibaseConfiguration.getCurrentConfiguredValue(name)); } } @@ -256,48 +256,4 @@ private void executeUpdate(ServletContext servletContext, InitialContext ic) thr public void contextDestroyed(ServletContextEvent servletContextEvent) { } - protected class ServletValueContainer implements ConfigurationValueProvider { - - @Override - public int getPrecedence() { - return 30; - } - - private ServletContext servletContext; - private InitialContext initialContext; - - public ServletValueContainer(ServletContext servletContext, InitialContext initialContext) { - this.servletContext = servletContext; - this.initialContext = initialContext; - } - - /** - * Try to read the value that is stored by the given key from - * <ul> - * <li>JNDI</li> - * <li>the servlet context's init parameters</li> - * <li>system properties</li> - * </ul> - */ - @Override - public CurrentValueSourceDetails getValue(String key) { - // Try to get value from JNDI - try { - Context envCtx = (Context) initialContext.lookup(JAVA_COMP_ENV); - String valueFromJndi = (String) envCtx.lookup(key); - - return new CurrentValueSourceDetails(valueFromJndi, "JNDI", key); - } catch (NamingException e) { - // Ignore - } - - // Return the value from the servlet context - String valueFromServletContext = servletContext.getInitParameter(key); - if (valueFromServletContext != null) { - return new CurrentValueSourceDetails(valueFromServletContext, "Servlet context value", key); - } - - return new CurrentValueSourceDetails(System.getProperty(key), "System property", key); - } - } } diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/ServletConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/integration/servlet/ServletConfigurationValueProvider.java new file mode 100644 index 00000000000..926c00c3f34 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/ServletConfigurationValueProvider.java @@ -0,0 +1,61 @@ +package liquibase.integration.servlet; + +import liquibase.configuration.ConfigurationValueProvider; +import liquibase.configuration.ProvidedValue; +import org.springframework.util.StringUtils; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.servlet.ServletContext; + +public class ServletConfigurationValueProvider implements ConfigurationValueProvider { + + private static final String JAVA_COMP_ENV = "java:comp/env"; + + @Override + public int getPrecedence() { + return 30; + } + + private final ServletContext servletContext; + private final InitialContext initialContext; + + public ServletConfigurationValueProvider(ServletContext servletContext, InitialContext initialContext) { + this.servletContext = servletContext; + this.initialContext = initialContext; + } + + /** + * Try to read the value that is stored by the given key from + * <ul> + * <li>JNDI</li> + * <li>the servlet context's init parameters</li> + * <li>system properties</li> + * </ul> + */ + @Override + public ProvidedValue getProvidedValue(String key) { + if (initialContext != null) { + // Try to get value from JNDI + try { + Context envCtx = (Context) initialContext.lookup(JAVA_COMP_ENV); + String valueFromJndi = (String) envCtx.lookup(key); + + return new ProvidedValue(key, JAVA_COMP_ENV + "/" + key, valueFromJndi, "JNDI", this); + } catch (NamingException e) { + // Ignore + } + } + + if (servletContext != null) { + // Return the value from the servlet context + String valueFromServletContext = servletContext.getInitParameter(key); + if (valueFromServletContext != null) { + return new ProvidedValue(key, key, valueFromServletContext, "Servlet context", this); + } + } + + return null; + } +} diff --git a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java index a5397293171..3fb7c5e53ea 100644 --- a/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java +++ b/liquibase-core/src/main/java/liquibase/integration/spring/SpringLiquibase.java @@ -1,11 +1,7 @@ package liquibase.integration.spring; -import liquibase.Contexts; -import liquibase.LabelExpression; -import liquibase.Liquibase; -import liquibase.Scope; -import liquibase.configuration.CurrentValue; -import liquibase.GlobalConfiguration; +import liquibase.*; +import liquibase.configuration.ConfiguredValue; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.DatabaseFactory; @@ -251,10 +247,10 @@ public void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) { */ @Override public void afterPropertiesSet() throws LiquibaseException { - final CurrentValue<Boolean> shouldRunProperty = GlobalConfiguration.SHOULD_RUN.getCurrentValueDetails(); + final ConfiguredValue<Boolean> shouldRunProperty = GlobalConfiguration.SHOULD_RUN.getCurrentConfiguredValue(); - if (!shouldRunProperty.getValue()) { - Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " +shouldRunProperty.getSource() + " was set to false"); + if (!(Boolean) shouldRunProperty.getValue()) { + Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run because " +shouldRunProperty.getProvidedValue().describe() + " was set to false"); return; } if (!shouldRun) { diff --git a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java index 204f2f0a8a8..3a4a8af1836 100644 --- a/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/logging/core/DefaultLoggerConfiguration.java @@ -1,12 +1,12 @@ package liquibase.logging.core; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.ConfigurationDefinitionHolder; +import liquibase.configuration.AutoloadedConfigurations; /** * Configuration container for {@link liquibase.logging.LogService} properties */ -public class DefaultLoggerConfiguration implements ConfigurationDefinitionHolder { +public class DefaultLoggerConfiguration implements AutoloadedConfigurations { public static ConfigurationDefinition<String> LOG_LEVEL; diff --git a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java index 5a49a36f77e..74646873a11 100644 --- a/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/parser/ChangeLogParserConfiguration.java @@ -1,12 +1,12 @@ package liquibase.parser; import liquibase.configuration.ConfigurationDefinition; -import liquibase.configuration.ConfigurationDefinitionHolder; +import liquibase.configuration.AutoloadedConfigurations; /** * Configuration container for properties applicable to most {@link liquibase.parser.ChangeLogParser} implementations */ -public class ChangeLogParserConfiguration implements ConfigurationDefinitionHolder { +public class ChangeLogParserConfiguration implements AutoloadedConfigurations { public static final ConfigurationDefinition<Boolean> SUPPORT_PROPERTY_ESCAPING; public static final ConfigurationDefinition<Boolean> USE_PROCEDURE_SCHEMA; diff --git a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java index 1a6b8d15a59..e485d684c81 100644 --- a/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java +++ b/liquibase-core/src/main/java/liquibase/ui/ConsoleUIService.java @@ -3,6 +3,8 @@ import liquibase.AbstractExtensibleObject; import liquibase.Scope; import liquibase.GlobalConfiguration; +import liquibase.configuration.ConfigurationDefinition; +import liquibase.configuration.ConfiguredValue; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.logging.Logger; import liquibase.util.StringUtil; @@ -111,8 +113,9 @@ public <T> T prompt(String prompt, T defaultValue, InputHandler<T> inputHandler, */ protected ConsoleWrapper getConsole() { if (console == null) { - boolean headlessConfigValue = GlobalConfiguration.HEADLESS.getCurrentValue(); - boolean wasHeadlessOverridden = !GlobalConfiguration.HEADLESS.getCurrentValueDetails().getDefaultValueUsed(); + final ConfiguredValue<Boolean> headlessValue = GlobalConfiguration.HEADLESS.getCurrentConfiguredValue(); + boolean headlessConfigValue = headlessValue.getValue(); + boolean wasHeadlessOverridden = !ConfigurationDefinition.wasDefaultValueUsed(headlessValue); final Logger log = Scope.getCurrentScope().getLog(getClass()); diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations similarity index 100% rename from liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationDefinitionHolder rename to liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.AutoloadedConfigurations diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy index e4f633434ff..b996aec8649 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy @@ -6,17 +6,34 @@ import spock.lang.Unroll class ConfigurationDefinitionTest extends Specification { + @Unroll + def "does not allow invalid keys"() { + when: + new ConfigurationDefinition.Builder(prefix).define(property, String).addAliasKey(alias) + + then: + def e = thrown(IllegalArgumentException) + e.message == expectedMessage + + where: + prefix | property | alias | expectedMessage + "test" | "invalid-key" | "valid" | "Invalid key format: test.invalid-key" + "invalid-prefix" | "invalid-key" | "valid" | "Invalid prefix format: invalid-prefix" + "invalid-prefix" | "validValue" | "valid" | "Invalid prefix format: invalid-prefix" + "validPrefix" | "validValue" | "invalid-alias" | "Invalid alias format: invalid-alias" + } + def "Can build and register"() { when: - def definition = new ConfigurationDefinition.Builder("test.can-build") - .define("test-property", String) + def definition = new ConfigurationDefinition.Builder("test.canBuild") + .define("testProperty", String) .setDefaultValue("Default Value") .setDescription("A description here") .build() then: assert Scope.currentScope.getSingleton(LiquibaseConfiguration).getRegisteredDefinitions().contains(definition) - definition.key == "test.can-build.test-property" + definition.key == "test.canBuild.testProperty" definition.defaultValue == "Default Value" definition.description == "A description here" } @@ -30,25 +47,25 @@ class ConfigurationDefinitionTest extends Specification { .setDefaultValue(defaultValue) .buildTemporary() - System.setProperty("test.current-value", "From from system") + System.setProperty("test.currentValue", "From from system") System.setProperty("test.other", "Alias set in system") - def currentValue = Scope.child(["test.current-value": "From scope"], new Scope.ScopedRunnerWithReturn<CurrentValue>() { + def currentValue = Scope.child(["test.currentValue": "From scope"], new Scope.ScopedRunnerWithReturn<ConfiguredValue>() { @Override - CurrentValue run() throws Exception { - return definition.getCurrentValueDetails() + ConfiguredValue run() throws Exception { + return definition.getCurrentConfiguredValue() } }) then: currentValue.value == expectedValue - currentValue.source.describe() == expectedSource - currentValue.getDefaultValueUsed() == defaultValueUsed + currentValue.getProvidedValue().describe() == expectedSource + ConfigurationDefinition.wasDefaultValueUsed(currentValue) == defaultValueUsed where: key | defaultValue | expectedValue | expectedSource | defaultValueUsed - "current-value" | "Default Value" | "From scope" | "Scoped value 'test.current-value'" | false - "unset-value" | "Configured Default" | "Configured Default" | "Default value for 'test.unset-value'" | true - "unset-value" | null | null | "No configuration or default value found for 'test.unset-value'" | false + "currentValue" | "Default Value" | "From scope" | "Scoped value 'test.currentValue'" | false + "unsetValue" | "Configured Default" | "Configured Default" | "Default value 'test.unsetValue'" | true + "unsetValue" | null | null | "No configuration or default value found 'test.unsetValue'" | false } @@ -61,10 +78,10 @@ class ConfigurationDefinitionTest extends Specification { .addAliasKey("other") .buildTemporary() - def currentValue = Scope.child([(key): "From Scope"], new Scope.ScopedRunnerWithReturn<CurrentValue>() { + def currentValue = Scope.child([(key): "From Scope"], new Scope.ScopedRunnerWithReturn<ConfiguredValue>() { @Override - CurrentValue run() throws Exception { - return definition.getCurrentValueDetails() + ConfiguredValue run() throws Exception { + return definition.getCurrentConfiguredValue() } }) @@ -117,6 +134,44 @@ class ConfigurationDefinitionTest extends Specification { input | expected | expectedPlain "value" | "OBFUSCATED value" | "value" null | "OBFUSCATED null" | null + } + + def convertValues() { + when: + def definition = new ConfigurationDefinition.Builder("test") + .define("property", Boolean) + .buildTemporary() + + System.setProperty("test.property", "true") + + then: + definition.getCurrentConfiguredValue().getValue() == Boolean.TRUE + + } + + def equalsAndHash() { + when: + def definition1 = new ConfigurationDefinition.Builder("test") + .define("property1", Boolean) + .buildTemporary() + + def definition2 = new ConfigurationDefinition.Builder("test") + .define("property2", Boolean) + .buildTemporary() + + def dupeDefinition1 = new ConfigurationDefinition.Builder("test") + .define("property1", Boolean) + .buildTemporary() + + then: + definition1.equals(definition1) + definition1.hashCode() == definition1.hashCode() + + !definition1.equals(definition2) + definition1.hashCode() != definition2.hashCode() + + definition1.equals(dupeDefinition1) + definition1.hashCode() == dupeDefinition1.hashCode() } } diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfiguredValueTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfiguredValueTest.groovy new file mode 100644 index 00000000000..60e2b273767 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfiguredValueTest.groovy @@ -0,0 +1,51 @@ +package liquibase.configuration + +import liquibase.configuration.core.ScopeValueProvider +import liquibase.configuration.core.SystemPropertyValueProvider +import spock.lang.Specification + +class ConfiguredValueTest extends Specification { + + def "empty"() { + when: + def configuredValue = new ConfiguredValue("requested.key") + + then: + !configuredValue.found() + configuredValue.getValue() == null + configuredValue.getProvidedValues()*.describe() == ["No configuration or default value found 'requested.key'"] + configuredValue.getProvidedValue().describe() == "No configuration or default value found 'requested.key'" + } + + def "one override"() { + when: + def configuredValue = new ConfiguredValue() + configuredValue.override(new ProvidedValue("requested.key", "actual.key", "value", "first override", new SystemPropertyValueProvider())) + + then: + configuredValue.found() + configuredValue.getValue() == "value" + configuredValue.getProvidedValue().describe() == "first override 'actual.key'" + configuredValue.getProvidedValue().requestedKey == "requested.key" + configuredValue.getProvidedValue().actualKey == "actual.key" + configuredValue.getProvidedValues()*.describe() == ["first override 'actual.key'"] + configuredValue.getProvidedValues()*.provider*.class.name == [SystemPropertyValueProvider.name] + } + + def "two overrides"() { + when: + def configuredValue = new ConfiguredValue() + configuredValue.override(new ProvidedValue("requested.key", "actual.key", "value", "first override", new SystemPropertyValueProvider())) + configuredValue.override(new ProvidedValue("requested.key", "other.actual.key", "second value", "second override", new ScopeValueProvider())) + + then: + configuredValue.found() + configuredValue.getValue() == "second value" + configuredValue.getProvidedValue().describe() == "second override 'other.actual.key'" + configuredValue.getProvidedValue().requestedKey == "requested.key" + configuredValue.getProvidedValue().actualKey == "other.actual.key" + configuredValue.getProvidedValues()*.provider*.class.name == [ScopeValueProvider.name, SystemPropertyValueProvider.name] + configuredValue.getProvidedValues()*.describe() == ["second override 'other.actual.key'", "first override 'actual.key'"] + } + +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy index 0944603e6e5..2e82ede3762 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/LiquibaseConfigurationTest.groovy @@ -5,22 +5,34 @@ import spock.lang.Specification class LiquibaseConfigurationTest extends Specification { - def "getCurrentValueDetails"() { + def "getCurrentConfiguredValue"() { when: - - System.setProperty("test.current-value", "From system") - def currentValue = Scope.child(["test.current-value": "From scope"], new Scope.ScopedRunnerWithReturn<CurrentValueDetails>() { + System.setProperty("test.currentValue", "From system") + def currentValue = Scope.child(["test.currentValue": "From scope"], new Scope.ScopedRunnerWithReturn<ConfiguredValue>() { @Override - CurrentValueDetails run() throws Exception { - return Scope.currentScope.getSingleton(LiquibaseConfiguration).getCurrentValue("test.current-value") + ConfiguredValue run() throws Exception { + return Scope.currentScope.getSingleton(LiquibaseConfiguration).getCurrentConfiguredValue("test.currentValue") } }) then: currentValue.value == "From scope" - currentValue.sourceHistory*.describe() == ["Scoped value 'test.current-value'", "System property 'test.current-value'"] + currentValue.providedValues*.describe() == ["Scoped value 'test.currentValue'", "System property 'test.currentValue'"] + } + + def "getCurrentConfiguredValue with no value found"() { + when: + def currentValue = Scope.currentScope.getSingleton(LiquibaseConfiguration).getCurrentConfiguredValue("test.unknownValue") + + then: + currentValue != null + currentValue.getValue() == null + currentValue.getProvidedValue().sourceDescription == "No configuration or default value found" + currentValue.getProvidedValue().requestedKey == "test.unknownValue" + currentValue.getProvidedValue().provider != null } + def "autoRegisters and sorts providers"() { expect: Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).configurationValueProviders*.getClass()*.getName().contains("liquibase.configuration.core.SystemPropertyValueProvider") @@ -31,4 +43,23 @@ class LiquibaseConfigurationTest extends Specification { Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).getRegisteredDefinitions().size() > 10 } + def "getRegisteredDefinition for a key"() { + when: + def definition = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).getRegisteredDefinition("liquibase.shouldRun") + + then: + definition.key == "liquibase.shouldRun" + definition.description == "Should Liquibase commands execute" + + } + + def "getRegisteredDefinition for an unknown key"() { + when: + def definition = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration).getRegisteredDefinition("test.invalid") + + then: + definition == null + + } + } diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ProvidedValueTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ProvidedValueTest.groovy new file mode 100644 index 00000000000..a77716798db --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ProvidedValueTest.groovy @@ -0,0 +1,12 @@ +package liquibase.configuration + +import liquibase.configuration.core.SystemPropertyValueProvider +import spock.lang.Specification + +class ProvidedValueTest extends Specification { + + def describe() { + expect: + new ProvidedValue("requested.key", "actual.key", "value", "test source", new SystemPropertyValueProvider()).describe() == "test source 'actual.key'" + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy index b14a092ed04..facd49a0bed 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/ScopeValueProviderTest.groovy @@ -1,7 +1,7 @@ package liquibase.configuration.core import liquibase.Scope -import liquibase.configuration.CurrentValueSourceDetails +import liquibase.configuration.ProvidedValue import spock.lang.Specification import spock.lang.Unroll @@ -23,10 +23,10 @@ class ScopeValueProviderTest extends Specification { ] def passedKey = key - CurrentValueSourceDetails foundValue = Scope.child(env, new Scope.ScopedRunnerWithReturn() { + ProvidedValue foundValue = Scope.child(env, new Scope.ScopedRunnerWithReturn<ProvidedValue>() { @Override - Object run() throws Exception { - new ScopeValueProvider().getValue(passedKey) + ProvidedValue run() throws Exception { + new ScopeValueProvider().getProvidedValue(passedKey) } }) diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy index a6c16c10ca0..a65396dfc6b 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy @@ -24,7 +24,7 @@ class SystemPropertyValueProviderTest extends Specification { } } - def value = provider.getValue(key) + def value = provider.getProvidedValue(key) then: if (value == null) { diff --git a/liquibase-core/src/test/java/liquibase/integration/servlet/LiquibaseServletListenerTest.java b/liquibase-core/src/test/java/liquibase/integration/servlet/LiquibaseServletListenerTest.java index 12e3003b463..9641915db04 100644 --- a/liquibase-core/src/test/java/liquibase/integration/servlet/LiquibaseServletListenerTest.java +++ b/liquibase-core/src/test/java/liquibase/integration/servlet/LiquibaseServletListenerTest.java @@ -69,6 +69,9 @@ public void setUp() throws Exception { } public void testShouldNotShutEmbeddedDerbyDown() throws Exception { + if (dataSource == null) { + return; + } try (Connection pooled = dataSource.getConnection()) { servletListener.contextInitialized(new ServletContextEvent(servletContext)); assertEquals("connection.closed", false, pooled.isClosed()); From bd47b230f4da79082459a95dcfb6b26c1e04a865 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Fri, 19 Mar 2021 19:07:41 -0500 Subject: [PATCH 11/17] Cleaning up liquibase.configuration refactoring, adding javadoc, adding tests LB-1222 --- ...AbstractMapConfigurationValueProvider.java | 79 +++++++++++++++++++ .../core/MapConfigurationValueProvider.java | 30 +++++++ .../core/SystemPropertyValueProvider.java | 30 ++----- .../integration/commandline/Main.java | 13 ++- .../license/LicenseServiceFactory.java | 29 ++++--- .../MapConfigurationValueProviderTest.groovy | 56 +++++++++++++ .../SystemPropertyValueProviderTest.groovy | 43 +--------- 7 files changed, 197 insertions(+), 83 deletions(-) create mode 100644 liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java new file mode 100644 index 00000000000..02c8fb95d59 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java @@ -0,0 +1,79 @@ +package liquibase.configuration; + +import liquibase.util.StringUtil; + +import java.util.Map; + +public abstract class AbstractMapConfigurationValueProvider extends AbstractConfigurationValueProvider { + + protected abstract Map<?, ?> getMap(); + + protected abstract String getSourceDescription(); + + /** + * Finds the given key in the result of {@link #getMap()} using {@link #keyMatches(String, String)} to determine key equality + */ + @Override + public ProvidedValue getProvidedValue(String key) { + if (key == null) { + return null; + } + + final Map<?, ?> sourceData = getMap(); + + //try direct lookup first, for performance: + if (sourceData.containsKey(key)) { + return new ProvidedValue(key, key, sourceData.get(key), getSourceDescription(), this); + } + + + for (Map.Entry<?, ?> entry : sourceData.entrySet()) { + final String actualKey = String.valueOf(entry.getKey()); + + if (keyMatches(key, actualKey)) { + final Object value = entry.getValue(); + if (isValueSet(value)) { + return new ProvidedValue(key, actualKey, value, getSourceDescription(), this); + } + } + } + + return null; + } + + /** + * Used by {@link #getProvidedValue(String)} to determine if the given value is a "real" value. + * This implementation returns false if value is null or if it is an empty string + */ + protected boolean isValueSet(Object value) { + if (value == null) { + return false; + } + if (value instanceof String) { + return StringUtil.isNotEmpty((String) value); + } + + return false; + } + + /** + * Used by {@link #getProvidedValue(String)} to determine of a given map entry matches the wanted key. + * This implementation compares the values case-insensitively, and will replace camelCase words with kabob-case + * @param wantedKey the configuration key requested + * @param storedKey the key stored in the map + */ + protected boolean keyMatches(String wantedKey, String storedKey) { + if (storedKey.equalsIgnoreCase(wantedKey)) { + return true; + } + + //convert camelCase to kabob-case + wantedKey = wantedKey.replaceAll("([A-Z])", "-$1"); + if (storedKey.equalsIgnoreCase(wantedKey)) { + return true; + } + + return false; + } + +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java new file mode 100644 index 00000000000..1f99b6252a5 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java @@ -0,0 +1,30 @@ +package liquibase.configuration.core; + +import liquibase.configuration.AbstractMapConfigurationValueProvider; + +import java.util.Map; + +public class MapConfigurationValueProvider extends AbstractMapConfigurationValueProvider { + + private final Map<?, ?> map; + + + public MapConfigurationValueProvider(Map<?, ?> map) { + this.map = map; + } + + @Override + public int getPrecedence() { + return -1; + } + + @Override + protected String getSourceDescription() { + return "In memory map"; + } + + @Override + protected Map<?, ?> getMap() { + return map; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java index fb5473592f1..b21ee0e9e34 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java @@ -1,6 +1,7 @@ package liquibase.configuration.core; import liquibase.configuration.AbstractConfigurationValueProvider; +import liquibase.configuration.AbstractMapConfigurationValueProvider; import liquibase.configuration.ConfigurationValueProvider; import liquibase.configuration.ProvidedValue; import liquibase.util.StringUtil; @@ -13,7 +14,7 @@ * <p> * To improve usability, it will search for the given key case insensitively. */ -public class SystemPropertyValueProvider extends AbstractConfigurationValueProvider { +public class SystemPropertyValueProvider extends AbstractMapConfigurationValueProvider { @Override public int getPrecedence() { @@ -21,31 +22,12 @@ public int getPrecedence() { } @Override - public ProvidedValue getProvidedValue(String key) { - if (key == null) { - return null; - } - - final Properties systemProperties = getSystemProperties(); - - String propValue = systemProperties.getProperty(key); - if (StringUtil.isNotEmpty(propValue)) { - return new ProvidedValue(key, key, propValue, "System property", this); - } - - // - // Not matching with the actual key then try case insensitive - // - for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) { - String foundKey = (String) entry.getKey(); - if (foundKey.equalsIgnoreCase(key)) { - return new ProvidedValue(key, foundKey, entry.getValue(),"System property", this); - } - } - return null; + protected String getSourceDescription() { + return "System property"; } - protected Properties getSystemProperties() { + @Override + protected Map<?, ?> getMap() { return System.getProperties(); } } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index c5871e372f1..80c614d19f1 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -196,13 +196,6 @@ public Integer run() throws Exception { Main main = new Main(); try { - if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { - Scope.getCurrentScope().getUI().sendErrorMessage(( - String.format(coreBundle.getString("did.not.run.because.param.was.set.to.false"), - GlobalConfiguration.SHOULD_RUN.getKey()))); - return 0; - } - if ((args.length == 0) || ((args.length == 1) && ("--" + OPTIONS.HELP).equals(args[0]))) { main.printHelp(System.out); return 0; @@ -328,6 +321,12 @@ public Integer run() throws Exception { Scope.getCurrentScope().getUI().sendMessage(CommandLineUtils.getBanner()); + if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { + Scope.getCurrentScope().getUI().sendErrorMessage(( + String.format(coreBundle.getString("did.not.run.because.param.was.set.to.false"), + GlobalConfiguration.SHOULD_RUN.getKey()))); + return 0; + } if (setupNeeded(main)) { List<String> setupMessages = main.checkSetup(); diff --git a/liquibase-core/src/main/java/liquibase/license/LicenseServiceFactory.java b/liquibase-core/src/main/java/liquibase/license/LicenseServiceFactory.java index 858d591ec25..29fee1b537e 100644 --- a/liquibase-core/src/main/java/liquibase/license/LicenseServiceFactory.java +++ b/liquibase-core/src/main/java/liquibase/license/LicenseServiceFactory.java @@ -4,19 +4,24 @@ public class LicenseServiceFactory extends AbstractPluginFactory<LicenseService> { - private LicenseServiceFactory() {} + private LicenseServiceFactory() { + } - @Override - protected Class<LicenseService> getPluginClass() { - return LicenseService.class; - } + @Override + protected Class<LicenseService> getPluginClass() { + return LicenseService.class; + } - @Override - protected int getPriority(LicenseService obj, Object... args) { - return obj.getPriority(); - } + @Override + protected int getPriority(LicenseService obj, Object... args) { + return obj.getPriority(); + } - public LicenseService getLicenseService() { - return getPlugin(); - } + public LicenseService getLicenseService() { + return getPlugin(); + } + + public void unregister(LicenseService service) { + this.removeInstance(service); + } } diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy new file mode 100644 index 00000000000..aa240f015e8 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy @@ -0,0 +1,56 @@ +package liquibase.configuration.core + +import liquibase.configuration.core.MapConfigurationValueProvider +import spock.lang.Specification +import spock.lang.Unroll + +class MapConfigurationValueProviderTest extends Specification { + + @Unroll + def "keyMatches"() { + expect: + new MapConfigurationValueProvider([:]).keyMatches(wantedKey, storedKey) == matches + + where: + wantedKey | storedKey | matches + "single" | "single" | true + "single" | "SINGLE" | true + "single" | "SiNglE" | true + "parent.child" | "parent.child" | true + "parent.child" | "PARENT.Child" | true + "parent.child" | "PARENT-Child" | false + "parent.child" | "PARENT_Child" | false + "parent.bothChildren" | "Parent.BothChildren" | true + "parent.bothChildren" | "parent.both-children" | true + "parent.bothChildren" | "parent.both_children" | false + "single" | "invalid" | false + "parent.child" | "parent" | false + } + +// def other() { +// expect: +// def provider = new MapConfigurationValueProvider([ +// "lower" : "stored lower", +// "lower.dot" : "stored lower dot", +// "lower_under.dot": "stored lower under dot", +// "UPPER" : "stored upper", +// "UPPER.DOT" : "stored upper dot", +// "Mixed.Case" : "stored mixed case", +// ]) +// +// where: +// requestedKey | expectedValue +// +// "lower" | "saw lower" | "System property 'lower'" +// "LOWER" | "saw lower" | "System property 'lower'" +// "upper" | "saw upper" | "System property 'UPPER'" +// "UPPER" | "saw upper" | "System property 'UPPER'" +// "lower.underscore" | null | null +// "upper.dot" | "saw upper dot" | "System property 'UPPER.DOT'" +// "UPPER.DOT" | "saw upper dot" | "System property 'UPPER.DOT'" +// "LOWER.UNDER.dot" | null | null +// "LOWER_UNDER_DOT" | null | null +// "invalid" | null | null +// null | null | null +// } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy index a65396dfc6b..ba048c98de7 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/SystemPropertyValueProviderTest.groovy @@ -7,45 +7,8 @@ import spock.lang.Unroll class SystemPropertyValueProviderTest extends Specification { @Unroll - def "GetValue"() { - when: - def properties = new Properties() - properties.setProperty("lower", "saw lower") - properties.setProperty("lower.dot", "saw lower dot") - properties.setProperty("lower_under.dot", "saw lower word dot") - properties.setProperty("UPPER", "saw upper") - properties.setProperty("UPPER.DOT", "saw upper dot") - properties.setProperty("Mixed.Case", "saw mixed case") - - def provider = new SystemPropertyValueProvider() { - @Override - protected Properties getSystemProperties() { - return properties - } - } - - def value = provider.getProvidedValue(key) - - then: - if (value == null) { - assert expectedValue == null - } else { - assert value.value == expectedValue - assert value.describe() == expectedSource - } - - where: - key | expectedValue | expectedSource - "lower" | "saw lower" | "System property 'lower'" - "LOWER" | "saw lower" | "System property 'lower'" - "upper" | "saw upper" | "System property 'UPPER'" - "UPPER" | "saw upper" | "System property 'UPPER'" - "lower.underscore" | null | null - "upper.dot" | "saw upper dot" | "System property 'UPPER.DOT'" - "UPPER.DOT" | "saw upper dot" | "System property 'UPPER.DOT'" - "LOWER.UNDER.dot" | null | null - "LOWER_UNDER_DOT" | null | null - "invalid" | null | null - null | null | null + def "getProvidedValue"() { + expect: + new SystemPropertyValueProvider().getProvidedValue("USER.NAME").getValue() == System.getProperty("user.name") } } From 08d3c2ca69606bd9f83dda61123fd90f6bbcfe80 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 23 Mar 2021 10:14:03 -0500 Subject: [PATCH 12/17] Merged from 4.3.x --- .../main/java/liquibase/changelog/ChangelogRewriter.java | 8 ++++---- .../command/core/DeactivateChangeLogCommand.java | 2 +- .../main/java/liquibase/integration/commandline/Main.java | 3 ++- .../maven/plugins/LiquibaseDeactivateChangeLogMojo.java | 5 ++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/changelog/ChangelogRewriter.java b/liquibase-core/src/main/java/liquibase/changelog/ChangelogRewriter.java index ef5c356f154..fb98253fe40 100644 --- a/liquibase-core/src/main/java/liquibase/changelog/ChangelogRewriter.java +++ b/liquibase-core/src/main/java/liquibase/changelog/ChangelogRewriter.java @@ -1,7 +1,7 @@ package liquibase.changelog; import liquibase.Scope; -import liquibase.configuration.GlobalConfiguration; +import liquibase.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.parser.core.xml.XMLChangeLogSAXParser; import liquibase.resource.InputStreamList; @@ -38,7 +38,7 @@ public static ChangeLogRewriterResult removeChangeLogId(String changeLogFile, St list = resourceAccessor.openStreams("", changeLogFile); List<URI> uris = list.getURIs(); InputStream is = list.iterator().next(); - String encoding = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); String changeLogString = StreamUtil.readStreamAsString(is, encoding); if (changeLogFile.toLowerCase().endsWith(".xml")) { // @@ -133,7 +133,7 @@ public static ChangeLogRewriterResult addChangeLogId(String changeLogFile, Strin list = resourceAccessor.openStreams("", changeLogFile); List<URI> uris = list.getURIs(); InputStream is = list.iterator().next(); - String encoding = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding(); + String encoding = GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); String changeLogString = StreamUtil.readStreamAsString(is, encoding); if (changeLogFile.toLowerCase().endsWith(".xml")) { String patternString = "(?ms).*<databaseChangeLog[^>]*>"; @@ -229,4 +229,4 @@ public ChangeLogRewriterResult(String message, boolean success) { public String message; public boolean success; } -} \ No newline at end of file +} diff --git a/liquibase-core/src/main/java/liquibase/command/core/DeactivateChangeLogCommand.java b/liquibase-core/src/main/java/liquibase/command/core/DeactivateChangeLogCommand.java index b5059ae6983..ec127f243cc 100644 --- a/liquibase-core/src/main/java/liquibase/command/core/DeactivateChangeLogCommand.java +++ b/liquibase-core/src/main/java/liquibase/command/core/DeactivateChangeLogCommand.java @@ -56,7 +56,7 @@ public void setOutputStream(PrintStream outputStream) { } @Override - protected CommandResult run() throws Exception { + public CommandResult run() throws Exception { // // Access the HubService // Stop if we do no have a key diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 5df6076ca9a..1a5e64d748d 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -1663,7 +1663,8 @@ protected void doMigration() throws Exception { DeactivateChangeLogCommand liquibaseCommand = (DeactivateChangeLogCommand)createLiquibaseCommand(database, liquibase, COMMANDS.DEACTIVATE_CHANGELOG, argsMap); liquibaseCommand.setChangeLogFile(changeLogFile); - CommandResult result = liquibaseCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(liquibaseCommand); + if (result.succeeded) { Scope.getCurrentScope().getUI().sendMessage(result.print()); } else { diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDeactivateChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDeactivateChangeLogMojo.java index 9745317bbfa..bdf960fe1b1 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDeactivateChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/LiquibaseDeactivateChangeLogMojo.java @@ -30,8 +30,7 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseException { super.performLiquibaseTask(liquibase); Database database = liquibase.getDatabase(); - DeactivateChangeLogCommand deactivateChangeLogCommand = - (DeactivateChangeLogCommand) CommandFactory.getInstance().getCommand("deactivateChangeLog"); + DeactivateChangeLogCommand deactivateChangeLogCommand = (DeactivateChangeLogCommand) Scope.getCurrentScope().getSingleton(CommandFactory.class).getCommand("deactivateChangeLog"); deactivateChangeLogCommand.setChangeLogFile(changeLogFile); Map<String, Object> argsMap = new HashMap<>(); argsMap.put("changeLogFile", changeLogFile); @@ -40,7 +39,7 @@ protected void performLiquibaseTask(Liquibase liquibase) argsMap.put("changeLog", liquibase.getDatabaseChangeLog()); deactivateChangeLogCommand.configure(argsMap); try { - CommandResult result = deactivateChangeLogCommand.execute(); + CommandResult result = Scope.getCurrentScope().getSingleton(CommandFactory.class).execute(deactivateChangeLogCommand); if (result.succeeded) { Scope.getCurrentScope().getUI().sendMessage(result.print()); } else { From 96d45abeaff2f913668275a19bf9bc57ae49528f Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 23 Mar 2021 16:50:21 -0500 Subject: [PATCH 13/17] Re-introduced deprecated methods for pre-4.4.0 liquibase.command compatibility LB-1306 --- .../AbstractConfigurationContainer.java | 109 +++++ ...AbstractMapConfigurationValueProvider.java | 5 +- .../configuration/ConfigurationContainer.java | 34 ++ .../configuration/ConfigurationProperty.java | 177 ++++++++ .../ConfigurationValueHandler.java | 8 + .../configuration/GlobalConfiguration.java | 391 ++++++++++++++++++ .../configuration/LiquibaseConfiguration.java | 19 + .../DeprecatedConfigurationValueProvider.java | 54 +++ .../output/changelog/DiffToChangeLog.java | 3 +- .../main/java/liquibase/hub/HubUpdater.java | 3 +- .../java/liquibase/hub/core/HttpClient.java | 3 +- .../integration/commandline/Main.java | 11 +- .../servlet/LiquibaseServletListener.java | 8 +- ...e.configuration.ConfigurationValueProvider | 1 + .../changelog/ChangeLogRewriterTest.groovy | 2 +- .../ConfigurationDefinitionTest.groovy | 4 + .../ConfigurationPropertyTest.groovy | 55 +++ .../DeprecatedConfigurationCodeTest.groovy | 75 ++++ .../GlobalConfigurationTest.groovy | 12 + ...catedConfigurationValueProviderTest.groovy | 22 + .../MapConfigurationValueProviderTest.groovy | 36 +- .../AbstractLiquibaseChangeLogMojo.java | 7 +- 22 files changed, 995 insertions(+), 44 deletions(-) create mode 100644 liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java create mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationPropertyTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/DeprecatedConfigurationCodeTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/GlobalConfigurationTest.groovy create mode 100644 liquibase-core/src/test/groovy/liquibase/configuration/core/DeprecatedConfigurationValueProviderTest.groovy diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java new file mode 100644 index 00000000000..d089e13bc40 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/AbstractConfigurationContainer.java @@ -0,0 +1,109 @@ +package liquibase.configuration; + +import liquibase.Scope; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @deprecated Use new {@link ConfigurationDefinition} style + */ +public abstract class AbstractConfigurationContainer implements ConfigurationContainer { + + private final String namespace; + private final ConfigurationContainer container; + private Map<String, ConfigurationProperty> properties = new HashMap<>(); + + public AbstractConfigurationContainer(String namespace) { + this.namespace = namespace; + this.container = new ConfigurationContainer(); + } + + /** + * @deprecated + */ + protected ConfigurationContainer getContainer() { + return container; + } + + /** + * @deprecated + */ + @Override + public ConfigurationProperty getProperty(String propertyName) { + return properties.get(propertyName); + } + + /** + * @deprecated + */ + @Override + public Set<ConfigurationProperty> getProperties() { + return new HashSet<>(properties.values()); + } + + /** + * @deprecated + */ + @Override + public <T> T getValue(String propertyName, Class<T> returnType) { + final ConfiguredValue currentValue = Scope.getCurrentScope().getSingleton(LiquibaseConfiguration.class).getCurrentConfiguredValue(namespace + "." + propertyName); + return (T) currentValue.getValue(); + } + + /** + * @deprecated + */ + @Override + public void setValue(String propertyName, Object value) { + DeprecatedConfigurationValueProvider.setData(namespace + "." + propertyName, value); + } + + /** + * @deprecated + */ + @Override + public String getNamespace() { + return namespace; + } + + /** + * @deprecated + */ + protected class ConfigurationContainer { + + /** + * @deprecated + */ + public ConfigurationProperty addProperty(String propertyName, Class type) { + final ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder(namespace); + final ConfigurationDefinition.Builder.NewDefinition newDefinition = builder.define(propertyName, type); + + final ConfigurationProperty property = new ConfigurationProperty(namespace, newDefinition); + + properties.put(propertyName, property); + return property; + } + + public ConfigurationProperty getProperty(String propertyName) { + return AbstractConfigurationContainer.this.getProperty(propertyName); + } + + public <T> T getValue(String propertyName, Class<T> returnType) { + return AbstractConfigurationContainer.this.getValue(propertyName, returnType); + } + + public void setValue(String propertyName, Object value) { + AbstractConfigurationContainer.this.setValue(propertyName, value); + } + } + + protected static class DelegatedConfigurationContainer extends AbstractConfigurationContainer { + public DelegatedConfigurationContainer(String namespace) { + super(namespace); + } + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java index 02c8fb95d59..20f1649d987 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java @@ -23,7 +23,10 @@ public ProvidedValue getProvidedValue(String key) { //try direct lookup first, for performance: if (sourceData.containsKey(key)) { - return new ProvidedValue(key, key, sourceData.get(key), getSourceDescription(), this); + final Object foundValue = sourceData.get(key); + if (isValueSet(foundValue)) { + return new ProvidedValue(key, key, foundValue, getSourceDescription(), this); + } } diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java new file mode 100644 index 00000000000..36186531940 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationContainer.java @@ -0,0 +1,34 @@ +package liquibase.configuration; + +import java.util.Set; + +/** + * @deprecated interface from old style configuration code. Use {@link ConfigurationDefinition} and {@link AutoloadedConfigurations} now. + */ +public interface ConfigurationContainer { + + /** + * @deprecated + */ + ConfigurationProperty getProperty(String propertyName); + + /** + * @deprecated + */ + Set<ConfigurationProperty> getProperties(); + + /** + * @deprecated + */ + <T> T getValue(String propertyName, Class<T> returnType); + + /** + * @deprecated + */ + void setValue(String propertyName, Object value); + + /** + * @deprecated + */ + String getNamespace(); +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java new file mode 100644 index 00000000000..5f215ef3ebd --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationProperty.java @@ -0,0 +1,177 @@ +package liquibase.configuration; + +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; +import liquibase.exception.UnexpectedLiquibaseException; +import liquibase.util.StringUtil; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @deprecated + */ +public class ConfigurationProperty { + + private final ConfigurationDefinition.Builder.NewDefinition definitionBuilder; + private ConfigurationDefinition definition; + private final String namespace; + + public ConfigurationProperty(String namespace, ConfigurationDefinition.Builder.NewDefinition definitionBuilder) { + this.namespace = namespace; + this.definitionBuilder = definitionBuilder; + this.definition = definitionBuilder.buildTemporary(); + } + + /** + * Returns the property name. + * + * @deprecated + */ + public String getName() { + return definition.getKey().replace(namespace+".", ""); + } + + /** + * Returns the namespace used by this property's {@link ConfigurationContainer} + * @deprecated + */ + public String getNamespace() { + return namespace; + } + + /** + * Returns the type of value stored in this property + * @deprecated + */ + public Class getType() { + return definition.getType(); + } + + /** + * Converts an object of a different type to the type used by this property. If types are not convertible, an exception is thrown. + * @deprecated + */ + protected Object valueOf(Object value) { + Class type = definition.getType(); + if (value == null) { + return value; + } else if (type.isAssignableFrom(value.getClass())) { + return value; + } else if (value instanceof String) { + if (type.equals(Boolean.class)) { + return Boolean.valueOf((String) value); + } else if (type.equals(Integer.class)) { + return Integer.valueOf((String) value); + } else if (type.equals(BigDecimal.class)) { + return new BigDecimal((String) value); + } else if (type.equals(Long.class)) { + return Long.valueOf((String) value); + } else if (type.equals(List.class)) { + return StringUtil.splitAndTrim((String) value, ","); + } else { + throw new UnexpectedLiquibaseException("Cannot parse property "+value.getClass().getSimpleName()+" to a "+type.getSimpleName()); + } + } else { + throw new UnexpectedLiquibaseException("Could not convert "+value.getClass().getSimpleName()+" to a "+type.getSimpleName()); + } + } + + /** + * Returns the value currently stored in this property without any casting. + * @deprecated + */ + public Object getValue() { + return definition.getCurrentValue(); + } + + /** + * Returns the value currently stored in this property cast to the given type. + * @deprecated + */ + public <T> T getValue(Class<T> type) { + if (!this.definition.getType().isAssignableFrom(type)) { + throw new UnexpectedLiquibaseException("Property "+definition.getType()+" on is of type "+this.definition.getType().getSimpleName()+", not "+type.getSimpleName()); + } + + return (T) definition.getCurrentValue(); + } + + /** + * Overwrites the value currently stored in this property. It he passed type is not compatible with the defined type, an exception is thrown. + * @deprecated + */ + public void setValue(Object value) { + DeprecatedConfigurationValueProvider.setData(definition, value); + } + + /** + * Adds an alias for this property. An alias is an alternate to the "name" field that can be used by the ConfigurationProvers to look up starting values. + * @deprecated + */ + public ConfigurationProperty addAlias(String... aliases) { + if (aliases != null) { + for (String alias : aliases) { + definitionBuilder.addAliasKey(alias); + } + + definition = definitionBuilder.buildTemporary(); + } + + return this; + } + + /** + * Returns a human-readable definition of this property + * @deprecated + */ + public String getDescription() { + return definition.getDescription(); + } + + /** + * @deprecated + */ + public ConfigurationProperty setDescription(String description) { + this.definitionBuilder.setDescription(description); + this.definition = definitionBuilder.buildTemporary(); + + return this; + } + + /** + * Returns the default value to use if no ConfigurationProviders override it. + * @deprecated + */ + public Object getDefaultValue() { + return definition.getDefaultValue(); + } + + /** + * Sets the default value to use if no ConfigurationProviders override it. Throws an exception if the given object is not compatible with the defined type. + * @deprecated + */ + public ConfigurationProperty setDefaultValue(Object defaultValue) { + this.definitionBuilder.setDefaultValue(defaultValue); + this.definition = definitionBuilder.buildTemporary(); + + return this; + } + + /** + * Returns true if the value has been set by a ConfigurationValueProvider or by {@link #setValue(Object)} + * @deprecated + */ + public boolean getWasOverridden() { + return !ConfigurationDefinition.wasDefaultValueUsed(this.definition.getCurrentConfiguredValue()); + } + + /** + * @deprecated + */ + public ConfigurationProperty setValueHandler(ConfigurationValueHandler handler) { + this.definitionBuilder.setValueHandler(value -> handler.convert(value)); + this.definition = definitionBuilder.buildTemporary(); + + return this; + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java new file mode 100644 index 00000000000..d6d322d7a77 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueHandler.java @@ -0,0 +1,8 @@ +package liquibase.configuration; + +/** + * @deprecated + */ +public interface ConfigurationValueHandler { + Object convert(Object value); +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java new file mode 100644 index 00000000000..128fd7e1a75 --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/GlobalConfiguration.java @@ -0,0 +1,391 @@ +package liquibase.configuration; + +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; + +import java.util.Set; + +/** + * @deprecated use {@link liquibase.GlobalConfiguration} + */ +public class GlobalConfiguration extends liquibase.GlobalConfiguration implements ConfigurationContainer { + + /** + * @deprecated + */ + public static final String SHOULD_RUN = liquibase.GlobalConfiguration.SHOULD_RUN.getKey(); + + /** + * @deprecated + */ + public static final String DATABASECHANGELOG_TABLE_NAME = liquibase.GlobalConfiguration.DATABASECHANGELOG_TABLE_NAME.getKey(); + + /** + * @deprecated + */ + public static final String DATABASECHANGELOGLOCK_TABLE_NAME = liquibase.GlobalConfiguration.DATABASECHANGELOGLOCK_TABLE_NAME.getKey(); + + /** + * @deprecated + */ + public static final String LIQUIBASE_TABLESPACE_NAME = liquibase.GlobalConfiguration.LIQUIBASE_TABLESPACE_NAME.getKey(); + + /** + * @deprecated + */ + public static final String LIQUIBASE_CATALOG_NAME = liquibase.GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getKey(); + + /** + * @deprecated + */ + public static final String LIQUIBASE_SCHEMA_NAME = liquibase.GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getKey(); + + /** + * @deprecated + */ + public static final String OUTPUT_LINE_SEPARATOR = liquibase.GlobalConfiguration.OUTPUT_LINE_SEPARATOR.getKey(); + + /** + * @deprecated + */ + public static final String OUTPUT_ENCODING = liquibase.GlobalConfiguration.OUTPUT_ENCODING.getKey(); + + /** + * @deprecated + */ + public static final String CHANGELOGLOCK_WAIT_TIME = liquibase.GlobalConfiguration.CHANGELOGLOCK_WAIT_TIME.getKey(); + + /** + * @deprecated + */ + public static final String CHANGELOGLOCK_POLL_RATE = liquibase.GlobalConfiguration.CHANGELOGLOCK_POLL_RATE.getKey(); + + /** + * @deprecated + */ + public static final String CONVERT_DATA_TYPES = liquibase.GlobalConfiguration.CONVERT_DATA_TYPES.getKey(); + + /** + * @deprecated + */ + public static final String GENERATE_CHANGESET_CREATED_VALUES = liquibase.GlobalConfiguration.GENERATE_CHANGESET_CREATED_VALUES.getKey(); + + /** + * @deprecated + */ + public static final String AUTO_REORG = liquibase.GlobalConfiguration.AUTO_REORG.getKey(); + + /** + * @deprecated + */ + public static final String DIFF_COLUMN_ORDER = liquibase.GlobalConfiguration.DIFF_COLUMN_ORDER.getKey(); + + /** + * @deprecated + */ + public static final String ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA = liquibase.GlobalConfiguration.ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA.getKey(); + + /** + * @deprecated + */ + public static final String GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION = liquibase.GlobalConfiguration.GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION.getKey(); + + /** + * @deprecated + */ + public static final String INCLUDE_CATALOG_IN_SPECIFICATION = liquibase.GlobalConfiguration.INCLUDE_CATALOG_IN_SPECIFICATION.getKey(); + + /** + * @deprecated + */ + public static final String SHOULD_SNAPSHOT_DATA = liquibase.GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getKey(); + + /** + * @deprecated + */ + public static final String FILTER_LOG_MESSAGES = liquibase.GlobalConfiguration.FILTER_LOG_MESSAGES.getKey(); + + /** + * @deprecated + */ + public static final String HEADLESS = liquibase.GlobalConfiguration.HEADLESS.getKey(); + + private static final AbstractConfigurationContainer.DelegatedConfigurationContainer containerDelegate = new AbstractConfigurationContainer.DelegatedConfigurationContainer("liquibase"); + + public GlobalConfiguration() { + } + + /** + * Should Liquibase execute + * @deprecated + */ + public boolean getShouldRun() { + return liquibase.GlobalConfiguration.SHOULD_RUN.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setShouldRun(boolean shouldRun) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.SHOULD_RUN, shouldRun); + return this; + } + + /** + * Table name to use for DATABASECHANGELOG + * @deprecated + */ + public String getDatabaseChangeLogTableName() { + return liquibase.GlobalConfiguration.DATABASECHANGELOG_TABLE_NAME.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setDatabaseChangeLogTableName(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.DATABASECHANGELOG_TABLE_NAME, name); + return this; + } + + /** + * Table name to use for DATABASECHANGELOGLOCK + * @deprecated + */ + public String getDatabaseChangeLogLockTableName() { + return liquibase.GlobalConfiguration.DATABASECHANGELOGLOCK_TABLE_NAME.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setDatabaseChangeLogLockTableName(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.DATABASECHANGELOGLOCK_TABLE_NAME, name); + return this; + } + + /** + * Wait time (in minutes) to wait to receive the changelog lock before giving up. + * @deprecated + */ + public Long getDatabaseChangeLogLockWaitTime() { + return liquibase.GlobalConfiguration.CHANGELOGLOCK_WAIT_TIME.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setDatabaseChangeLogLockWaitTime(Long minutes) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.CHANGELOGLOCK_WAIT_TIME, minutes); + return this; + } + + /** + * Wait time (in seconds) between polling requests to the changelog lock system. + * @deprecated + */ + public Long getDatabaseChangeLogLockPollRate() { + return liquibase.GlobalConfiguration.CHANGELOGLOCK_POLL_RATE.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setDatabaseChangeLogLockPollRate(Long seconds) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.CHANGELOGLOCK_POLL_RATE, seconds); + return this; + } + + /** + * Name of the tablespace to use for liquibase database objects + * @deprecated + */ + public String getLiquibaseTablespaceName() { + return liquibase.GlobalConfiguration.LIQUIBASE_TABLESPACE_NAME.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setLiquibaseTablespaceName(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.LIQUIBASE_TABLESPACE_NAME, name); + return this; + } + + /** + * Should Liquibase snapshot data for table by default + * @deprecated + */ + public boolean getShouldSnapshotData() { + return liquibase.GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setShouldSnapshotData(boolean shouldSnapshotData) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.SHOULD_SNAPSHOT_DATA, shouldSnapshotData); + return this; + } + + /** + * @deprecated + */ + public boolean getShouldFilterLogMessages() { + return liquibase.GlobalConfiguration.FILTER_LOG_MESSAGES.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setShouldFilterLogMessages(boolean filter) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.FILTER_LOG_MESSAGES, filter); + return this; + } + + /** + * @deprecated + */ + public boolean getHeadless() { + return liquibase.GlobalConfiguration.HEADLESS.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setHeadless(boolean headless) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.HEADLESS, headless); + return this; + } + + /** + * Name of the catalog to use for liquibase database objects + */ + public String getLiquibaseCatalogName() { + return liquibase.GlobalConfiguration.LIQUIBASE_CATALOG_NAME.getCurrentValue(); + + } + + public GlobalConfiguration setLiquibaseCatalogName(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.LIQUIBASE_CATALOG_NAME, name); + return this; + } + + /** + * Name of the schema to use for liquibase database objects + */ + public String getLiquibaseSchemaName() { + return liquibase.GlobalConfiguration.LIQUIBASE_SCHEMA_NAME.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setLiquibaseSchemaName(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.LIQUIBASE_SCHEMA_NAME, name); + return this; + } + + /** + * Line separator to use in output + * @deprecated + */ + public String getOutputLineSeparator() { + return liquibase.GlobalConfiguration.OUTPUT_LINE_SEPARATOR.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setOutputLineSeparator(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.OUTPUT_LINE_SEPARATOR, name); + return this; + } + + /** + * String encoding to use in output. + * @deprecated + */ + public String getOutputEncoding() { + return liquibase.GlobalConfiguration.OUTPUT_ENCODING.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setOutputEncoding(String name) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.OUTPUT_ENCODING, name); + return this; + } + + /** + * @deprecated + */ + public Boolean getDiffColumnOrder() { + return liquibase.GlobalConfiguration.DIFF_COLUMN_ORDER.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setDiffColumnOrder(boolean diff) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.DIFF_COLUMN_ORDER, diff); + return this; + } + + + /** + * @deprecated + */ + public Boolean getAlwaysOverrideStoredLogicSchema() { + return liquibase.GlobalConfiguration.ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA.getCurrentValue(); + + } + + /** + * @deprecated + */ + public GlobalConfiguration setAlwaysOverrideStoredLogicSchema(boolean override) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.ALWAYS_OVERRIDE_STORED_LOGIC_SCHEMA, override); + return this; + } + + + /** + * @deprecated + */ + public Boolean getGeneratedChangeSetIdsContainDescription() { + return liquibase.GlobalConfiguration.GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION.getCurrentValue(); + } + + /** + * @deprecated + */ + public GlobalConfiguration setGeneratedChangeSetIdsContainDescription(boolean containDescription) { + DeprecatedConfigurationValueProvider.setData(liquibase.GlobalConfiguration.GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION, containDescription); + return this; + } + + @Override + public ConfigurationProperty getProperty(String propertyName) { + return containerDelegate.getProperty(propertyName); + } + + @Override + public Set<ConfigurationProperty> getProperties() { + return containerDelegate.getProperties(); + } + + @Override + public <T> T getValue(String propertyName, Class<T> returnType) { + return containerDelegate.getValue(propertyName, returnType); + } + + @Override + public void setValue(String propertyName, Object value) { + containerDelegate.setValue(propertyName, value); + } + + @Override + public String getNamespace() { + return containerDelegate.getNamespace(); + } +} diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index c02553bcf90..e943c5b6269 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -2,6 +2,7 @@ import liquibase.Scope; import liquibase.SingletonObject; +import liquibase.exception.UnexpectedLiquibaseException; import liquibase.servicelocator.ServiceLocator; import java.util.*; @@ -35,6 +36,13 @@ protected LiquibaseConfiguration() { } + /** + * @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. */ @@ -65,6 +73,17 @@ public boolean removeProvider(ConfigurationValueProvider provider) { return this.configurationValueProviders.remove(provider); } + /** + * @deprecated use {@link ConfigurationDefinition} instances directly + */ + public <T extends ConfigurationContainer> T getConfiguration(Class<T> type) { + try { + return type.newInstance(); + } catch (Throwable e) { + throw new UnexpectedLiquibaseException(e); + } + } + /** * Searches for the given key in the current providers. diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java new file mode 100644 index 00000000000..08d2538b5bf --- /dev/null +++ b/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java @@ -0,0 +1,54 @@ +package liquibase.configuration.core; + +import liquibase.configuration.ConfigurationDefinition; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link liquibase.configuration.ConfigurationValueProvider} that simulates the behavior from pre-4.4 methods like {@link liquibase.configuration.GlobalConfiguration#setOutputEncoding(String)}. + * It is also useful for integrations that do not yet support a "Scope" style calling of logic. + * The values set in here should override environmental settings like {@link SystemPropertyValueProvider} but is overridden by new-style code using {@link ScopeValueProvider}. + * + * @deprecated + */ +public class DeprecatedConfigurationValueProvider extends MapConfigurationValueProvider { + + private static final Map<String, Object> data = new HashMap<>(); + + public DeprecatedConfigurationValueProvider() { + super(data); + } + + @Override + public int getPrecedence() { + return 40; + } + + /** + * @deprecated + */ + public static void setData(String key, Object value) { + data.put(key, value); + } + + /** + * @deprecated + */ + public static <T> void setData(ConfigurationDefinition<T> configuration, T value) { + data.put(configuration.getKey(), value); + } + + /** + * Clears all data stored in this provider. + * @deprecated + */ + public static void clearData() { + data.clear(); + } + + @Override + protected String getSourceDescription() { + return "Legacy configuration"; + } +} diff --git a/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java b/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java index 2db7d90510a..14875a65642 100644 --- a/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java +++ b/liquibase-core/src/main/java/liquibase/diff/output/changelog/DiffToChangeLog.java @@ -5,6 +5,7 @@ import liquibase.change.core.*; import liquibase.changelog.ChangeSet; import liquibase.GlobalConfiguration; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; import liquibase.database.*; import liquibase.database.core.*; import liquibase.diff.DiffResult; @@ -96,7 +97,7 @@ public void print(String changeLogFile, ChangeLogSerializer changeLogSerializer) File objectsDir = null; if (changeLogFile.toLowerCase().endsWith("sql")) { - System.setProperty("liquibase.pro.sql.inline", "true"); + DeprecatedConfigurationValueProvider.setData("liquibase.pro.sql.inline", "true"); } else if (this.diffResult.getComparisonSnapshot() instanceof EmptyDatabaseSnapshot) { objectsDir = new File(file.getParentFile(), "objects"); } else { diff --git a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java index 4238ecdc921..fb53e077b2c 100644 --- a/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java +++ b/liquibase-core/src/main/java/liquibase/hub/HubUpdater.java @@ -13,6 +13,7 @@ import liquibase.command.core.SyncHubCommand; import liquibase.configuration.ConfigurationDefinition; import liquibase.configuration.ConfiguredValue; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; import liquibase.database.Database; import liquibase.database.DatabaseConnection; import liquibase.database.jvm.JdbcConnection; @@ -479,7 +480,7 @@ public void register(String changeLogFile) message = "* Registering changelog file " + changeLogFile + " with Hub"; Scope.getCurrentScope().getUI().sendMessage(message); Scope.getCurrentScope().getLog(getClass()).info(message); - System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), registerResponse.getApiKey()); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_API_KEY, registerResponse.getApiKey()); registerChangeLog(registerResponse.getProjectId(), changeLog, changeLogFile); message = "Great! Your free operation and deployment reports will be available to you after your local Liquibase commands complete."; diff --git a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java index 9e86bab3801..38824f5f4a6 100644 --- a/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java +++ b/liquibase-core/src/main/java/liquibase/hub/core/HttpClient.java @@ -1,6 +1,7 @@ package liquibase.hub.core; import liquibase.Scope; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; import liquibase.hub.HubConfiguration; import liquibase.hub.LiquibaseHubException; import liquibase.hub.LiquibaseHubObjectNotFoundException; @@ -181,7 +182,7 @@ protected <T> T doRequest(String method, String url, Object requestBodyObject, newHubUrl = newHubUrl.replaceAll(url, ""); Scope.getCurrentScope().getLog(getClass()).info("Redirecting to URL: " + newHubUrl); - System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), newHubUrl); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_URL, newHubUrl); throw new LiquibaseHubRedirectException(); } } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 1a5e64d748d..0ad9a66e6ad 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -11,6 +11,7 @@ import liquibase.command.core.*; import liquibase.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; import liquibase.hub.HubConfiguration; import liquibase.database.Database; import liquibase.diff.compare.CompareControl; @@ -343,14 +344,14 @@ public Integer run() throws Exception { // Store the Hub API key for later use // if (StringUtil.isNotEmpty(main.liquibaseHubApiKey)) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), main.liquibaseHubApiKey); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_API_KEY, main.liquibaseHubApiKey); } // // Store the Hub URL for later use // if (StringUtil.isNotEmpty(main.liquibaseHubUrl)) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), main.liquibaseHubUrl); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_URL, main.liquibaseHubUrl); } main.applyDefaults(); @@ -439,7 +440,7 @@ protected static void setLogLevel(LogService logService, java.util.logging.Logge // Set the Liquibase Hub log level if logging is not OFF // if (level != Level.OFF) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_LOGLEVEL.getKey(), level.toString()); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_LOGLEVEL, level); } } @@ -1036,7 +1037,7 @@ protected void parsePropertiesFile(InputStream propertiesInputStream) throws IOE } } if (System.getProperty((String) entry.getKey()) == null) { - System.setProperty((String) entry.getKey(), (String) entry.getValue()); + DeprecatedConfigurationValueProvider.setData((String) entry.getKey(), entry.getValue()); } } else { Field field = getDeclaredField((String)entry.getKey()); @@ -1428,7 +1429,7 @@ protected void doMigration() throws Exception { // Set the global configuration option based on presence of the dataOutputDirectory // boolean b = dataOutputDirectory != null; - System.setProperty(GlobalConfiguration.SHOULD_SNAPSHOT_DATA.getKey(), String.valueOf(b)); + DeprecatedConfigurationValueProvider.setData(GlobalConfiguration.SHOULD_SNAPSHOT_DATA, b); ObjectChangeFilter objectChangeFilter = null; CompareControl.ComputedSchemas computedSchemas = CompareControl.computeSchemas( diff --git a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java index d3de0919fd4..3e8050c67bb 100644 --- a/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java +++ b/liquibase-core/src/main/java/liquibase/integration/servlet/LiquibaseServletListener.java @@ -141,9 +141,9 @@ public void contextInitialized(ServletContextEvent servletContextEvent) { * </ol> */ private boolean checkPreconditions(ServletContext servletContext, InitialContext ic) { - if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { + if (!liquibase.GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getLog(getClass()).info("Liquibase did not run on " + hostName - + " because " + GlobalConfiguration.SHOULD_RUN.getKey() + + " because " + liquibase.GlobalConfiguration.SHOULD_RUN.getKey() + " was set to false"); return false; } @@ -173,8 +173,8 @@ private boolean checkPreconditions(ServletContext servletContext, InitialContext } } - final ConfiguredValue<Boolean> shouldRunValue = GlobalConfiguration.SHOULD_RUN.getCurrentConfiguredValue(); - if (GlobalConfiguration.SHOULD_RUN.getCurrentValue() && !ConfigurationDefinition.wasDefaultValueUsed(shouldRunValue)) { + final ConfiguredValue<Boolean> shouldRunValue = liquibase.GlobalConfiguration.SHOULD_RUN.getCurrentConfiguredValue(); + if (liquibase.GlobalConfiguration.SHOULD_RUN.getCurrentValue() && !ConfigurationDefinition.wasDefaultValueUsed(shouldRunValue)) { shouldRun = true; servletContext.log("ignoring " + LIQUIBASE_HOST_INCLUDES + " and " + LIQUIBASE_HOST_EXCLUDES + ", since " + shouldRunValue.getProvidedValue().describe() diff --git a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider index 5d078dc0980..f4ba760cb72 100644 --- a/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider +++ b/liquibase-core/src/main/resources/META-INF/services/liquibase.configuration.ConfigurationValueProvider @@ -1,2 +1,3 @@ +liquibase.configuration.core.DeprecatedConfigurationValueProvider liquibase.configuration.core.SystemPropertyValueProvider liquibase.configuration.core.ScopeValueProvider diff --git a/liquibase-core/src/test/groovy/liquibase/changelog/ChangeLogRewriterTest.groovy b/liquibase-core/src/test/groovy/liquibase/changelog/ChangeLogRewriterTest.groovy index 915578d98ad..b667a852a1f 100644 --- a/liquibase-core/src/test/groovy/liquibase/changelog/ChangeLogRewriterTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/changelog/ChangeLogRewriterTest.groovy @@ -99,7 +99,7 @@ class ChangeLogRewriterTest extends Specification { then: !result.success - result.message.matches(".*was not registered due to an error.*Permission denied.*") + result.message.matches(".*was not registered due to an error.*") !matcher.matches() !idMatcher.matches() changeLog.getChangeLogId() == null diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy index b996aec8649..db77b4dd503 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy @@ -6,6 +6,10 @@ import spock.lang.Unroll class ConfigurationDefinitionTest extends Specification { + def cleanup() { + System.clearProperty("test.property") + } + @Unroll def "does not allow invalid keys"() { when: diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationPropertyTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationPropertyTest.groovy new file mode 100644 index 00000000000..6aef30a01cc --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationPropertyTest.groovy @@ -0,0 +1,55 @@ +package liquibase.configuration + +import liquibase.configuration.core.DeprecatedConfigurationValueProvider +import spock.lang.Specification + +class ConfigurationPropertyTest extends Specification { + + def "setup"() { + DeprecatedConfigurationValueProvider.clearData() + } + + def "cleanup"() { + DeprecatedConfigurationValueProvider.clearData() + } + + def "Works correctly"() { + when: + def builder = new ConfigurationDefinition.Builder("test").define("property", String) + def property = new ConfigurationProperty("test", builder) + .addAlias("test.other.property") + .setDescription("test property desc") + + then: + property.getNamespace() == "test" + property.getName() == "property" + property.getType() == String + property.getDescription() == "test property desc" + property.getValue() == null + + when: + property.setDefaultValue("default value") + then: + property.getDefaultValue() == "default value" + property.getValue() == "default value" + !property.getWasOverridden() + + when: + DeprecatedConfigurationValueProvider.setData("test.property", "set value") + then: + property.getValue(String) == "set value" + property.getWasOverridden() + + + when: + property.setValue("other value") + then: + property.getValue() == "other value" + + when: + DeprecatedConfigurationValueProvider.clearData() + DeprecatedConfigurationValueProvider.setData("test.other.property", "alias value") + then: + property.getValue() == "alias value" + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/DeprecatedConfigurationCodeTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/DeprecatedConfigurationCodeTest.groovy new file mode 100644 index 00000000000..da50be35f4c --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/DeprecatedConfigurationCodeTest.groovy @@ -0,0 +1,75 @@ +package liquibase.configuration + +import liquibase.configuration.core.DeprecatedConfigurationValueProvider +import spock.lang.Specification + +/** + * Test deprecated styles of code to ensure we are API compatible with them. + * Be liberal with type casts so ensure we are using the correct APIs + */ +class DeprecatedConfigurationCodeTest extends Specification { + + def "cleanup"() { + DeprecatedConfigurationValueProvider.clearData() + } + + def "4_3 getter style configuration lookup"() { + expect: + LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding() == "UTF-8" + } + + def "4_3 setter style configuration setting"() { + when: + def config = LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class) + + config.setOutputEncoding("ASCII") + + then: + config.getOutputEncoding() == "ASCII" + + when: + DeprecatedConfigurationValueProvider.clearData() + + then: + config.getOutputEncoding() == "UTF-8" + } + + def "4_3 ConfigurationContainer custom implementations"() { + when: + def config = LiquibaseConfiguration.getInstance().getConfiguration(DeprecatedConfigurationConfig.class) + def property = (ConfigurationProperty) config.getProperty(DeprecatedConfigurationConfig.TEST_PROPERTY) + + then: + config.getProperties()*.getName() == ["testProperty"] + property.description == "A test property" + property.getValue() == "default value" + !property.getWasOverridden() + } + + private static class DeprecatedConfigurationConfig extends AbstractConfigurationContainer { + + private static final String TEST_PROPERTY = "testProperty" + + DeprecatedConfigurationConfig() { + super("test"); + + getContainer().addProperty(TEST_PROPERTY, String.class) + .setDescription("A test property") + .setDefaultValue("default value") + .addAlias("mock.property"); + } + + /** + * Should Liquibase execute + */ + boolean getTestProperty() { + return getContainer().getValue(TEST_PROPERTY, Boolean.class); + } + + DeprecatedConfigurationConfig setTestProperty(boolean value) { + getContainer().setValue(TEST_PROPERTY, value); + return this; + } + } + +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/GlobalConfigurationTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/GlobalConfigurationTest.groovy new file mode 100644 index 00000000000..47aaed9851b --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/GlobalConfigurationTest.groovy @@ -0,0 +1,12 @@ +package liquibase.configuration + +import spock.lang.Specification + +class GlobalConfigurationTest extends Specification { + + def "string properties are set correctly"() { + expect: + assert GlobalConfiguration.HEADLESS == "liquibase.headless" + assert GlobalConfiguration.SHOULD_RUN == "liquibase.shouldRun" + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/DeprecatedConfigurationValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/DeprecatedConfigurationValueProviderTest.groovy new file mode 100644 index 00000000000..37b68ef3412 --- /dev/null +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/DeprecatedConfigurationValueProviderTest.groovy @@ -0,0 +1,22 @@ +package liquibase.configuration.core + +import spock.lang.Specification + +class DeprecatedConfigurationValueProviderTest extends Specification { + + def "can set and clear values"() { + when: + DeprecatedConfigurationValueProvider.setData("test.key", "test value") + + then: + new DeprecatedConfigurationValueProvider().getProvidedValue("test.key").getValue() == "test value" + new DeprecatedConfigurationValueProvider().getProvidedValue("invalid.key") == null + + when: + DeprecatedConfigurationValueProvider.clearData() + + then: + new DeprecatedConfigurationValueProvider().getProvidedValue("test.key") == null + + } +} diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy index aa240f015e8..ee7311755e5 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy @@ -6,6 +6,15 @@ import spock.lang.Unroll class MapConfigurationValueProviderTest extends Specification { + def "empty values count as not set"() { + when: + def provider = new MapConfigurationValueProvider(["empty.property":""]) + + then: + provider.getProvidedValue("empty.property") == null + provider.getProvidedValue("empty-property") == null + } + @Unroll def "keyMatches"() { expect: @@ -26,31 +35,4 @@ class MapConfigurationValueProviderTest extends Specification { "single" | "invalid" | false "parent.child" | "parent" | false } - -// def other() { -// expect: -// def provider = new MapConfigurationValueProvider([ -// "lower" : "stored lower", -// "lower.dot" : "stored lower dot", -// "lower_under.dot": "stored lower under dot", -// "UPPER" : "stored upper", -// "UPPER.DOT" : "stored upper dot", -// "Mixed.Case" : "stored mixed case", -// ]) -// -// where: -// requestedKey | expectedValue -// -// "lower" | "saw lower" | "System property 'lower'" -// "LOWER" | "saw lower" | "System property 'lower'" -// "upper" | "saw upper" | "System property 'UPPER'" -// "UPPER" | "saw upper" | "System property 'UPPER'" -// "lower.underscore" | null | null -// "upper.dot" | "saw upper dot" | "System property 'UPPER.DOT'" -// "UPPER.DOT" | "saw upper dot" | "System property 'UPPER.DOT'" -// "LOWER.UNDER.dot" | null | null -// "LOWER_UNDER_DOT" | null | null -// "invalid" | null | null -// null | null | null -// } } diff --git a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java index 1ae682a991a..8b8175dc07a 100644 --- a/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java +++ b/liquibase-maven-plugin/src/main/java/org/liquibase/maven/plugins/AbstractLiquibaseChangeLogMojo.java @@ -4,6 +4,7 @@ import liquibase.Liquibase; import liquibase.Scope; +import liquibase.configuration.core.DeprecatedConfigurationValueProvider; import liquibase.database.Database; import liquibase.exception.LiquibaseException; import liquibase.hub.HubConfiguration; @@ -108,13 +109,13 @@ protected void performLiquibaseTask(Liquibase liquibase) throws LiquibaseExcepti // Store the Hub API key and URL for later use // if (StringUtil.isNotEmpty(hubApiKey)) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_API_KEY.getKey(), hubApiKey); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_API_KEY, hubApiKey); } if (StringUtil.isNotEmpty(hubUrl)) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), hubUrl); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_URL.getKey(), hubUrl); } if (StringUtil.isNotEmpty(hubMode)) { - System.setProperty(HubConfiguration.LIQUIBASE_HUB_MODE.getKey(), hubMode); + DeprecatedConfigurationValueProvider.setData(HubConfiguration.LIQUIBASE_HUB_MODE.getKey(), hubMode); } } From d753f698f1b58d626a2da0c8eb926103260d9010 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 23 Mar 2021 23:38:49 -0500 Subject: [PATCH 14/17] Improved actualKey/description from converted configuration values --- .../configuration/ConfigurationDefinition.java | 14 +++++++++----- .../liquibase/integration/commandline/Main.java | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java index 44dc0171238..3ede0085b1c 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java @@ -116,10 +116,10 @@ public ConfiguredValue<DataType> getCurrentConfiguredValue() { } } - final Object providedValue = configurationValue.getProvidedValue().getValue(); - final DataType finalValue = valueHandler.convert(providedValue); + final ProvidedValue providedValue = configurationValue.getProvidedValue(); + final DataType finalValue = valueHandler.convert(providedValue.getValue()); if (providedValue != finalValue) { - configurationValue.override(new ConvertedValueProvider<DataType>(finalValue).getProvidedValue(key)); + configurationValue.override(new ConvertedValueProvider<DataType>(finalValue, providedValue).getProvidedValue(key)); } return (ConfiguredValue<DataType>) configurationValue; @@ -310,9 +310,13 @@ public ProvidedValue getProvidedValue(String key) { private static final class ConvertedValueProvider<DataType> implements ConfigurationValueProvider { private final DataType value; + private final String originalSource; + private final String actualKey; - public ConvertedValueProvider(DataType value) { + public ConvertedValueProvider(DataType value, ProvidedValue originalProvidedValue) { this.value = value; + this.actualKey = originalProvidedValue.getActualKey(); + this.originalSource = originalProvidedValue.getSourceDescription(); } @Override @@ -322,7 +326,7 @@ public int getPrecedence() { @Override public ProvidedValue getProvidedValue(String key) { - return new ProvidedValue(key, key, value, "Parsed/processed value", this); + return new ProvidedValue(key, actualKey, value, originalSource, this); } } } diff --git a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java index 0ad9a66e6ad..d26322b6c7b 100644 --- a/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java +++ b/liquibase-core/src/main/java/liquibase/integration/commandline/Main.java @@ -328,7 +328,7 @@ public Integer run() throws Exception { if (!GlobalConfiguration.SHOULD_RUN.getCurrentValue()) { Scope.getCurrentScope().getUI().sendErrorMessage(( String.format(coreBundle.getString("did.not.run.because.param.was.set.to.false"), - GlobalConfiguration.SHOULD_RUN.getKey()))); + GlobalConfiguration.SHOULD_RUN.getCurrentConfiguredValue().getProvidedValue().getActualKey()))); return 0; } From f3ca634204329563c03246038aab01672c880f69 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Wed, 31 Mar 2021 11:36:11 -0500 Subject: [PATCH 15/17] - Removed unneeded MapConfigurationValueProvider top level class - Added ConfigurationValueProvider.getPrecedence javadoc LB-1222 --- ...AbstractMapConfigurationValueProvider.java | 6 ++++ .../ConfigurationValueProvider.java | 12 +++++++ .../DeprecatedConfigurationValueProvider.java | 10 +++--- .../core/MapConfigurationValueProvider.java | 30 ------------------ .../core/ScopeValueProvider.java | 2 +- .../core/SystemPropertyValueProvider.java | 2 +- .../MapConfigurationValueProviderTest.groovy | 31 ++++++++++++++++++- 7 files changed, 56 insertions(+), 37 deletions(-) delete mode 100644 liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java diff --git a/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java index 20f1649d987..527f169cee0 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/AbstractMapConfigurationValueProvider.java @@ -4,6 +4,12 @@ import java.util.Map; +/** + * Convenience class for {@link ConfigurationValueProvider}s that can collect the possible values into a Map. + * By default, it will follow standardized fuzzy-matching rules including being case insensitive, checking camelCase and kabob-case, etc. + * + * @see #keyMatches(String, String) + */ public abstract class AbstractMapConfigurationValueProvider extends AbstractConfigurationValueProvider { protected abstract Map<?, ?> getMap(); diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java index ffdc4765631..6ad4f468ba9 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationValueProvider.java @@ -7,6 +7,18 @@ public interface ConfigurationValueProvider { /** * Returns the precedence of values returned by this provider. Higher a provider with higher precedence overrides values from lower precedence providers. + * <br><br> + * Standard provider precedence: + * <ul> + * <li>400 {@link liquibase.configuration.core.ScopeValueProvider}</li> + * <li>350 {@link liquibase.configuration.core.DeprecatedConfigurationValueProvider}</li> + * <li>300: TODO JNDI attributes</li> + * <li>250: TODO Servlet Context</li> + * <li>200 {@link liquibase.configuration.core.SystemPropertyValueProvider}</li> + * <li>150 EnvironmentValueProvider</li> + * <li>100: TODO profile/context specific properties files</li> + * <li>50: TODO default properties files</li> + * </ul> */ int getPrecedence(); diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java index 08d2538b5bf..27d8a82abec 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/DeprecatedConfigurationValueProvider.java @@ -1,5 +1,6 @@ package liquibase.configuration.core; +import liquibase.configuration.AbstractMapConfigurationValueProvider; import liquibase.configuration.ConfigurationDefinition; import java.util.HashMap; @@ -12,17 +13,18 @@ * * @deprecated */ -public class DeprecatedConfigurationValueProvider extends MapConfigurationValueProvider { +public class DeprecatedConfigurationValueProvider extends AbstractMapConfigurationValueProvider { private static final Map<String, Object> data = new HashMap<>(); - public DeprecatedConfigurationValueProvider() { - super(data); + @Override + protected Map<?, ?> getMap() { + return data; } @Override public int getPrecedence() { - return 40; + return 350; } /** diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java deleted file mode 100644 index 1f99b6252a5..00000000000 --- a/liquibase-core/src/main/java/liquibase/configuration/core/MapConfigurationValueProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -package liquibase.configuration.core; - -import liquibase.configuration.AbstractMapConfigurationValueProvider; - -import java.util.Map; - -public class MapConfigurationValueProvider extends AbstractMapConfigurationValueProvider { - - private final Map<?, ?> map; - - - public MapConfigurationValueProvider(Map<?, ?> map) { - this.map = map; - } - - @Override - public int getPrecedence() { - return -1; - } - - @Override - protected String getSourceDescription() { - return "In memory map"; - } - - @Override - protected Map<?, ?> getMap() { - return map; - } -} diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java index 2fbd31ae6a7..589dc773864 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/ScopeValueProvider.java @@ -14,7 +14,7 @@ public class ScopeValueProvider extends AbstractConfigurationValueProvider { @Override public int getPrecedence() { - return 50; + return 400; } @Override diff --git a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java index b21ee0e9e34..3859faf2c72 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java +++ b/liquibase-core/src/main/java/liquibase/configuration/core/SystemPropertyValueProvider.java @@ -18,7 +18,7 @@ public class SystemPropertyValueProvider extends AbstractMapConfigurationValuePr @Override public int getPrecedence() { - return 20; + return 200; } @Override diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy index ee7311755e5..df513748fa5 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/core/MapConfigurationValueProviderTest.groovy @@ -1,9 +1,13 @@ package liquibase.configuration.core -import liquibase.configuration.core.MapConfigurationValueProvider +import liquibase.configuration.AbstractMapConfigurationValueProvider import spock.lang.Specification import spock.lang.Unroll +/** + * Tests the base {@link AbstractMapConfigurationValueProvider} logic. Can't call this + * AbstractMapConfigurationValueProviderTest or maven won't pick it up + */ class MapConfigurationValueProviderTest extends Specification { def "empty values count as not set"() { @@ -35,4 +39,29 @@ class MapConfigurationValueProviderTest extends Specification { "single" | "invalid" | false "parent.child" | "parent" | false } + + static class MapConfigurationValueProvider extends AbstractMapConfigurationValueProvider { + + private final Map<?, ?> map + + MapConfigurationValueProvider(Map<?, ?> map) { + this.map = map + } + + @Override + int getPrecedence() { + return -1 + } + + @Override + protected String getSourceDescription() { + return "Test map" + } + + @Override + protected Map<?, ?> getMap() { + return map + } + } + } From 02a3949e72e23e35d3b8933ed23f911f53d96aee Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Wed, 31 Mar 2021 14:00:49 -0500 Subject: [PATCH 16/17] Added fine-level logging for configuration lookup LB-1222 --- .../ConfigurationDefinition.java | 21 ++++++++++++ .../configuration/LiquibaseConfiguration.java | 34 +++++++++++++++++-- .../ConfigurationDefinitionTest.groovy | 21 ++++++++++-- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java index 3ede0085b1c..831eb692fb0 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java +++ b/liquibase-core/src/main/java/liquibase/configuration/ConfigurationDefinition.java @@ -190,6 +190,27 @@ public int hashCode() { return Objects.hash(key); } + /** + * Return true if the given key matches this definition. + */ + public boolean equalsKey(String key) { + if (key == null) { + return false; + } + + if (getKey().equalsIgnoreCase(key)) { + return true; + } + + for (String alias : getAliasKeys()) { + if (alias.equalsIgnoreCase(key)) { + return true; + } + } + + return false; + } + /** * Used to construct new {@link ConfigurationDefinition} instances. */ diff --git a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java index e943c5b6269..ffe4b2c3c2f 100644 --- a/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/configuration/LiquibaseConfiguration.java @@ -23,6 +23,13 @@ public class LiquibaseConfiguration implements SingletonObject { private final SortedSet<ConfigurationValueProvider> configurationValueProviders; private final SortedSet<ConfigurationDefinition> definitions = new TreeSet<>(); + /** + * 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<String, String> lastLoggedKeyValues = new HashMap<>(); + protected LiquibaseConfiguration() { configurationValueProviders = new TreeSet<>((o1, o2) -> { if (o1.getPrecedence() < o2.getPrecedence()) { @@ -90,8 +97,8 @@ public <T extends ConfigurationContainer> T getConfiguration(Class<T> type) { * * @return the value for the key, or null if not configured. */ - public ConfiguredValue getCurrentConfiguredValue(String key) { - ConfiguredValue details = new ConfiguredValue(key); + public ConfiguredValue<?> getCurrentConfiguredValue(String key) { + ConfiguredValue<?> details = new ConfiguredValue<>(key); for (ConfigurationValueProvider provider : configurationValueProviders) { final ProvidedValue providerValue = provider.getProvidedValue(key); @@ -101,6 +108,29 @@ public ConfiguredValue getCurrentConfiguredValue(String key) { } } + final String foundValue = String.valueOf(details.getValue()); + if (!foundValue.equals(lastLoggedKeyValues.get(key))) { + lastLoggedKeyValues.put(key, foundValue); + + //avoid infinite loop when logging is getting set up + StringBuilder logMessage = new StringBuilder("Found '" + key + "' configuration of '"+foundValue+"'"); + boolean foundFirstValue = false; + for (ProvidedValue providedValue : details.getProvidedValues()) { + logMessage.append("\n "); + if (foundFirstValue) { + logMessage.append("Overrides "); + } + logMessage.append(providedValue.describe()); + final Object value = providedValue.getValue(); + if (value != null) { + logMessage.append(" of '").append(providedValue.getValue()).append("'"); + } + foundFirstValue = true; + } + + Scope.getCurrentScope().getLog(getClass()).fine(logMessage.toString()); + } + return details; } diff --git a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy index db77b4dd503..56de95f0c3f 100644 --- a/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/configuration/ConfigurationDefinitionTest.groovy @@ -24,7 +24,7 @@ class ConfigurationDefinitionTest extends Specification { "test" | "invalid-key" | "valid" | "Invalid key format: test.invalid-key" "invalid-prefix" | "invalid-key" | "valid" | "Invalid prefix format: invalid-prefix" "invalid-prefix" | "validValue" | "valid" | "Invalid prefix format: invalid-prefix" - "validPrefix" | "validValue" | "invalid-alias" | "Invalid alias format: invalid-alias" + "validPrefix" | "validValue" | "invalid-alias" | "Invalid alias format: invalid-alias" } def "Can build and register"() { @@ -66,8 +66,8 @@ class ConfigurationDefinitionTest extends Specification { ConfigurationDefinition.wasDefaultValueUsed(currentValue) == defaultValueUsed where: - key | defaultValue | expectedValue | expectedSource | defaultValueUsed - "currentValue" | "Default Value" | "From scope" | "Scoped value 'test.currentValue'" | false + key | defaultValue | expectedValue | expectedSource | defaultValueUsed + "currentValue" | "Default Value" | "From scope" | "Scoped value 'test.currentValue'" | false "unsetValue" | "Configured Default" | "Configured Default" | "Default value 'test.unsetValue'" | true "unsetValue" | null | null | "No configuration or default value found 'test.unsetValue'" | false @@ -178,4 +178,19 @@ class ConfigurationDefinitionTest extends Specification { definition1.hashCode() == dupeDefinition1.hashCode() } + + @Unroll + def equalsKey() { + expect: + liquibase.GlobalConfiguration.SHOULD_RUN.equalsKey(input) == expected + + where: + input | expected + "liquibase.shouldRun" | true + "liquibase.otherValue" | false + "liquibase.SHOULDRUN" | true + "should.run" | true + "SHOULD.RUN" | true + null | false + } } From c0d97bcd013cdf8e49253e891bf4f7ae3edb9141 Mon Sep 17 00:00:00 2001 From: Nathan Voxland <nathan@voxland.net> Date: Tue, 6 Apr 2021 11:29:25 -0500 Subject: [PATCH 17/17] Standardized naming of "changelog" and "changeset" as one word in configuration properties LB-1222 --- .../java/liquibase/GlobalConfiguration.java | 22 ++++++++++++------- .../main/java/liquibase/util/StringUtil.java | 7 ++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java index 422cff325a2..efd547b8fcb 100644 --- a/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java +++ b/liquibase-core/src/main/java/liquibase/GlobalConfiguration.java @@ -38,22 +38,26 @@ public class GlobalConfiguration implements AutoloadedConfigurations { .addAliasKey("should.run") .build(); - DATABASECHANGELOG_TABLE_NAME = builder.define("databaseChangeLogTableName", String.class) + DATABASECHANGELOG_TABLE_NAME = builder.define("databaseChangelogTableName", String.class) + .addAliasKey("liquibase.databaseChangeLogTableName") .setDescription("Name of table to use for tracking change history") .setDefaultValue("DATABASECHANGELOG") .build(); - DATABASECHANGELOGLOCK_TABLE_NAME = builder.define("databaseChangeLogLockTableName", String.class) + DATABASECHANGELOGLOCK_TABLE_NAME = builder.define("databaseChangelogLockTableName", String.class) + .addAliasKey("liquibase.databaseChangeLogLockTableName") .setDescription("Name of table to use for tracking concurrent Liquibase usage") .setDefaultValue("DATABASECHANGELOGLOCK") .build(); - CHANGELOGLOCK_WAIT_TIME = builder.define("changeLogLockWaitTimeInMinutes", Long.class) + CHANGELOGLOCK_WAIT_TIME = builder.define("changelogLockWaitTimeInMinutes", Long.class) + .addAliasKey("liquibase.changeLogLockWaitTimeInMinutes") .setDescription("Number of minutes to wait for the changelog lock to be available before giving up") .setDefaultValue(5L) .build(); - CHANGELOGLOCK_POLL_RATE = builder.define("changeLogLockPollRate", Long.class) + CHANGELOGLOCK_POLL_RATE = builder.define("changelogLockPollRate", Long.class) + .addAliasKey("liquibase.changeLogLockPollRate") .setDescription("Number of seconds wait between checks to the changelog lock when it is locked") .setDefaultValue(10L) .build(); @@ -88,8 +92,9 @@ public class GlobalConfiguration implements AutoloadedConfigurations { .setDefaultValue(true) .build(); - GENERATE_CHANGESET_CREATED_VALUES = builder.define("generateChangeSetCreatedValues", Boolean.class) - .setDescription("Should Liquibase include a 'created' attribute in diff/generateChangeLog changeSets with" + + GENERATE_CHANGESET_CREATED_VALUES = builder.define("generateChangesetCreatedValues", Boolean.class) + .addAliasKey("liquibase.generateChangeSetCreatedValues") + .setDescription("Should Liquibase include a 'created' attribute in diff/generateChangelog changesets with" + " the current datetime") .setDefaultValue(false) .build(); @@ -110,8 +115,9 @@ public class GlobalConfiguration implements AutoloadedConfigurations { .build(); - GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION = builder.define("generatedChangeSetIdsContainsDescription", Boolean.class) - .setDescription("Should Liquibase include the change description in the id when generating changeSets?") + GENERATED_CHANGESET_IDS_INCLUDE_DESCRIPTION = builder.define("generatedChangesetIdsContainsDescription", Boolean.class) + .addAliasKey("liquibase.generatedChangeSetIdsContainsDescription") + .setDescription("Should Liquibase include the change description in the id when generating changesets?") .setDefaultValue(false) .build(); diff --git a/liquibase-core/src/main/java/liquibase/util/StringUtil.java b/liquibase-core/src/main/java/liquibase/util/StringUtil.java index 8dc33ebbdec..2f8e05ba665 100644 --- a/liquibase-core/src/main/java/liquibase/util/StringUtil.java +++ b/liquibase-core/src/main/java/liquibase/util/StringUtil.java @@ -503,6 +503,13 @@ public static String randomIdentifer(int len) { return sb.toString(); } + /** + * Converts a camelCase string to a kabob-case one + */ + public static String toKabobCase(String string) { + return string.replaceAll("([A-Z])", "-$1").toLowerCase(); + } + public interface StringUtilFormatter<Type> { String toString(Type obj); }