From b99321eacd6dd4a0ba0984c6ee1829f81a0866f9 Mon Sep 17 00:00:00 2001 From: Dieppa on the rocks Date: Wed, 29 Jun 2022 18:58:45 +0100 Subject: [PATCH] Without app jar standalone (#21) --- .../mongodb-springdata-v2-wrapper/pom.xml | 87 ++++++++++ .../v2/DateToZonedDateTimeConverter.java | 19 +++ .../v2/SpringDataMongoV2DriverProvider.java | 57 +++++++ .../v2/ZonedDateTimeToDateConverter.java | 17 ++ .../mongodb-springdata-v3-wrapper/pom.xml | 87 ++++++++++ .../v3/DateToZonedDateTimeConverter.java | 19 +++ .../v3/SpringDataMongoV3DriverProvider.java | 59 +++++++ .../v3/ZonedDateTimeToDateConverter.java | 17 ++ driver-wrappers/pom.xml | 20 +++ mongock-cli-core/pom.xml | 2 + .../io/mongock/cli/core/CliCoreRunner.java | 15 ++ mongock-cli-springboot/pom.xml | 1 + mongock-cli-util/pom.xml | 7 + .../io/mongock/cli/util/CliConfiguration.java | 157 ++++++++++++++++++ .../cli/util/ConnectionDriverProvider.java | 7 + .../io/mongock/cli/util/DriverWrapper.java | 44 +++++ .../mongock/cli/util/MongockDefaultApp.java | 12 ++ .../RunnerBuilderProviderConfigurable.java | 5 + .../io/mongock/cli/util/logger/CliLogger.java | 13 +- .../cli/util/logger/CliLoggerFactory.java | 8 + mongock-cli/pom.xml | 54 +++++- .../io/mongock/cli/wrapper/MongockCli.java | 81 +++++---- .../cli/wrapper/argument/Argument.java | 58 +++++++ .../cli/wrapper/argument/ArgumentsHolder.java | 95 +++++++++++ .../cli/wrapper/jars/CliClassLoader.java | 83 +++++++++ .../java/io/mongock/cli/wrapper/jars/Jar.java | 82 +++++++++ .../mongock/cli/wrapper/jars/JarFactory.java | 50 ++++++ .../cli/wrapper/launcher/LauncherCliJar.java | 123 ++++++-------- .../cli/wrapper/launcher/LauncherDefault.java | 104 ++++-------- .../wrapper/launcher/LauncherSpringboot.java | 36 +--- .../wrapper/launcher/LauncherStandalone.java | 61 ++----- .../io/mongock/cli/wrapper/util/ArgsUtil.java | 81 --------- .../cli/wrapper/util/ClassLoaderUtil.java | 47 ------ .../io/mongock/cli/wrapper/util/JarUtil.java | 45 ----- .../mongock/cli/wrapper/util/Parameters.java | 13 -- .../src/main/resources/linux_script_template | 6 +- mongock-default-app-professional/pom.xml | 93 +++++++++++ .../professional/DefaultProfessionalApp.java | 19 +++ .../cli/app/professional/DriverFactory.java | 28 ++++ ...RunnerBuilderProviderProfessionalImpl.java | 35 ++++ .../events/MongockEventListener.java | 20 +++ mongock-default-app/pom.xml | 97 +++++++++++ .../java/io/mongock/cli/app/DefaultApp.java | 18 ++ .../io/mongock/cli/app/DriverFactory.java | 28 ++++ .../cli/app/RunnerBuilderProviderImpl.java | 37 +++++ .../cli/app/events/MongockEventListener.java | 20 +++ pom.xml | 29 ++-- 47 files changed, 1638 insertions(+), 458 deletions(-) create mode 100644 driver-wrappers/mongodb-springdata-v2-wrapper/pom.xml create mode 100644 driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/DateToZonedDateTimeConverter.java create mode 100644 driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/SpringDataMongoV2DriverProvider.java create mode 100644 driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/ZonedDateTimeToDateConverter.java create mode 100644 driver-wrappers/mongodb-springdata-v3-wrapper/pom.xml create mode 100644 driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/DateToZonedDateTimeConverter.java create mode 100644 driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/SpringDataMongoV3DriverProvider.java create mode 100644 driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/ZonedDateTimeToDateConverter.java create mode 100644 driver-wrappers/pom.xml create mode 100644 mongock-cli-util/src/main/java/io/mongock/cli/util/CliConfiguration.java create mode 100644 mongock-cli-util/src/main/java/io/mongock/cli/util/ConnectionDriverProvider.java create mode 100644 mongock-cli-util/src/main/java/io/mongock/cli/util/DriverWrapper.java create mode 100644 mongock-cli-util/src/main/java/io/mongock/cli/util/MongockDefaultApp.java create mode 100644 mongock-cli-util/src/main/java/io/mongock/cli/util/RunnerBuilderProviderConfigurable.java create mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/Argument.java create mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/ArgumentsHolder.java create mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/CliClassLoader.java create mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/Jar.java create mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/JarFactory.java delete mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ArgsUtil.java delete mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ClassLoaderUtil.java delete mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/util/JarUtil.java delete mode 100644 mongock-cli/src/main/java/io/mongock/cli/wrapper/util/Parameters.java create mode 100644 mongock-default-app-professional/pom.xml create mode 100644 mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DefaultProfessionalApp.java create mode 100644 mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DriverFactory.java create mode 100644 mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/RunnerBuilderProviderProfessionalImpl.java create mode 100644 mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/events/MongockEventListener.java create mode 100644 mongock-default-app/pom.xml create mode 100644 mongock-default-app/src/main/java/io/mongock/cli/app/DefaultApp.java create mode 100644 mongock-default-app/src/main/java/io/mongock/cli/app/DriverFactory.java create mode 100644 mongock-default-app/src/main/java/io/mongock/cli/app/RunnerBuilderProviderImpl.java create mode 100644 mongock-default-app/src/main/java/io/mongock/cli/app/events/MongockEventListener.java diff --git a/driver-wrappers/mongodb-springdata-v2-wrapper/pom.xml b/driver-wrappers/mongodb-springdata-v2-wrapper/pom.xml new file mode 100644 index 0000000..c21b0c2 --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v2-wrapper/pom.xml @@ -0,0 +1,87 @@ + + + + driver-wrappers + io.mongock + 5.0.28-SNAPSHOT + + 4.0.0 + + mongodb-springdata-v2-wrapper + + + 4.3.3 + 4.4.1 + 2.6.3 + + + + + io.mongock + mongock-cli-util + ${project.version} + + + + io.mongock + mongodb-springdata-v2-driver + ${mongock.community.version} + + + + + org.springframework.data + spring-data-mongodb + 2.2.13.RELEASE + + + org.mongodb + mongodb-driver-sync + 3.11.2 + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + shade + + + false + + + + + + + + + + + \ No newline at end of file diff --git a/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/DateToZonedDateTimeConverter.java b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/DateToZonedDateTimeConverter.java new file mode 100644 index 0000000..e350afb --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/DateToZonedDateTimeConverter.java @@ -0,0 +1,19 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v2; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +@ReadingConverter +public enum DateToZonedDateTimeConverter implements Converter { + INSTANCE; + + @Override + public ZonedDateTime convert(Date source) { + return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault()); + + } +} diff --git a/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/SpringDataMongoV2DriverProvider.java b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/SpringDataMongoV2DriverProvider.java new file mode 100644 index 0000000..ecc348d --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/SpringDataMongoV2DriverProvider.java @@ -0,0 +1,57 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v2; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.ConnectionDriverProvider; +import io.mongock.driver.api.driver.ConnectionDriver; +import io.mongock.driver.mongodb.springdata.v2.SpringDataMongoV2Driver; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; + +import java.util.ArrayList; +import java.util.List; + +public class SpringDataMongoV2DriverProvider implements ConnectionDriverProvider { + + + @Override + public ConnectionDriver getDriver(CliConfiguration configuration) { + + + MongoTemplate mongoTemplate = getMongoTemplate(configuration.getDatabaseUrl(), configuration.getDatabaseName()); + + // Driver + SpringDataMongoV2Driver driver = SpringDataMongoV2Driver.withDefaultLock(mongoTemplate); + driver.enableTransaction(); + + return driver; + } + + /** + * Main MongoTemplate for Mongock to work. + */ + private static MongoTemplate getMongoTemplate(String connectionString, String dbName) { + + MongoClient mongoClient = MongoClients.create(connectionString); + MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, dbName); + + // Custom converters to map ZonedDateTime. + MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter(); + mongoMapping.setCustomConversions(customConversions()); + mongoMapping.afterPropertiesSet(); + + return mongoTemplate; + } + + + private static MongoCustomConversions customConversions() { + List> converters = new ArrayList<>(); + converters.add(DateToZonedDateTimeConverter.INSTANCE); + converters.add(ZonedDateTimeToDateConverter.INSTANCE); + return new MongoCustomConversions(converters); + } + +} diff --git a/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/ZonedDateTimeToDateConverter.java b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/ZonedDateTimeToDateConverter.java new file mode 100644 index 0000000..c2edd95 --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v2-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v2/ZonedDateTimeToDateConverter.java @@ -0,0 +1,17 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v2; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.WritingConverter; + +import java.time.ZonedDateTime; +import java.util.Date; + +@WritingConverter +public enum ZonedDateTimeToDateConverter implements Converter { + INSTANCE; + + @Override + public Date convert(ZonedDateTime source) { + return source == null ? null : Date.from(source.toInstant()); + } +} diff --git a/driver-wrappers/mongodb-springdata-v3-wrapper/pom.xml b/driver-wrappers/mongodb-springdata-v3-wrapper/pom.xml new file mode 100644 index 0000000..791097d --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v3-wrapper/pom.xml @@ -0,0 +1,87 @@ + + + + driver-wrappers + io.mongock + 5.0.28-SNAPSHOT + + 4.0.0 + + mongodb-springdata-v3-wrapper + + + 4.3.3 + 4.4.1 + 2.6.3 + + + + + + io.mongock + mongock-cli-util + ${project.version} + + + + + io.mongock + mongodb-springdata-v3-driver + ${mongock.community.version} + + + + + + org.mongodb + mongodb-driver-sync + 4.4.1 + + + org.springframework.data + spring-data-mongodb + 3.3.1 + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + shade + + + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/DateToZonedDateTimeConverter.java b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/DateToZonedDateTimeConverter.java new file mode 100644 index 0000000..6351aa8 --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/DateToZonedDateTimeConverter.java @@ -0,0 +1,19 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v3; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +@ReadingConverter +public enum DateToZonedDateTimeConverter implements Converter { + INSTANCE; + + @Override + public ZonedDateTime convert(Date source) { + return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault()); + + } +} diff --git a/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/SpringDataMongoV3DriverProvider.java b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/SpringDataMongoV3DriverProvider.java new file mode 100644 index 0000000..4a028ce --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/SpringDataMongoV3DriverProvider.java @@ -0,0 +1,59 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v3; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.ConnectionDriverProvider; +import io.mongock.driver.api.driver.ConnectionDriver; +import io.mongock.driver.mongodb.springdata.v3.SpringDataMongoV3Driver; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.convert.MappingMongoConverter; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; + +import java.util.ArrayList; +import java.util.List; + +public class SpringDataMongoV3DriverProvider implements ConnectionDriverProvider { + + + @Override + public ConnectionDriver getDriver(CliConfiguration configuration) { + + + MongoTemplate mongoTemplate = getMongoTemplate(configuration.getDatabaseUrl(), configuration.getDatabaseName()); + + // Driver + SpringDataMongoV3Driver driver = SpringDataMongoV3Driver.withDefaultLock(mongoTemplate); + driver.enableTransaction(); + + return driver; + } + + /** + * Main MongoTemplate for Mongock to work. + */ + private static MongoTemplate getMongoTemplate(String connectionString, String dbName) { + + MongoClient mongoClient = MongoClients.create(connectionString); + MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, dbName); + + // Custom converters to map ZonedDateTime. + MappingMongoConverter mongoMapping = (MappingMongoConverter) mongoTemplate.getConverter(); + mongoMapping.setCustomConversions(customConversions()); + mongoMapping.afterPropertiesSet(); + + return mongoTemplate; + } + + + + private static MongoCustomConversions customConversions() { + List> converters = new ArrayList<>(); + converters.add(DateToZonedDateTimeConverter.INSTANCE); + converters.add(ZonedDateTimeToDateConverter.INSTANCE); + return new MongoCustomConversions(converters); + } + + +} diff --git a/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/ZonedDateTimeToDateConverter.java b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/ZonedDateTimeToDateConverter.java new file mode 100644 index 0000000..3158965 --- /dev/null +++ b/driver-wrappers/mongodb-springdata-v3-wrapper/src/main/java/io/mongock/driver/cli/wrapper/mongodb/springdata/v3/ZonedDateTimeToDateConverter.java @@ -0,0 +1,17 @@ +package io.mongock.driver.cli.wrapper.mongodb.springdata.v3; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.WritingConverter; + +import java.time.ZonedDateTime; +import java.util.Date; + +@WritingConverter +public enum ZonedDateTimeToDateConverter implements Converter { + INSTANCE; + + @Override + public Date convert(ZonedDateTime source) { + return source == null ? null : Date.from(source.toInstant()); + } +} diff --git a/driver-wrappers/pom.xml b/driver-wrappers/pom.xml new file mode 100644 index 0000000..cdb062c --- /dev/null +++ b/driver-wrappers/pom.xml @@ -0,0 +1,20 @@ + + + + mongock-cli-project + io.mongock + 5.0.28-SNAPSHOT + + 4.0.0 + + driver-wrappers + pom + + mongodb-springdata-v3-wrapper + mongodb-springdata-v2-wrapper + + + + \ No newline at end of file diff --git a/mongock-cli-core/pom.xml b/mongock-cli-core/pom.xml index a6c2a8f..5993408 100644 --- a/mongock-cli-core/pom.xml +++ b/mongock-cli-core/pom.xml @@ -27,10 +27,12 @@ io.mongock mongock-runner-core + ${mongock.community.version} io.mongock.professional mongock-runner-common + ${mongock.pro.version} provided true diff --git a/mongock-cli-core/src/main/java/io/mongock/cli/core/CliCoreRunner.java b/mongock-cli-core/src/main/java/io/mongock/cli/core/CliCoreRunner.java index c17dbf3..bd2a4e1 100644 --- a/mongock-cli-core/src/main/java/io/mongock/cli/core/CliCoreRunner.java +++ b/mongock-cli-core/src/main/java/io/mongock/cli/core/CliCoreRunner.java @@ -1,5 +1,6 @@ package io.mongock.cli.core; +import io.mongock.api.exception.MongockException; import io.mongock.cli.core.commands.MainCommand; import io.mongock.cli.core.commands.migrate.MigrateCommand; import io.mongock.cli.core.commands.undo.UndoCommand; @@ -10,6 +11,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; + +import io.mongock.runner.core.builder.RunnerBuilderProvider; import picocli.CommandLine; import static io.mongock.cli.core.commands.CommandName.MIGRATE; @@ -32,6 +35,7 @@ public static class Builder { private final Set commands = new HashSet<>(); private IFactory factory; private RunnerBuilder builder; + private RunnerBuilderProvider builderProvider; private Builder() { } @@ -51,7 +55,18 @@ public Builder runnerBuilder(RunnerBuilder builder) { return this; } + public Builder runnerBuilderProvider(RunnerBuilderProvider builderProvider) { + this.builderProvider = builderProvider; + return this; + } + public CommandLine build() { + if(builder == null) { + if(builderProvider == null) { + throw new MongockException("Not injected RunnerBuilder nor RunnerBuilderProvider"); + } + builder = builderProvider.getBuilder(); + } addCommand(UNDO , new UndoCommand(builder)); addCommand(MIGRATE, new MigrateCommand(builder)); addCommand(STATE, new StateCommand(builder)); diff --git a/mongock-cli-springboot/pom.xml b/mongock-cli-springboot/pom.xml index ea0370c..bbfb709 100644 --- a/mongock-cli-springboot/pom.xml +++ b/mongock-cli-springboot/pom.xml @@ -32,6 +32,7 @@ io.mongock mongock-runner-core + ${mongock.community.version} diff --git a/mongock-cli-util/pom.xml b/mongock-cli-util/pom.xml index 4bafe7c..672159d 100644 --- a/mongock-cli-util/pom.xml +++ b/mongock-cli-util/pom.xml @@ -18,6 +18,13 @@ + + + io.mongock + mongock-driver-api + ${mongock.community.version} + + com.diogonunes JColor diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/CliConfiguration.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/CliConfiguration.java new file mode 100644 index 0000000..03a272d --- /dev/null +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/CliConfiguration.java @@ -0,0 +1,157 @@ +package io.mongock.cli.util; + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +public class CliConfiguration { + + private String driverName; + + private String databaseUrl; + + private String databaseName; + + + private String jarsLibFolder; + + private String cliVersion; + + private String scanPackage; + + private String licenseKey; + + private String userApplication; + + private String userChangeUnit; + + public static Builder fileBuilder() { + return new Builder(); + } + + public CliConfiguration setScanPackage(String scanPackage) { + this.scanPackage = scanPackage; + return this; + } + + public String getScanPackage() { + return scanPackage; + } + + + public CliConfiguration setUserAppIfNotNull(String userApplication) { + this.userApplication = userApplication != null ? userApplication : this.userApplication; + return this; + } + + public Optional getUserApplication() { + return Optional.ofNullable(userApplication); + } + + public Optional getUserChangeUnit() { + return Optional.ofNullable(userChangeUnit); + } + + public CliConfiguration setUserChangeUnitIfNotNull(String userChangeUnit) { + this.userChangeUnit = userChangeUnit != null ? userChangeUnit : this.userChangeUnit; + return this; + } + + public CliConfiguration setJarsLibFolder(String jarsLibFolder) { + this.jarsLibFolder = jarsLibFolder; + return this; + } + + public CliConfiguration setCliVersion(String cliVersion) { + this.cliVersion = cliVersion; + return this; + } + + + public DriverWrapper getDriverWrapper() { + return DriverWrapper.getDriver(driverName) + .setJarsLibFolder(jarsLibFolder) + .setVersion(cliVersion); + } + + public CliConfiguration setDriverNameIfNotNull(String driverName) { + this.driverName = driverName != null ? driverName : this.driverName; + return this; + } + + public Optional getLicenseKey() { + return Optional.ofNullable(licenseKey); + } + + public CliConfiguration setLicenseKeyIfNotNull(String licenseKey) { + this.licenseKey = licenseKey != null ? licenseKey : this.licenseKey; + return this; + } + + public String getDatabaseUrl() { + return databaseUrl; + } + + public CliConfiguration setDatabaseUrl(String databaseUrl) { + this.databaseUrl = databaseUrl != null ? databaseUrl : this.databaseUrl; + return this; + } + + public String getDatabaseName() { + return databaseName; + } + + public CliConfiguration setDatabaseName(String databaseName) { + this.databaseName = databaseName != null ? databaseName : this.databaseName; + return this; + } + + public static class Builder { + + private String configFile; + + private Builder() { + } + + + public Builder setConfigFile(String configFile) { + this.configFile = configFile; + return this; + } + + + public CliConfiguration build() { + try { + CliConfiguration config = new CliConfiguration(); + for (String configLine : Files.readAllLines(Paths.get(configFile))) { + if (configLine != null && !configLine.isEmpty()) { + String[] parts = configLine.split("="); + setConfigValue(config, parts[0], parts[1]); + } + } + return config; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private CliConfiguration setConfigValue(CliConfiguration config, String propertyName, String propertyValue) { + switch (propertyName.toLowerCase()) { + case "licensekey": + return config.setLicenseKeyIfNotNull(propertyValue); + case "scanpackage": + return config.setScanPackage(propertyValue); + case "driver": + return config.setDriverNameIfNotNull(propertyValue); + case "databaseurl": + return config.setDatabaseUrl(propertyValue); + case "databasename": + return config.setDatabaseName(propertyValue); + + default: + return config;//IGNORED + } + } + + } +} diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/ConnectionDriverProvider.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/ConnectionDriverProvider.java new file mode 100644 index 0000000..e9e22b0 --- /dev/null +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/ConnectionDriverProvider.java @@ -0,0 +1,7 @@ +package io.mongock.cli.util; + +import io.mongock.driver.api.driver.ConnectionDriver; + +public interface ConnectionDriverProvider { + ConnectionDriver getDriver(CliConfiguration configuration); +} diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/DriverWrapper.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/DriverWrapper.java new file mode 100644 index 0000000..d46560b --- /dev/null +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/DriverWrapper.java @@ -0,0 +1,44 @@ +package io.mongock.cli.util; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public enum DriverWrapper { + MONGODB_SPRING_DATA_V3("%s/mongodb-springdata-v3-wrapper-%s.jar"), + MONGODB_SPRING_DATA_V2("%s/mongodb-springdata-v2-wrapper-%s.jar"); + + private final String jarTemplate; + private String jarsLibFolder; + private String version; + + DriverWrapper(String template) { + this.jarTemplate = template; + } + + public DriverWrapper setJarsLibFolder(String jarsLibFolder) { + this.jarsLibFolder = jarsLibFolder; + return this; + } + + public DriverWrapper setVersion(String version) { + this.version = version; + return this; + } + + public String getJarPath() { + return String.format(jarTemplate, jarsLibFolder, version); + } + + public static DriverWrapper getDriver(String driverName) { + return valueOf(driverName.toUpperCase()); + } + + public static String getAllDriverNames(String separator) { + return Arrays.stream(values()) + .map(DriverWrapper::name) + .collect(Collectors.joining(separator)); + + } + + +} diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/MongockDefaultApp.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/MongockDefaultApp.java new file mode 100644 index 0000000..f853c3a --- /dev/null +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/MongockDefaultApp.java @@ -0,0 +1,12 @@ +package io.mongock.cli.util; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface MongockDefaultApp { +} diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/RunnerBuilderProviderConfigurable.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/RunnerBuilderProviderConfigurable.java new file mode 100644 index 0000000..ca71678 --- /dev/null +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/RunnerBuilderProviderConfigurable.java @@ -0,0 +1,5 @@ +package io.mongock.cli.util; + +public interface RunnerBuilderProviderConfigurable { + void setConfiguration(CliConfiguration configuration); +} diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLogger.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLogger.java index 1e761b9..c2962da 100644 --- a/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLogger.java +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLogger.java @@ -37,6 +37,7 @@ default void trace(String format, Object... arguments) { print(TRACE, format, arguments); } + default void debug(String format, Object... arguments) { print(DEBUG, format, arguments); } @@ -49,14 +50,24 @@ default void warn(String format, Object... arguments) { print(WARN, format, arguments); } -// void warn(String format, Throwable th); + + + default void warn(Throwable ex) { + print(WARN, ex); + } default void error(String format, Object... arguments) { print(ERROR, format, arguments); } + default void error(Throwable ex) { + print(ERROR, ex); + } + // void error(String format, Throwable th); void print(Level level, String format, Object... arguments); + + void print(Level level, Throwable ex); } diff --git a/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLoggerFactory.java b/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLoggerFactory.java index 307707a..d4aeb1f 100644 --- a/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLoggerFactory.java +++ b/mongock-cli-util/src/main/java/io/mongock/cli/util/logger/CliLoggerFactory.java @@ -78,6 +78,14 @@ public void print(Level level, String format, Object... arguments) { } } + @Override + public void print(Level level, Throwable ex) { + if(shouldLog(level)) { + ex.printStackTrace(level.isGreaterEqual(ERROR) ? System.err : System.out); + } + + } + private String getFormattedClassName(String classname) { String finalClassName = className; diff --git a/mongock-cli/pom.xml b/mongock-cli/pom.xml index 24cd445..58d5a90 100644 --- a/mongock-cli/pom.xml +++ b/mongock-cli/pom.xml @@ -15,6 +15,7 @@ 1.8 1.8 1.8 + @@ -33,20 +34,66 @@ mongock-cli-util ${project.version} + + + io.mongock + mongock-default-app + ${project.version} + + + + io.mongock + mongock-default-app-professional + ${project.version} + io.mongock mongock-api + ${mongock.community.version} + + io.mongock mongock-runner-core + ${mongock.community.version} + + + + + + io.mongock + mongock-standalone + ${mongock.community.version} + + io.mongock.professional + mongock-standalone + ${mongock.pro.version} + + + + + + io.mongock + mongodb-springdata-v3-wrapper + ${project.version} + + + + io.mongock + mongodb-springdata-v2-wrapper + ${project.version} + + + + org.slf4j slf4j-api - 1.7.32 + ${slf4j.version} org.springframework.boot @@ -111,6 +158,7 @@ + org.apache.maven.plugins maven-shade-plugin @@ -121,8 +169,12 @@ shade + false + *:* diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/MongockCli.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/MongockCli.java index 791d198..6efd5ff 100644 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/MongockCli.java +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/MongockCli.java @@ -1,63 +1,80 @@ package io.mongock.cli.wrapper; +import io.mongock.cli.util.CliConfiguration; import io.mongock.cli.util.banner.Banner; import io.mongock.cli.util.logger.CliLogger; import io.mongock.cli.util.logger.CliLoggerFactory; +import io.mongock.cli.wrapper.argument.Argument; +import io.mongock.cli.wrapper.argument.ArgumentsHolder; +import io.mongock.cli.wrapper.jars.JarFactory; import io.mongock.cli.wrapper.launcher.LauncherCliJar; -import io.mongock.cli.wrapper.util.ArgsUtil; import java.util.stream.Stream; import static io.mongock.cli.util.logger.CliLogger.Level.INFO; -import static io.mongock.cli.wrapper.util.ArgsUtil.getCleanArgs; -import static io.mongock.cli.wrapper.util.Parameters.APP_JAR_ARG_LONG; -import static io.mongock.cli.wrapper.util.Parameters.APP_JAR_ARG_SHORT; -import static io.mongock.cli.wrapper.util.Parameters.CLI_CORE_JAR_ARG; -import static io.mongock.cli.wrapper.util.Parameters.CLI_SPRING_JAR_ARG; -import static io.mongock.cli.wrapper.util.Parameters.LOG_LEVEL_ARG; -import static io.mongock.cli.wrapper.util.Parameters.MONGOCK_CORE_JAR_ARG; +import static io.mongock.cli.wrapper.argument.Argument.CLI_VERSION; +import static io.mongock.cli.wrapper.argument.Argument.COMMUNITY_VERSION; +import static io.mongock.cli.wrapper.argument.Argument.DRIVER; +import static io.mongock.cli.wrapper.argument.Argument.LICENSE_KEY; +import static io.mongock.cli.wrapper.argument.Argument.LOG_LEVEL; +import static io.mongock.cli.wrapper.argument.Argument.PROFESSIONAL_VERSION; +import static io.mongock.cli.wrapper.argument.Argument.USER_APP_JAR; +import static io.mongock.cli.wrapper.argument.Argument.USER_CHANGE_UNIT_JAR; +import static io.mongock.cli.wrapper.argument.Argument.USER_CONFIGURATION; public class MongockCli { - private static final CliLogger logger = CliLoggerFactory.getLogger(MongockCli.class); - private static final String[] argumentsToCleanUp = { - APP_JAR_ARG_LONG, - APP_JAR_ARG_SHORT, - CLI_SPRING_JAR_ARG, - CLI_CORE_JAR_ARG, - LOG_LEVEL_ARG, - MONGOCK_CORE_JAR_ARG - }; + private static final String JARS_LIB = "lib"; + + private static ArgumentsHolder argumentsHolder; + private static final CliLogger logger = CliLoggerFactory.getLogger(MongockCli.class); static { Banner.print(System.out); } public static void main(String... args) { - setLogger(args); + Argument.validateArguments(); + argumentsHolder = new ArgumentsHolder(args); + setLogger(); printArgs(args); - try { - String appJar = ArgsUtil.getOptionalParam(args, APP_JAR_ARG_LONG) - .orElseGet(() -> ArgsUtil.getParameter(args, APP_JAR_ARG_SHORT, false)); - - LauncherCliJar.builder() - .setAppJarFile(appJar) - .setCliCoreJar(ArgsUtil.getParameter(args, CLI_CORE_JAR_ARG, false)) - .setCliSpringJar(ArgsUtil.getParameter(args, CLI_SPRING_JAR_ARG, false)) - .setMongockCoreJarFile(ArgsUtil.getParameter(args, MONGOCK_CORE_JAR_ARG, false)) + LauncherCliJar.builder(buildJarFactory()) + .setConfiguration(getConfiguration()) .build() - .loadClasses() - .launch(getCleanArgs(args, argumentsToCleanUp)); + .launch(argumentsHolder.getCleanArgs()); System.exit(0); } catch (Exception ex) { - logger.error(ex.getMessage()); + logger.error(ex); System.exit(1); } } + private static CliConfiguration getConfiguration() { + return argumentsHolder.getOptional(USER_CONFIGURATION) + .map(file -> CliConfiguration.fileBuilder().setConfigFile(file).build()) + .orElseGet(CliConfiguration::new) + .setJarsLibFolder(JARS_LIB) + .setCliVersion(argumentsHolder.getOrException(CLI_VERSION)) + .setDriverNameIfNotNull(argumentsHolder.getOrNull(DRIVER)) + .setUserAppIfNotNull(argumentsHolder.getOrNull(USER_APP_JAR)) + .setUserChangeUnitIfNotNull(argumentsHolder.getOrNull(USER_CHANGE_UNIT_JAR)) + .setLicenseKeyIfNotNull(argumentsHolder.getOrNull(LICENSE_KEY)) + ; + } + + + private static JarFactory buildJarFactory() { + return new JarFactory( + JARS_LIB, + argumentsHolder.getOrException(CLI_VERSION), + argumentsHolder.getOrException(COMMUNITY_VERSION), + argumentsHolder.getOrException(PROFESSIONAL_VERSION)); + } + + // Unneeded loop when level > DEBUG...but small ;) private static void printArgs(String[] args) { StringBuilder sb = new StringBuilder("CLI arguments: "); @@ -65,8 +82,8 @@ private static void printArgs(String[] args) { logger.debug(sb.toString()); } - private static void setLogger(String[] args) { - CliLoggerFactory.setLevel(ArgsUtil.getOptionalParam(args, LOG_LEVEL_ARG) + private static void setLogger() { + CliLoggerFactory.setLevel(argumentsHolder.getOptional(LOG_LEVEL) .map(CliLogger.Level::fromStringDefaultInfo) .orElse(INFO)); } diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/Argument.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/Argument.java new file mode 100644 index 0000000..9bef6e6 --- /dev/null +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/Argument.java @@ -0,0 +1,58 @@ +package io.mongock.cli.wrapper.argument; + +import java.util.HashSet; +import java.util.Set; + +public enum Argument { + + + USER_APP_JAR("-aj", "--app-jar"), + USER_CHANGE_UNIT_JAR("-cj", "--changes-jar"), + USER_CONFIGURATION("-cf", "--config-file"), + + DRIVER("-d", "--driver"), + LICENSE_KEY("-lk", "--license-key"), + + CLI_VERSION("-cv", "--cli-version"), + COMMUNITY_VERSION("-mcv", "--mongock-community-version"), + PROFESSIONAL_VERSION("-mpv", "--mongock-professional-version"), + LOG_LEVEL("-ll", "--log-level") + ; + + private final String shortName; + private final String longName; + + Argument(String shortName, String longName) { + this.shortName = shortName; + this.longName = longName; + } + + + public String getShortName() { + return shortName; + } + + public String getLongName() { + return longName; + } + + public String getDefaultName() { + return getLongName(); + } + + public static void validateArguments() { + Set insertedValues = new HashSet<>(); + for(Argument arg: values()) { + checkValueInserted(insertedValues, arg.getLongName()); + checkValueInserted(insertedValues, arg.getShortName()); + insertedValues.add(arg.getLongName()); + insertedValues.add(arg.getShortName()); + } + } + + private static void checkValueInserted(Set values, String value) { + if(values.contains(value)) { + throw new RuntimeException(String.format("Argument[%s] duplicated", value)); + } + } +} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/ArgumentsHolder.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/ArgumentsHolder.java new file mode 100644 index 0000000..de19970 --- /dev/null +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/argument/ArgumentsHolder.java @@ -0,0 +1,95 @@ +package io.mongock.cli.wrapper.argument; + +import io.mongock.cli.util.logger.CliLogger; +import io.mongock.cli.util.logger.CliLoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ArgumentsHolder { + + private static final CliLogger logger = CliLoggerFactory.getLogger(ArgumentsHolder.class); + + private final String[] args; + + public ArgumentsHolder(String[] args) { + this.args = args; + } + + public String[] getCleanArgs() { + + StringBuilder sb = new StringBuilder("cleaning arguments: "); + Set paramNamesSet = Arrays + .stream(Argument.values()) + .map(arg -> Arrays.asList(arg.getLongName(), arg.getShortName())) + .flatMap(Collection::stream) + .collect(Collectors.toSet()) + .stream() + .peek(arg -> sb.append(arg).append(" ")) + .map(String::toLowerCase) + .collect(Collectors.toSet()); + logger.debug(sb.toString()); + + + List tempNewArgs = new ArrayList<>(); + + for (int i = 0; i < args.length; i++) { + if (!paramNamesSet.contains(args[i].toLowerCase())) { + tempNewArgs.add(args[i]); + } else { + i++; + } + } + + String[] newArgs = new String[tempNewArgs.size()]; + tempNewArgs.toArray(newArgs); + logger.debug("cleaned args size: " + newArgs.length); + StringBuilder sb2 = new StringBuilder("cleaned args: "); + Stream.of(newArgs).forEach(arg -> sb2.append(arg).append(" ")); + logger.debug(sb2.toString()); + return newArgs; + } + + public String getOrNull(Argument argument) { + return getByArgument(argument, false); + } + + public String getOrException(Argument argument) { + return getByArgument(argument, true); + } + + public Optional getOptional(Argument argument) { + return Optional.ofNullable(getByArgument(argument, false)); + } + + private String getByArgument(Argument argument, boolean throwException) { + String value; + if (((value = getValue(argument.getShortName())) == null) && ((value = getValue(argument.getLongName())) == null) && throwException) { + String argumentName = argument.getLongName() + " or " + argument.getShortName(); + throw new RuntimeException( + String.format("Found [%s] flag with missing value. Please follow the format \"%s value\"", argumentName, argumentName) + ); + } + return value; + } + + private String getValue(String paramName) { + int i = 0; + do { + if (paramName.equalsIgnoreCase(args[i])) { + if (args.length == i + 1) { + return null; + } + return args[i + 1]; + } + } while ((++i) < args.length); + return null; + } + +} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/CliClassLoader.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/CliClassLoader.java new file mode 100644 index 0000000..c432b73 --- /dev/null +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/CliClassLoader.java @@ -0,0 +1,83 @@ +package io.mongock.cli.wrapper.jars; + +import io.mongock.cli.util.logger.CliLogger; +import io.mongock.cli.util.logger.CliLoggerFactory; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.function.Function; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class CliClassLoader { + private static final CliLogger logger = CliLoggerFactory.getLogger(CliClassLoader.class); + private static final String CLASS_EXT = ".class"; + private static final String SPRINGBOOT_PREFIX = "org/springframework/boot"; + + private static final Function springBootEntryFilter = entryName -> + entryName.startsWith(SPRINGBOOT_PREFIX) && entryName.endsWith(CLASS_EXT); + + private static final Function nonSpringBootEntryFilter = entryName -> entryName.endsWith(CLASS_EXT); + + + private final List jars = new ArrayList<>(); + private URLClassLoader classLoader; + + public CliClassLoader addJar(Jar jar) { + jars.add(jar); + return this; + } + + public CliClassLoader addJars(List jars) { + jars.addAll(jars); + return this; + } + + public void loadClasses() { + URLClassLoader classLoader = getClassLoader(); + jars.forEach(jar -> CliClassLoader.loadJarClasses(jar, classLoader)); + } + + public static void loadJarClasses(Jar jar, URLClassLoader classLoader) { + try { + JarFile appJarFile = jar.getJarFile(); + logger.debug("loading jar: %s, with classLoader %s", appJarFile.getName(), classLoader.getClass().getName()); + Thread.currentThread().getContextClassLoader(); + Enumeration jarEntryEnum = appJarFile.entries(); + Function jarEntryFilter = jar.isSpringApplication() + ? springBootEntryFilter + : nonSpringBootEntryFilter; + + while (jarEntryEnum.hasMoreElements()) { + String entryName = jarEntryEnum.nextElement().getName(); + + + if (jarEntryFilter.apply(entryName)) { + String className = entryName.substring(0, entryName.lastIndexOf(CLASS_EXT)).replace('/', '.'); + try { + classLoader.loadClass(className); + } catch (Throwable e) { + logger.warn(String.format("%s not loaded(%s)", className, e.getMessage())); + } + logger.trace("Loaded: " + className); + } + } + appJarFile.close(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public URLClassLoader getClassLoader() { + if (classLoader == null) { + classLoader = URLClassLoader.newInstance( + jars.stream().map(Jar::getUrl).toArray(URL[]::new), + Thread.currentThread().getContextClassLoader() + ); + } + return classLoader; + } +} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/Jar.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/Jar.java new file mode 100644 index 0000000..bde79d3 --- /dev/null +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/Jar.java @@ -0,0 +1,82 @@ +package io.mongock.cli.wrapper.jars; + +import io.mongock.cli.wrapper.launcher.LauncherSpringboot; +import org.springframework.boot.loader.archive.JarFileArchive; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +public class Jar { + + public static final String JAR_URL_TEMPLATE = "jar:file:%s!/"; + private final String jarPath; + + public Jar(String jarPath) { + this.jarPath = jarPath; + } + + public String getPath() { + return jarPath; + } + + public URL getUrl() { + try { + return new URL(String.format(JAR_URL_TEMPLATE, jarPath)); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + public JarFile getJarFile() { + try { + return new JarFile(jarPath); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public JarFileArchive getJarFileArchive() { + try { + return new JarFileArchive(new File(jarPath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Class getMainClass(ClassLoader classLoader) throws ClassNotFoundException { + String className = getMainClassName(); + return classLoader.loadClass(className); + } + + public String getMainClassName() { + JarFileArchive archive = getJarFileArchive(); + String className = getAttributes(archive).getValue(Attributes.Name.MAIN_CLASS); + return className; + } + + public boolean isSpringApplication() { + JarFileArchive archive = getJarFileArchive(); + return getAttributes(archive).getValue(LauncherSpringboot.BOOT_CLASSPATH_INDEX_ATTRIBUTE) != null; + } + + private static Attributes getAttributes(JarFileArchive archive) { + try { + Manifest manifest = archive.getManifest(); + if(manifest == null) { + throw new RuntimeException("manifest not present in the appJar"); + } + Attributes attributes = manifest.getMainAttributes(); + if(attributes == null) { + throw new RuntimeException("Mongock CLI cannot access to attributes in manifest"); + } + return attributes; + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/JarFactory.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/JarFactory.java new file mode 100644 index 0000000..d939c1a --- /dev/null +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/jars/JarFactory.java @@ -0,0 +1,50 @@ +package io.mongock.cli.wrapper.jars; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class JarFactory { + private final String jarsLib; + private final String cliVersion; + private final String mongockCommunityVersion; + private final String mongockProVersion; + + + public JarFactory(String jarsLib, String cliVersion, String mongockCommunityVersion, String mongockProVersion) { + this.jarsLib = jarsLib; + this.cliVersion = cliVersion; + this.mongockCommunityVersion = mongockCommunityVersion; + this.mongockProVersion = mongockProVersion; + } + + public Jar defaultApp() { + return new Jar(String.format("%s/mongock-default-app-%s.jar", jarsLib, cliVersion)); + } + + public Jar defaultProfessionalApp() { + return new Jar(String.format("%s/mongock-default-app-professional-%s.jar", jarsLib, cliVersion)); + } + + public Jar cliSpringboot() { + return new Jar(String.format("%s/mongock-cli-springboot-%s.jar", jarsLib, cliVersion)); + } + + public Jar cliCore() { + return new Jar(String.format("%s/mongock-cli-core-%s.jar", jarsLib, cliVersion)); + } + + public List runnerCommunityDependencies() { + return Arrays.asList( + new Jar(String.format("%s/mongock-standalone-base-%s.jar", jarsLib, mongockCommunityVersion)), + new Jar(String.format("%s/mongock-standalone-%s.jar", jarsLib, mongockCommunityVersion)) + ); + } + + //TODO generify versions + public List runnerProfessionalDependencies() { + return Collections.emptyList(); + } + + +} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherCliJar.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherCliJar.java index 9bdd003..208a8e6 100644 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherCliJar.java +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherCliJar.java @@ -1,103 +1,88 @@ package io.mongock.cli.wrapper.launcher; -import io.mongock.cli.wrapper.util.JarUtil; -import org.springframework.boot.loader.archive.JarFileArchive; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.cli.wrapper.jars.CliClassLoader; +import io.mongock.cli.wrapper.jars.Jar; +import io.mongock.cli.wrapper.jars.JarFactory; -import java.io.File; -import java.io.IOException; -import java.util.Optional; +import static io.mongock.cli.wrapper.argument.Argument.DRIVER; -import static io.mongock.cli.wrapper.util.Parameters.APP_JAR_ARG_LONG; -import static io.mongock.cli.wrapper.util.Parameters.CLI_CORE_JAR_ARG; -import static io.mongock.cli.wrapper.util.Parameters.CLI_SPRING_JAR_ARG; -import static io.mongock.cli.wrapper.util.Parameters.MONGOCK_CORE_JAR_ARG; public interface LauncherCliJar { - LauncherCliJar loadClasses(); - void launch(String[] args); - static LauncherBuilder builder() { - return new LauncherBuilder(); + static LauncherBuilder builder(JarFactory jarFactory) { + return new LauncherBuilder(jarFactory); } class LauncherBuilder { - private String cliSpringJar; - private String cliCoreJar; - - private String appJarFile; - - private String mongockCoreJarFile; + private JarFactory jarFactory; + private CliConfiguration configuration; - - public LauncherBuilder() { + public LauncherBuilder(JarFactory jarFactory) { + this.jarFactory = jarFactory; } - public LauncherBuilder setAppJarFile(String appJarFile) { - this.appJarFile = appJarFile; + public LauncherBuilder setConfiguration(CliConfiguration configuration) { + this.configuration = configuration; return this; } - public LauncherBuilder setCliSpringJar(String cliSpringJar) { - this.cliSpringJar = cliSpringJar; - return this; - } - public LauncherBuilder setCliCoreJar(String cliCoreJar) { - this.cliCoreJar = cliCoreJar; - return this; - } - - public LauncherBuilder setMongockCoreJarFile(String mongockCoreJarFile) { - this.mongockCoreJarFile = mongockCoreJarFile; - return this; - } - - public LauncherCliJar build() throws IOException { - if (getAppJar().isPresent()) { - JarFileArchive archive = new JarFileArchive(new File(appJarFile)); - if (JarUtil.isSpringApplication(archive)) { - return buildLauncherSpring(archive); + public LauncherCliJar build() { + if (configuration.getUserApplication().isPresent()) { + Jar userApplicationJar = new Jar(configuration.getUserApplication().get()); + if (userApplicationJar.isSpringApplication()) { + new CliClassLoader().addJar(userApplicationJar).loadClasses(); + return new LauncherSpringboot(userApplicationJar, jarFactory.cliSpringboot()); } else { - return buildLauncherStandalone(archive); + + CliClassLoader cliClassLoader = new CliClassLoader() + .addJar(userApplicationJar) + .addJar(jarFactory.cliCore()); + cliClassLoader.loadClasses(); + return new LauncherStandalone(userApplicationJar, cliClassLoader.getClassLoader()); } + } else if(configuration.getUserChangeUnit().isPresent()) { + DriverWrapper driverWrapper = configuration.getDriverWrapper(); + CliClassLoader cliClassLoader = new CliClassLoader() + .addJar(isProfessional() ? jarFactory.defaultProfessionalApp() : jarFactory.defaultApp()) + .addJar(jarFactory.cliCore()) + .addJar(new Jar(driverWrapper.getJarPath())) + .addJars(isProfessional() ? jarFactory.runnerProfessionalDependencies() : jarFactory.runnerCommunityDependencies()) + .addJar(new Jar(configuration.getUserChangeUnit().get())); + cliClassLoader.loadClasses(); + validateDriverIfApply(driverWrapper); + return new LauncherDefault( + isProfessional() ? jarFactory.defaultProfessionalApp() : jarFactory.defaultApp(), + cliClassLoader.getClassLoader(), + configuration.getLicenseKey().get(), + driverWrapper, + configuration + ); + } else { - return buildLauncherWithoutApp(); + throw new RuntimeException("Either an application jar or a jar containing the change units must be provided"); } } - private LauncherDefault buildLauncherWithoutApp() { - validateNotNullParameter(mongockCoreJarFile, "parameter " + MONGOCK_CORE_JAR_ARG); - validateNotNullParameter(cliCoreJar, "parameter " + CLI_CORE_JAR_ARG); - return new LauncherDefault(mongockCoreJarFile, cliCoreJar); - } - - private LauncherStandalone buildLauncherStandalone(JarFileArchive archive) { - validateNotNullParameter(appJarFile, "parameter " + APP_JAR_ARG_LONG); - validateNotNullParameter(cliCoreJar, "parameter " + CLI_CORE_JAR_ARG); - return new LauncherStandalone(archive, appJarFile, cliCoreJar); + private boolean isProfessional() { + return configuration.getLicenseKey().isPresent(); } - private LauncherSpringboot buildLauncherSpring(JarFileArchive archive) { - validateNotNullParameter(appJarFile, "parameter " + APP_JAR_ARG_LONG); - validateNotNullParameter(cliSpringJar, "parameter " + CLI_SPRING_JAR_ARG); - return new LauncherSpringboot(archive, appJarFile, cliSpringJar); - } - - - private Optional getAppJar() { - return Optional.ofNullable(appJarFile); + private void validateDriverIfApply(DriverWrapper driverWrapper) { + if (driverWrapper == null) { + throw new RuntimeException(String.format( + "When application is missing, Parameter `%s` must be provided : \n%s", + DRIVER.getDefaultName(), + DriverWrapper.getAllDriverNames("\n"))); + } } - - private void validateNotNullParameter(Object parameter, String name) { - if(parameter == null) { - throw new RuntimeException(name + " must be provided"); - } - } } } diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherDefault.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherDefault.java index 7033c3b..412a4c3 100644 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherDefault.java +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherDefault.java @@ -1,101 +1,53 @@ package io.mongock.cli.wrapper.launcher; -import io.mongock.cli.util.logger.CliLogger; -import io.mongock.cli.util.logger.CliLoggerFactory; -import io.mongock.cli.wrapper.util.ClassLoaderUtil; -import io.mongock.cli.wrapper.util.JarUtil; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.cli.wrapper.jars.Jar; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.jar.JarFile; -import java.util.stream.Stream; -public class LauncherDefault implements LauncherCliJar { +public class LauncherDefault extends LauncherStandalone { - private static final CliLogger logger = CliLoggerFactory.getLogger(LauncherDefault.class); + private final DriverWrapper driverWrapper; - private final String cliJarPath; + private final String licenseKey; + private final CliConfiguration cliConfiguration; - private final String mongockCoreJarFile; - private URLClassLoader classLoader; + public LauncherDefault(Jar appJar, + ClassLoader classLoader, + String licenseKey, + DriverWrapper driverWrapper, + CliConfiguration cliConfiguration + ) { + super(appJar, classLoader); + this.licenseKey = licenseKey; + this.driverWrapper = driverWrapper; + this.cliConfiguration = cliConfiguration; - public LauncherDefault(String mongockCoreJarFile, String cliJarPath) { - this.mongockCoreJarFile = mongockCoreJarFile; - this.cliJarPath = cliJarPath; - } - - @Override - public LauncherCliJar loadClasses() { - - try { - this.classLoader = buildClassLoader(); - ClassLoaderUtil.loadJarClasses(new JarFile(mongockCoreJarFile), classLoader); - ClassLoaderUtil.loadJarClasses(new JarFile(cliJarPath), classLoader); - return this; - } catch (Exception ex) { - throw new RuntimeException(ex); - } } @Override - public void launch(String[] args) { - try { - logger.info("launching Mongock CLI runner with default launcher"); + protected Object getRunnerBuilder(Class builderProviderImplClass) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { - Object commandLine = buildCli(getCliBuilder()); + Class.forName("io.mongock.runner.core.builder.RunnerBuilderProvider", false, classLoader); - StringBuilder sb = new StringBuilder(); - Stream.of(args).forEach(s -> sb.append(s).append(" ")); - logger.debug("executing CommandLine with args: " + sb); - Method executeMethod = commandLine.getClass().getDeclaredMethod("execute", String[].class); - executeMethod.setAccessible(true); - executeMethod.invoke(commandLine, new Object[]{args}); - logger.debug("successful call to commandLine.execute()"); + Constructor constructor = builderProviderImplClass.getDeclaredConstructor(); + Object builderProvider = constructor.newInstance(); + // setting configuration + Method setConfigMethod = builderProvider.getClass().getMethod("setConfiguration", CliConfiguration.class); + setConfigMethod.invoke(builderProvider, cliConfiguration); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - + Method getBuilderMethod = builderProvider.getClass().getMethod("getBuilder"); + Object builder = getBuilderMethod.invoke(builderProvider); - private Object buildCli(Object cliBuilder) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - logger.debug("building CommandLine"); - Method buildMethod = cliBuilder.getClass().getDeclaredMethod("build"); - buildMethod.setAccessible(true); - Object commandLine = buildMethod.invoke(cliBuilder); - logger.debug("successful built commandLine " + commandLine); - return commandLine; + return builder; } - private Object getCliBuilder() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { - logger.debug("loading MongockCLI class"); - Class mongockCliClass = Class.forName("io.mongock.cli.core.CliCoreRunner", false, classLoader); - logger.debug("successfully loaded MongockCLI class"); - - logger.debug("obtaining builder setter"); - Method builderMethod = mongockCliClass.getDeclaredMethod("builder"); - builderMethod.setAccessible(true); - Object cliBuilder = builderMethod.invoke(null); - logger.debug("obtained cliBuilder"); - return cliBuilder; - } - - - private URLClassLoader buildClassLoader() throws MalformedURLException { - return URLClassLoader.newInstance( - new URL[]{ - new URL(String.format(JarUtil.JAR_URL_TEMPLATE, mongockCoreJarFile)), - new URL(String.format(JarUtil.JAR_URL_TEMPLATE, cliJarPath)) - }, - Thread.currentThread().getContextClassLoader() - ); - } } diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherSpringboot.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherSpringboot.java index edbd8ed..49089ff 100644 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherSpringboot.java +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherSpringboot.java @@ -2,18 +2,15 @@ import io.mongock.cli.util.logger.CliLogger; import io.mongock.cli.util.logger.CliLoggerFactory; +import io.mongock.cli.wrapper.jars.Jar; import io.mongock.cli.wrapper.launcher.springboot.CliMainMethodRunner; -import io.mongock.cli.wrapper.util.ClassLoaderUtil; -import io.mongock.cli.wrapper.util.JarUtil; import org.springframework.boot.loader.JarLauncher; import org.springframework.boot.loader.LaunchedURLClassLoader; import org.springframework.boot.loader.MainMethodRunner; import org.springframework.boot.loader.archive.Archive; import java.net.URL; -import java.net.URLClassLoader; import java.util.Iterator; -import java.util.jar.JarFile; public class LauncherSpringboot extends JarLauncher implements LauncherCliJar { @@ -21,17 +18,13 @@ public class LauncherSpringboot extends JarLauncher implements LauncherCliJar { private static final CliLogger logger = CliLoggerFactory.getLogger(LauncherSpringboot.class); public static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = JarLauncher.BOOT_CLASSPATH_INDEX_ATTRIBUTE; private static final String SPRING_CLI_MAIN_CLASS = "io.mongock.cli.springboot.CliSpringbootRunner"; - private static final String CLASS_EXT = ".class"; - private static final String SPRINGBOOT_PREFIX = "org/springframework/boot"; - private final String cliJarPath; + private final Jar cliJar; private final String cliMainClass; - private final String appJar; - public LauncherSpringboot(Archive archive, String appJar, String cliJarPath) { - super(archive); - this.appJar = appJar; - this.cliJarPath = cliJarPath; + public LauncherSpringboot(Jar appJar, Jar cliJar) { + super(appJar.getJarFileArchive()); + this.cliJar = cliJar; this.cliMainClass = SPRING_CLI_MAIN_CLASS; } @@ -44,23 +37,6 @@ public String getOriginalMainClass() { } } - public LauncherSpringboot loadClasses() { - try { - URLClassLoader classLoader = URLClassLoader.newInstance( - new URL[]{new URL(String.format(JarUtil.JAR_URL_TEMPLATE, appJar))}, - Thread.currentThread().getContextClassLoader() - ); - - ClassLoaderUtil.loadJarClasses( - new JarFile(appJar), - classLoader, - entryName -> entryName.startsWith(SPRINGBOOT_PREFIX) && entryName.endsWith(CLASS_EXT)); - return this; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - @Override protected String getMainClass() { return cliMainClass; @@ -86,7 +62,7 @@ protected ClassLoader createClassLoader(Iterator archives) throws Excep return new LaunchedURLClassLoader( this.isExploded(), this.getArchive(), - new URL[]{new URL("jar:file:" + cliJarPath + "!/")}, + new URL[]{cliJar.getUrl()}, super.createClassLoader(archives)); } } diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherStandalone.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherStandalone.java index d59583f..b50725a 100644 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherStandalone.java +++ b/mongock-cli/src/main/java/io/mongock/cli/wrapper/launcher/LauncherStandalone.java @@ -3,63 +3,39 @@ import io.mongock.api.annotations.MongockCliConfiguration; import io.mongock.cli.util.logger.CliLogger; import io.mongock.cli.util.logger.CliLoggerFactory; -import io.mongock.cli.wrapper.util.ClassLoaderUtil; -import io.mongock.cli.wrapper.util.JarUtil; -import org.springframework.boot.loader.archive.JarFileArchive; +import io.mongock.cli.wrapper.jars.Jar; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.jar.JarFile; import java.util.stream.Stream; public class LauncherStandalone implements LauncherCliJar { private static final CliLogger logger = CliLoggerFactory.getLogger(LauncherStandalone.class); - private final JarFileArchive appJarArchive; - private final String appJar; - private final String cliJarPath; + private final Jar appJar; - private URLClassLoader classLoader; + protected final ClassLoader classLoader; - public LauncherStandalone(JarFileArchive appArchive, String appJar, String cliJarPath) { - this.appJarArchive = appArchive; + public LauncherStandalone(Jar appJar, ClassLoader classLoader) { this.appJar = appJar; - this.cliJarPath = cliJarPath; + this.classLoader = classLoader; } - @Override - public LauncherCliJar loadClasses() { - - try { - this.classLoader = buildClassLoader(); - ClassLoaderUtil.loadJarClasses(new JarFile(appJar), classLoader); - ClassLoaderUtil.loadJarClasses(new JarFile(cliJarPath), classLoader); - - return this; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - @Override public void launch(String[] args) { try { logger.info("launching Mongock CLI runner with Standalone launcher"); - String mainClassName = JarUtil.getMainClass(appJarArchive); - Class mainClass = getMainClass(mainClassName); + Class mainClass = appJar.getMainClass(classLoader); if (mainClass.isAnnotationPresent(MongockCliConfiguration.class)) { MongockCliConfiguration ann = mainClass.getAnnotation(MongockCliConfiguration.class); Class.forName("io.mongock.runner.core.builder.RunnerBuilderProvider", false, classLoader); Class builderProviderImplClass = ann.sources()[0]; + Object runnerBuilder = getRunnerBuilder(builderProviderImplClass); Object cliBuilder = getCliBuilder(); @@ -71,19 +47,14 @@ public void launch(String[] args) { executeCli(args, commandLine); } else { - throw new RuntimeException("Main class " + mainClassName + " not annotated with MongockCliConfiguration"); + throw new RuntimeException("Main class " + mainClass.getName() + " not annotated with MongockCliConfiguration"); } } catch (Exception ex) { throw new RuntimeException(ex); } } - private Class getMainClass(String mainClassName) throws ClassNotFoundException { - logger.debug("Main class: " + mainClassName); - Class mainClass = classLoader.loadClass(mainClassName); - logger.debug("loaded Main class"); - return mainClass; - } + private void executeCli(String[] args, Object commandLine) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { StringBuilder sb = new StringBuilder(); @@ -116,6 +87,7 @@ private void setRunnerBuilderToCli(Object runnerBuilder, Object cliBuilder) thro logger.debug("successfully set RunnerBuilder to MongockCli.builder"); } + private Object getCliBuilder() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { logger.debug("loading MongockCLI class"); Class mongockCliClass = Class.forName("io.mongock.cli.core.CliCoreRunner", false, classLoader); @@ -130,20 +102,13 @@ private Object getCliBuilder() throws ClassNotFoundException, NoSuchMethodExcept return cliBuilder; } - private Object getRunnerBuilder(Class builderProviderImplClass) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { + protected Object getRunnerBuilder(Class builderProviderImplClass) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { + Class.forName("io.mongock.runner.core.builder.RunnerBuilderProvider", false, classLoader); + Constructor constructor = builderProviderImplClass.getDeclaredConstructor(); Object builderProvider = constructor.newInstance(); Method getBuilderMethod = builderProvider.getClass().getMethod("getBuilder"); return getBuilderMethod.invoke(builderProvider); } - private URLClassLoader buildClassLoader() throws MalformedURLException { - return URLClassLoader.newInstance( - new URL[]{ - new URL(String.format(JarUtil.JAR_URL_TEMPLATE, appJar)), - new URL(String.format(JarUtil.JAR_URL_TEMPLATE, cliJarPath)) - }, - Thread.currentThread().getContextClassLoader() - ); - } } diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ArgsUtil.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ArgsUtil.java deleted file mode 100644 index 3c83367..0000000 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ArgsUtil.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.mongock.cli.wrapper.util; - -import io.mongock.cli.util.logger.CliLogger; -import io.mongock.cli.util.logger.CliLoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class ArgsUtil { - - private static final CliLogger logger = CliLoggerFactory.getLogger(ArgsUtil.class); - - private ArgsUtil() {} - - public static String[] getCleanArgs(String[] args, String... paramNames) { - - StringBuilder sb = new StringBuilder("cleaning arguments: "); - Set paramNamesSet = Stream.of(paramNames) - .peek(arg -> sb.append(arg).append(" ")) - .map(String::toLowerCase) - .collect(Collectors.toSet()); - logger.debug(sb.toString()); - - - List tempNewArgs = new ArrayList<>(); - - for (int i = 0; i < args.length; i++) { - if (!paramNamesSet.contains(args[i].toLowerCase())) { - tempNewArgs.add(args[i]); - } else { - i++; - } - } - - String[] newArgs = new String[tempNewArgs.size()]; - tempNewArgs.toArray(newArgs); - logger.debug("cleaned args size: " + newArgs.length); - StringBuilder sb2 = new StringBuilder("cleaned args: "); - Stream.of(newArgs).forEach(arg -> sb2.append(arg).append(" ")); - logger.debug(sb2.toString()); - return newArgs; - } - - public static Optional getOptionalParam(String[] args, String paramName) { - return Optional.ofNullable(getParameter(args, paramName, false)); - } - - public static String getParameter(String[] args, String paramName) { - return getParameter(args, paramName, true); - } - - public static String getParameter(String[] args, String paramName, boolean throwException) { - int i = 0; - do { - if (paramName.equalsIgnoreCase(args[i])) { - if (args.length == i + 1) { - if(throwException) { - throw new RuntimeException( - String.format("Found [%s] flag with missing value. Please follow the format \"%s value\"", paramName, paramName) - ); - } else { - return null; - } - - } - return args[i + 1]; - } - } while ((++i) < args.length); - if(throwException) { - throw new RuntimeException(String.format("Missing jar parameter. Please follow the format \"%s jar_path\"", paramName)); - - } else { - return null; - } - - } -} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ClassLoaderUtil.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ClassLoaderUtil.java deleted file mode 100644 index 5f31052..0000000 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/ClassLoaderUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.mongock.cli.wrapper.util; - -import io.mongock.cli.util.logger.CliLogger; -import io.mongock.cli.util.logger.CliLoggerFactory; - -import java.net.URLClassLoader; -import java.util.Enumeration; -import java.util.function.Function; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -public final class ClassLoaderUtil { - - private static final CliLogger logger = CliLoggerFactory.getLogger(ClassLoaderUtil.class); - - private static final String CLASS_EXT = ".class"; - - public static void loadJarClasses(JarFile appJarFile, - URLClassLoader classLoader) { - loadJarClasses(appJarFile, classLoader, e -> e.endsWith(CLASS_EXT)); - } - - public static void loadJarClasses(JarFile appJarFile, - URLClassLoader classLoader, - Function jarEntryFilter) { - try { - logger.debug("lading jar: %s, with classLoader %s", appJarFile.getName(), classLoader.getClass().getName() ); - Thread.currentThread().getContextClassLoader(); - Enumeration jarEntryEnum = appJarFile.entries(); - while (jarEntryEnum.hasMoreElements()) { - String entryName = jarEntryEnum.nextElement().getName(); - if (jarEntryFilter.apply(entryName)) { - String className = entryName.substring(0, entryName.lastIndexOf(CLASS_EXT)).replace('/', '.'); - try { - classLoader.loadClass(className); - } catch (Throwable e) { - logger.warn(String.format("%s not loaded(%s)", className, e.getMessage())); - } - logger.trace(className + " loaded "); - } - } - appJarFile.close(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/JarUtil.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/JarUtil.java deleted file mode 100644 index 722ed4e..0000000 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/JarUtil.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.mongock.cli.wrapper.util; - -import io.mongock.cli.util.logger.CliLogger; -import io.mongock.cli.util.logger.CliLoggerFactory; -import io.mongock.cli.wrapper.launcher.LauncherSpringboot; -import org.springframework.boot.loader.archive.JarFileArchive; - -import java.io.IOException; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - -public final class JarUtil { - - private static final CliLogger logger = CliLoggerFactory.getLogger(JarUtil.class); - - public static final String JAR_URL_TEMPLATE = "jar:file:%s!/"; - private JarUtil() {} - - public static String getMainClass(JarFileArchive archive) throws IOException { - String mainClass = getAttributes(archive).getValue(Attributes.Name.MAIN_CLASS); - logger.debug("%s main class: %s", archive.getUrl(), mainClass); - return mainClass; - } - - public static boolean isSpringApplication(JarFileArchive archive) { - try { - return getAttributes(archive).getValue(LauncherSpringboot.BOOT_CLASSPATH_INDEX_ATTRIBUTE) != null; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static Attributes getAttributes(JarFileArchive archive) throws IOException { - Manifest manifest = archive.getManifest(); - if(manifest == null) { - throw new RuntimeException("manifest not present in the appJar"); - } - Attributes attributes = manifest.getMainAttributes(); - if(attributes == null) { - throw new RuntimeException("Mongock CLI cannot access to attributes in manifest"); - } - return attributes; - } - -} diff --git a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/Parameters.java b/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/Parameters.java deleted file mode 100644 index ed996ce..0000000 --- a/mongock-cli/src/main/java/io/mongock/cli/wrapper/util/Parameters.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.mongock.cli.wrapper.util; - -public class Parameters { - - public static final String APP_JAR_ARG_SHORT = "-aj"; - public static final String APP_JAR_ARG_LONG = "--app-jar"; - - public static final String MONGOCK_CORE_JAR_ARG = "--mongock-core-jar"; - public static final String CLI_SPRING_JAR_ARG = "--cli-spring-jar"; - public static final String CLI_CORE_JAR_ARG = "--cli-core-jar"; - public static final String LOG_LEVEL_ARG = "--log-level"; - -} diff --git a/mongock-cli/src/main/resources/linux_script_template b/mongock-cli/src/main/resources/linux_script_template index 17fbe53..8982b11 100755 --- a/mongock-cli/src/main/resources/linux_script_template +++ b/mongock-cli/src/main/resources/linux_script_template @@ -1,8 +1,8 @@ #!/bin/sh #Generated cli script java -jar ${project.artifactId}-${project.version}.jar \ - --cli-spring-jar lib/mongock-cli-springboot-${project.version}.jar \ - --cli-core-jar lib/mongock-cli-core-${project.version}.jar \ - --mongock-core-jar lib/mongock-runner-core-${mongock.version}.jar \ + --cli-version ${project.version} \ + --mongock-community-version ${mongock.community.version} \ + --mongock-professional-version ${mongock.pro.version} \ "$@" \ \ diff --git a/mongock-default-app-professional/pom.xml b/mongock-default-app-professional/pom.xml new file mode 100644 index 0000000..66c3301 --- /dev/null +++ b/mongock-default-app-professional/pom.xml @@ -0,0 +1,93 @@ + + + + mongock-cli-project + io.mongock + 5.0.28-SNAPSHOT + + 4.0.0 + + mongock-default-app-professional + + + + + io.mongock + mongock-cli-util + ${project.version} + + + + + io.mongock.professional + mongock-standalone + ${mongock.pro.version} + + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + + + + + + io.mongock + mongodb-springdata-v3-wrapper + ${project.version} + provided + true + + + io.mongock + mongodb-springdata-v2-wrapper + ${project.version} + provided + true + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + shade + + + false + + + io.mongock.cli.app.professional.DefaultProfessionalApp + + + + + + + + + + \ No newline at end of file diff --git a/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DefaultProfessionalApp.java b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DefaultProfessionalApp.java new file mode 100644 index 0000000..c3d4382 --- /dev/null +++ b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DefaultProfessionalApp.java @@ -0,0 +1,19 @@ +package io.mongock.cli.app.professional; + +import io.mongock.api.annotations.MongockCliConfiguration; +import io.mongock.cli.util.MongockDefaultApp; + + +@MongockDefaultApp +@MongockCliConfiguration(sources = RunnerBuilderProviderProfessionalImpl.class) +public class DefaultProfessionalApp { + + + public static void main(String[] args) { + new RunnerBuilderProviderProfessionalImpl() + .getBuilder() + .buildRunner() + .execute(); + } + +} diff --git a/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DriverFactory.java b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DriverFactory.java new file mode 100644 index 0000000..24cad77 --- /dev/null +++ b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/DriverFactory.java @@ -0,0 +1,28 @@ +package io.mongock.cli.app.professional; + +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.ConnectionDriverProvider; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.driver.api.driver.ConnectionDriver; + +public final class DriverFactory { + + private DriverFactory() { + } + + public static ConnectionDriver getDriver(DriverWrapper driverWrapper, CliConfiguration configuration) { + + ConnectionDriverProvider connectionDriverProvider; + switch (driverWrapper) { + case MONGODB_SPRING_DATA_V3: + connectionDriverProvider = new io.mongock.driver.cli.wrapper.mongodb.springdata.v3.SpringDataMongoV3DriverProvider(); + break; + case MONGODB_SPRING_DATA_V2: + connectionDriverProvider = new io.mongock.driver.cli.wrapper.mongodb.springdata.v2.SpringDataMongoV2DriverProvider(); + break; + default: + throw new RuntimeException(String.format("%s not found", driverWrapper)); + } + return connectionDriverProvider.getDriver(configuration); + } +} diff --git a/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/RunnerBuilderProviderProfessionalImpl.java b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/RunnerBuilderProviderProfessionalImpl.java new file mode 100644 index 0000000..d6096aa --- /dev/null +++ b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/RunnerBuilderProviderProfessionalImpl.java @@ -0,0 +1,35 @@ +package io.mongock.cli.app.professional; + +import io.mongock.cli.app.professional.events.MongockEventListener; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.cli.util.RunnerBuilderProviderConfigurable; +import io.mongock.runner.core.builder.RunnerBuilder; +import io.mongock.runner.core.builder.RunnerBuilderProvider; +import io.mongock.runner.standalone.MongockStandalone; + +public class RunnerBuilderProviderProfessionalImpl implements RunnerBuilderProvider, RunnerBuilderProviderConfigurable { + + private DriverWrapper driverWrapper; + private CliConfiguration configuration; + + @Override + public RunnerBuilder getBuilder() { + + return MongockStandalone.builder() + .setDriver(DriverFactory.getDriver(driverWrapper, configuration)) + .addMigrationScanPackage(configuration.getScanPackage()) + .setLicenseKey(configuration.getLicenseKey().orElse(null)) + .setMigrationStartedListener(MongockEventListener::onStart) + .setMigrationSuccessListener(MongockEventListener::onSuccess) + .setMigrationFailureListener(MongockEventListener::onFail) + .setTrackIgnored(true) + .setTransactionEnabled(true); + } + + @Override + public void setConfiguration(CliConfiguration configuration) { + this.configuration = configuration; + this.driverWrapper = configuration.getDriverWrapper(); + } +} diff --git a/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/events/MongockEventListener.java b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/events/MongockEventListener.java new file mode 100644 index 0000000..5184096 --- /dev/null +++ b/mongock-default-app-professional/src/main/java/io/mongock/cli/app/professional/events/MongockEventListener.java @@ -0,0 +1,20 @@ +package io.mongock.cli.app.professional.events; + +import io.mongock.runner.core.event.MigrationFailureEvent; +import io.mongock.runner.core.event.MigrationStartedEvent; +import io.mongock.runner.core.event.MigrationSuccessEvent; + +public class MongockEventListener { + + public static void onStart(MigrationStartedEvent event) { + System.out.println("[EVENT LISTENER] - Mongock STARTED successfully"); + } + + public static void onSuccess(MigrationSuccessEvent event) { + System.out.println("[EVENT LISTENER] - Mongock finished successfully"); + } + + public static void onFail(MigrationFailureEvent event) { + System.out.println("[EVENT LISTENER] - Mongock finished with failures"); + } +} diff --git a/mongock-default-app/pom.xml b/mongock-default-app/pom.xml new file mode 100644 index 0000000..45fd0c9 --- /dev/null +++ b/mongock-default-app/pom.xml @@ -0,0 +1,97 @@ + + + + mongock-cli-project + io.mongock + 5.0.28-SNAPSHOT + + 4.0.0 + + mongock-default-app + + + + + + + + io.mongock + mongock-cli-util + ${project.version} + + + + + io.mongock + mongock-standalone + ${mongock.community.version} + provided + true + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + + + + + + io.mongock + mongodb-springdata-v3-wrapper + ${project.version} + provided + true + + + io.mongock + mongodb-springdata-v2-wrapper + ${project.version} + provided + true + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + shade + + + false + + + io.mongock.cli.app.DefaultApp + + + + + + + + + + \ No newline at end of file diff --git a/mongock-default-app/src/main/java/io/mongock/cli/app/DefaultApp.java b/mongock-default-app/src/main/java/io/mongock/cli/app/DefaultApp.java new file mode 100644 index 0000000..6bd60b9 --- /dev/null +++ b/mongock-default-app/src/main/java/io/mongock/cli/app/DefaultApp.java @@ -0,0 +1,18 @@ +package io.mongock.cli.app; + +import io.mongock.api.annotations.MongockCliConfiguration; +import io.mongock.cli.util.MongockDefaultApp; + +@MongockDefaultApp +@MongockCliConfiguration(sources = RunnerBuilderProviderImpl.class) +public class DefaultApp { + + + public static void main(String[] args) { + new RunnerBuilderProviderImpl() + .getBuilder() + .buildRunner() + .execute(); + } + +} diff --git a/mongock-default-app/src/main/java/io/mongock/cli/app/DriverFactory.java b/mongock-default-app/src/main/java/io/mongock/cli/app/DriverFactory.java new file mode 100644 index 0000000..a37d1e0 --- /dev/null +++ b/mongock-default-app/src/main/java/io/mongock/cli/app/DriverFactory.java @@ -0,0 +1,28 @@ +package io.mongock.cli.app; + +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.ConnectionDriverProvider; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.driver.api.driver.ConnectionDriver; + +public final class DriverFactory { + + private DriverFactory() { + } + + public static ConnectionDriver getDriver(DriverWrapper driverWrapper, CliConfiguration configuration) { + + ConnectionDriverProvider connectionDriverProvider; + switch (driverWrapper) { + case MONGODB_SPRING_DATA_V3: + connectionDriverProvider = new io.mongock.driver.cli.wrapper.mongodb.springdata.v3.SpringDataMongoV3DriverProvider(); + break; + case MONGODB_SPRING_DATA_V2: + connectionDriverProvider = new io.mongock.driver.cli.wrapper.mongodb.springdata.v2.SpringDataMongoV2DriverProvider(); + break; + default: + throw new RuntimeException(String.format("%s not found", driverWrapper)); + } + return connectionDriverProvider.getDriver(configuration); + } +} diff --git a/mongock-default-app/src/main/java/io/mongock/cli/app/RunnerBuilderProviderImpl.java b/mongock-default-app/src/main/java/io/mongock/cli/app/RunnerBuilderProviderImpl.java new file mode 100644 index 0000000..05fd7e1 --- /dev/null +++ b/mongock-default-app/src/main/java/io/mongock/cli/app/RunnerBuilderProviderImpl.java @@ -0,0 +1,37 @@ +package io.mongock.cli.app; + +import io.mongock.cli.app.events.MongockEventListener; +import io.mongock.cli.util.CliConfiguration; +import io.mongock.cli.util.DriverWrapper; +import io.mongock.cli.util.RunnerBuilderProviderConfigurable; +import io.mongock.runner.core.builder.RunnerBuilder; +import io.mongock.runner.core.builder.RunnerBuilderProvider; +import io.mongock.runner.standalone.MongockStandalone; + +public class RunnerBuilderProviderImpl implements RunnerBuilderProvider, RunnerBuilderProviderConfigurable { + + private DriverWrapper driverWrapper; + private CliConfiguration configuration; + + @Override + public RunnerBuilder getBuilder() { + + return MongockStandalone.builder() + .setDriver(DriverFactory.getDriver(driverWrapper, configuration)) + .addMigrationScanPackage(configuration.getScanPackage()) + .setMigrationStartedListener(MongockEventListener::onStart) + .setMigrationSuccessListener(MongockEventListener::onSuccess) + .setMigrationFailureListener(MongockEventListener::onFail) + .setTrackIgnored(true) + .setTransactionEnabled(true); + } + + + @Override + public void setConfiguration(CliConfiguration configuration) { + this.configuration = configuration; + this.driverWrapper = configuration.getDriverWrapper(); + } + + +} diff --git a/mongock-default-app/src/main/java/io/mongock/cli/app/events/MongockEventListener.java b/mongock-default-app/src/main/java/io/mongock/cli/app/events/MongockEventListener.java new file mode 100644 index 0000000..0d3a884 --- /dev/null +++ b/mongock-default-app/src/main/java/io/mongock/cli/app/events/MongockEventListener.java @@ -0,0 +1,20 @@ +package io.mongock.cli.app.events; + +import io.mongock.runner.core.event.MigrationFailureEvent; +import io.mongock.runner.core.event.MigrationStartedEvent; +import io.mongock.runner.core.event.MigrationSuccessEvent; + +public class MongockEventListener { + + public static void onStart(MigrationStartedEvent event) { + System.out.println("[EVENT LISTENER] - Mongock STARTED successfully"); + } + + public static void onSuccess(MigrationSuccessEvent event) { + System.out.println("[EVENT LISTENER] - Mongock finished successfully"); + } + + public static void onFail(MigrationFailureEvent event) { + System.out.println("[EVENT LISTENER] - Mongock finished with failures"); + } +} diff --git a/pom.xml b/pom.xml index c557806..2c585e2 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,9 @@ mongock-cli-springboot mongock-cli mongock-cli-util + mongock-default-app + driver-wrappers + mongock-default-app-professional 1.8 @@ -27,10 +30,12 @@ false [2.0.0, 3.0.0) 4.6.1 + 1.7.32 - 5.1.0 + 5.1.0-SNAPSHOT + 5.0.32-SNAPSHOT ossrh @@ -77,17 +82,17 @@ - - - - io.mongock - mongock-bom - ${mongock.version} - pom - import - - - + + + + + + + + + + +