diff --git a/tools/dbmigration/build.gradle b/tools/dbmigration/build.gradle index 0bf49b19f9..99c49304f9 100644 --- a/tools/dbmigration/build.gradle +++ b/tools/dbmigration/build.gradle @@ -37,6 +37,7 @@ dependencies{ shadowJar { transform(de.sebastianboegl.gradle.plugins.shadow.transformers.Log4j2PluginsFileTransformer) + archiveName = "migration-tool-${version}.jar" } - +task buildMigrationTool(dependsOn: shadowJar) \ No newline at end of file diff --git a/tools/dbmigration/src/main/kotlin/com/r3/corda/dbmigration/Launcher.kt b/tools/dbmigration/src/main/kotlin/com/r3/corda/dbmigration/Launcher.kt index e6a3d08a2d..dc82cd9e66 100644 --- a/tools/dbmigration/src/main/kotlin/com/r3/corda/dbmigration/Launcher.kt +++ b/tools/dbmigration/src/main/kotlin/com/r3/corda/dbmigration/Launcher.kt @@ -13,8 +13,7 @@ package com.r3.corda.dbmigration import com.typesafe.config.ConfigFactory -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource +import com.zaxxer.hikari.util.PropertyElf import joptsimple.OptionException import joptsimple.OptionParser import joptsimple.OptionSet @@ -37,6 +36,7 @@ import java.io.FileWriter import java.io.PrintWriter import java.io.Writer import java.net.URLClassLoader +import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.text.SimpleDateFormat @@ -71,7 +71,7 @@ private fun initOptionParser(): OptionParser = OptionParser().apply { .defaultsTo(Mode.NODE) accepts(BASE_DIRECTORY, "The node or doorman directory") - .withRequiredArg() + .withRequiredArg().required() accepts(CONFIG, "The name of the config file. By default 'node.conf' for a simple node and 'network-management.conf' for a doorman.") .withOptionalArg() @@ -141,12 +141,12 @@ private fun runCommand(options: OptionSet, parser: OptionParser) { private fun handleCommand(options: OptionSet, baseDirectory: Path, configFile: Path, mode: Mode, classLoader: ClassLoader, schemas: Set) { val config = ConfigFactory.parseFile(configFile.toFile()).resolve().parseAs(Configuration::class, false) - fun runMigrationCommand(withMigration: (SchemaMigration) -> Unit): Unit = runWithDataSource(config) { dataSource -> + fun runMigrationCommand(withMigration: (SchemaMigration) -> Unit): Unit = runWithDataSource(config, baseDirectory, classLoader) { dataSource -> withMigration(SchemaMigration(schemas, dataSource, true, config.database, classLoader)) } when { - options.has(RELEASE_LOCK) -> runWithDataSource(ConfigFactory.parseFile(configFile.toFile()).resolve().parseAs(Configuration::class)) { + options.has(RELEASE_LOCK) -> runWithDataSource(ConfigFactory.parseFile(configFile.toFile()).resolve().parseAs(Configuration::class), baseDirectory, classLoader) { SchemaMigration(emptySet(), it, true, config.database, Thread.currentThread().contextClassLoader).forceReleaseMigrationLock() } options.has(DRY_RUN) -> { @@ -165,7 +165,7 @@ private fun handleCommand(options: OptionSet, baseDirectory: Path, configFile: P fun generateMigrationFileForSchema(schemaClass: String) { logger.info("Creating database migration files for schema: $schemaClass into ${baseDirectory / "migration"}") try { - runWithDataSource(config) { + runWithDataSource(config, baseDirectory, classLoader) { MigrationExporter(baseDirectory, config.dataSourceProperties, classLoader, it).generateMigrationForCorDapp(schemaClass) } } catch (e: Exception) { @@ -211,11 +211,22 @@ private fun getMigrationOutput(baseDirectory: Path, options: OptionSet): Writer } } -private fun runWithDataSource(config: Configuration, withDatasource: (DataSource) -> Unit) { - val cfg = HikariConfig(config.dataSourceProperties) - cfg.maximumPoolSize = 1 - return HikariDataSource(cfg).use { dataSource -> - withDatasource(dataSource) +private fun runWithDataSource(config: Configuration, baseDirectory: Path, classLoader: ClassLoader, withDatasource: (DataSource) -> Unit) { + val driversFolder = baseDirectory / "drivers" + val dataSourceClass = config.dataSourceProperties["dataSourceClassName"] as String? + + return URLClassLoader(Files.newDirectoryStream(driversFolder, "*.jar").map { it.toUri().toURL() }.toTypedArray(), classLoader).use { driversClassLoader -> + val driverClass = driversClassLoader.loadClass(dataSourceClass) + val dataSourceInstance = driverClass.newInstance() as DataSource + + val props = Properties().also { + it.putAll(config.dataSourceProperties.propertyNames().toList() + .filter { name -> (name as String).startsWith("dataSource.") } + .map { name -> (name as String).substring("dataSource.".length) to (config.dataSourceProperties[name]) }.toMap()) + } + PropertyElf.setTargetFromProperties(dataSourceInstance, props) + + withDatasource(dataSourceInstance) } }