diff --git a/libraries.gradle b/libraries.gradle
index f58eb9b37e..a05a25521b 100644
--- a/libraries.gradle
+++ b/libraries.gradle
@@ -19,6 +19,7 @@ ext {
httpAsyncClientVersion = '4.1.4'
mysqlJDBCVersion = '8.0.15'
c3p0Version = '0.9.5.3'
+ flywaydbVersion = '6.0.4'
libraries = [
//jUnit (Tests)
@@ -111,10 +112,10 @@ ext {
jsonSchemaValidator: "com.github.java-json-tools:json-schema-validator:${jsonSchemaVersion}",
guava: "com.google.guava:guava:${guavaVersion}",
- httpAsyncClient: "org.apache.httpcomponents:httpasyncclient:${httpAsyncClientVersion}"
+ httpAsyncClient: "org.apache.httpcomponents:httpasyncclient:${httpAsyncClientVersion}",
+ flywaydb: "org.flywaydb:flyway-core:${flywaydbVersion}"
]
-
jsonSchemaValidatorLibs = [
libraries.jsonSchemaValidator,
libraries.guava
diff --git a/modules/db-flyway/build.gradle b/modules/db-flyway/build.gradle
new file mode 100644
index 0000000000..335cefa3b7
--- /dev/null
+++ b/modules/db-flyway/build.gradle
@@ -0,0 +1,11 @@
+description = 'jPOS-EE :: flyWay support'
+
+dependencies {
+ compile project(':modules:dbsupport')
+ compile project(':modules:db-postgresql')
+ compile project(':modules:logback')
+ compile libraries.flywaydb
+}
+
+apply from: "${rootProject.projectDir}/jpos-app.gradle"
+
diff --git a/modules/db-flyway/src/main/java/org/jpos/flyway/FlywaySupport.java b/modules/db-flyway/src/main/java/org/jpos/flyway/FlywaySupport.java
new file mode 100644
index 0000000000..80c7f4a56c
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/flyway/FlywaySupport.java
@@ -0,0 +1,63 @@
+package org.jpos.flyway;
+
+import org.flywaydb.core.Flyway;
+import org.flywaydb.core.api.configuration.FluentConfiguration;
+import org.flywaydb.core.api.logging.Log;
+import org.flywaydb.core.api.logging.LogCreator;
+import org.flywaydb.core.api.logging.LogFactory;
+import org.jpos.ee.DB;
+
+import java.util.Arrays;
+import java.util.Properties;
+
+public class FlywaySupport implements LogCreator, Log {
+ protected Flyway getFlyway(String configModifier, String args[]) {
+ LogFactory.setFallbackLogCreator(this);
+ Properties p = new DB(configModifier).getProperties();
+ FluentConfiguration config = Flyway.configure().dataSource(
+ p.getProperty("hibernate.connection.url"),
+ p.getProperty("hibernate.connection.username"),
+ p.getProperty("hibernate.connection.password"))
+ .outOfOrder(has(args, "--out-of-order"));
+ return config.load();
+ }
+
+ public Log createLogger(Class> clazz) {
+ return this;
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return true;
+ }
+
+ @Override
+ public void debug(String message) {
+ System.out.println("DEBUG: " + message);
+ }
+
+ @Override
+ public void info(String message) {
+ System.out.println(message);
+ }
+
+ @Override
+ public void warn(String message) {
+ System.err.println("WARNING: " + message);
+ }
+
+ @Override
+ public void error(String message) {
+ System.err.println("ERROR: " + message);
+ }
+
+ @Override
+ public void error(String message, Exception e) {
+ System.err.println("ERROR: " + message);
+ e.printStackTrace(System.err);
+ }
+
+ private boolean has (String[] args, String arg) {
+ return Arrays.stream(args).anyMatch(s -> s.equals(arg));
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/FLYWAY.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/FLYWAY.java
new file mode 100644
index 0000000000..51c4ba52b7
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/FLYWAY.java
@@ -0,0 +1,55 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2019 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.q2.cli;
+
+import org.flywaydb.core.Flyway;
+import org.jpos.ee.DB;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.CLISubSystem;
+
+import java.util.Properties;
+
+public class FLYWAY implements CLISubSystem {
+ public static final String PREFIX = "flyway.dbmodifier";
+
+ @Override
+ public String getPrompt(CLIContext ctx, String[] args) {
+ String prefix = null;
+ if (args.length > 1) {
+ prefix = args[1];
+ ctx.getUserData().put(PREFIX, prefix);
+ } else {
+ ctx.getUserData().remove(PREFIX);
+ }
+ return "flyway" + (prefix != null ? "[" + args[1] + "]" : "") + "> ";
+ }
+
+ @Override
+ public String[] getCompletionPrefixes(CLIContext ctx, String[] args) {
+ return new String[] { "org.jpos.q2.cli.flyway." };
+ }
+
+ private Flyway getFlyWay() {
+ Properties p = new DB().getProperties();
+ return Flyway.configure().dataSource(
+ p.getProperty("hibernate.connection.url"),
+ p.getProperty("hibernate.connection.username"),
+ p.getProperty("hibernate.connection.password")).load();
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/BASELINE.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/BASELINE.java
new file mode 100644
index 0000000000..38dca76ee6
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/BASELINE.java
@@ -0,0 +1,13 @@
+package org.jpos.q2.cli.flyway;
+
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class BASELINE extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) {
+ getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args).baseline();
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/CLEAN.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/CLEAN.java
new file mode 100644
index 0000000000..4c1f23dc49
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/CLEAN.java
@@ -0,0 +1,22 @@
+package org.jpos.q2.cli.flyway;
+
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class CLEAN extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) {
+ boolean superSure = false;
+ boolean sure = cli.confirm("Are you sure you want to Clean your database (Yes/No) ? ");
+ if (sure)
+ superSure = cli.confirm("This action can not be reversed - still want to proceed (Yes/No) ? ");
+
+ if (superSure)
+ getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args).clean();
+ else {
+ cli.println ("No action taken");
+ }
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/INFO.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/INFO.java
new file mode 100644
index 0000000000..ece44a726b
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/INFO.java
@@ -0,0 +1,26 @@
+package org.jpos.q2.cli.flyway;
+
+import org.flywaydb.core.Flyway;
+import org.flywaydb.core.api.MigrationInfo;
+import org.flywaydb.core.api.MigrationInfoService;
+import org.flywaydb.core.api.MigrationVersion;
+import org.flywaydb.core.internal.info.MigrationInfoDumper;
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class INFO extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) throws Exception {
+ Flyway flyway = getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args);
+ MigrationInfoService info = flyway.info();
+ MigrationInfo current = info.current();
+ MigrationVersion currentSchemaVersion = current == null ? MigrationVersion.EMPTY : current.getVersion();
+ MigrationVersion schemaVersionToOutput = currentSchemaVersion == null ? MigrationVersion.EMPTY : currentSchemaVersion;
+
+ cli.println ("Schema version: " + schemaVersionToOutput);
+ cli.println ("");
+ cli.println(MigrationInfoDumper.dumpToAsciiTable(info.all()));
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/MIGRATE.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/MIGRATE.java
new file mode 100644
index 0000000000..58feec04fd
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/MIGRATE.java
@@ -0,0 +1,15 @@
+package org.jpos.q2.cli.flyway;
+
+import org.flywaydb.core.Flyway;
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class MIGRATE extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) {
+ Flyway flyway = getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args);
+ flyway.migrate();
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/REPAIR.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/REPAIR.java
new file mode 100644
index 0000000000..cb4c307c5f
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/REPAIR.java
@@ -0,0 +1,13 @@
+package org.jpos.q2.cli.flyway;
+
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class REPAIR extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) {
+ getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args).repair();
+ }
+}
diff --git a/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/VALIDATE.java b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/VALIDATE.java
new file mode 100644
index 0000000000..788ea101f1
--- /dev/null
+++ b/modules/db-flyway/src/main/java/org/jpos/q2/cli/flyway/VALIDATE.java
@@ -0,0 +1,13 @@
+package org.jpos.q2.cli.flyway;
+
+import org.jpos.flyway.FlywaySupport;
+import org.jpos.q2.CLICommand;
+import org.jpos.q2.CLIContext;
+import org.jpos.q2.cli.FLYWAY;
+
+public class VALIDATE extends FlywaySupport implements CLICommand{
+ @Override
+ public void exec(CLIContext cli, String[] args) {
+ getFlyway((String) cli.getUserData().get(FLYWAY.PREFIX), args).validate();
+ }
+}
diff --git a/modules/dbsupport/src/main/java/org/jpos/ee/DB.java b/modules/dbsupport/src/main/java/org/jpos/ee/DB.java
index 0335b1b396..0cde891362 100644
--- a/modules/dbsupport/src/main/java/org/jpos/ee/DB.java
+++ b/modules/dbsupport/src/main/java/org/jpos/ee/DB.java
@@ -77,6 +77,7 @@ public class DB implements Closeable {
private static final String MODULES_CONFIG_PATH = "META-INF/org/jpos/ee/modules/";
private static Map sessionFactories = Collections.synchronizedMap(new HashMap<>());
private static Map metadatas = Collections.synchronizedMap(new HashMap<>());
+ private static Map properties = Collections.synchronizedMap(new HashMap<>());
/**
* Creates DB Object using default Hibernate instance
@@ -110,6 +111,7 @@ public DB (String configModifier) {
this.configModifier = configModifier;
sfSems.putIfAbsent(configModifier, new Semaphore(1));
mdSems.putIfAbsent(configModifier, new Semaphore(1));
+ getSessionFactory();
}
/**
@@ -118,7 +120,7 @@ public DB (String configModifier) {
* @param log Log object
*/
public DB(Log log) {
- super();
+ this();
setLog(log);
}
@@ -158,6 +160,11 @@ public SessionFactory getSessionFactory() {
return sf;
}
+ public Properties getProperties() {
+ String cm = configModifier != null ? configModifier : "";
+ return properties.get(cm);
+ }
+
public Dialect getDialect() {
return dialect;
}
@@ -494,6 +501,7 @@ public void printStats()
}
}
+
@Override
public String toString() {
return "DB{" + (configModifier != null ? configModifier : "") + '}';
@@ -533,10 +541,11 @@ private Metadata getMetadata() throws IOException, ConfigurationException, Docum
ssrb.configure(hibCfg);
propFile = System.getProperty(dbPropertiesPrefix + "DB_PROPERTIES", "cfg/" + dbPropertiesPrefix + "db.properties");
Properties dbProps = loadProperties(propFile);
- if (dbProps != null) {
- for (Map.Entry entry : dbProps.entrySet()) {
- ssrb.applySetting((String) entry.getKey(), Environment.get((String) entry.getValue()));
- }
+ for (Map.Entry entry : dbProps.entrySet()) {
+ String k = (String) entry.getKey();
+ String v = Environment.get((String) entry.getValue());
+ ssrb.applySetting(k,v);
+ dbProps.setProperty(k,v);
}
// if DBInstantiator has put db user name and/or password in Space, set Hibernate config accordingly
@@ -548,6 +557,7 @@ private Metadata getMetadata() throws IOException, ConfigurationException, Docum
if (pass != null)
ssrb.applySetting("hibernate.connection.password", pass);
+
MetadataSources mds = new MetadataSources(ssrb.build());
List moduleConfigs = ModuleUtils.getModuleEntries(MODULES_CONFIG_PATH);
for (String moduleConfig : moduleConfigs) {
@@ -560,6 +570,7 @@ private Metadata getMetadata() throws IOException, ConfigurationException, Docum
}
md = mds.buildMetadata();
metadatas.put(cm, md);
+ properties.put(cm, dbProps);
}
} finally {
mdSem.release();
diff --git a/settings.gradle b/settings.gradle
index eb627fcb4b..9b1a6e3192 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -42,7 +42,8 @@ include ':modules:core',
':modules:iso-http-server',
':modules:iso-http-servlet',
':modules:http-client',
- ':modules:seqno'
+ ':modules:seqno',
+ ':modules:db-flyway'
rootProject.name = 'jposee'