diff --git a/.idea/compiler.xml b/.idea/compiler.xml index ef69357c69..e0cf3b031c 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -43,14 +43,16 @@ + + + + - - @@ -326,4 +328,4 @@ - + \ No newline at end of file diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index 4c35473fe7..fee301b3f7 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -515,8 +515,3 @@ fun SerializedBytes.checkPayloadIs(type: Class): Untrustworthy return type.castIfPossible(payloadData)?.let { UntrustworthyData(it) } ?: throw IllegalArgumentException("We were expecting a ${type.name} but we instead got a ${payloadData.javaClass.name} ($payloadData)") } - -/** - * Extension method to make this method visible to nodeapi module. - */ -fun MappedSchema.getMigrationResource(): String? = this.internalGetMigrationResource() \ No newline at end of file diff --git a/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt b/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt index fc6be347ec..e10ed86091 100644 --- a/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt +++ b/experimental/flow-worker/src/main/kotlin/net/corda/flowworker/FlowWorkerServiceHub.kt @@ -54,6 +54,7 @@ import net.corda.node.utilities.AffinityExecutor import net.corda.nodeapi.internal.DEV_ROOT_CA import net.corda.nodeapi.internal.crypto.X509Utilities import net.corda.nodeapi.internal.persistence.CordaPersistence +import net.corda.nodeapi.internal.persistence.isH2Database import net.corda.serialization.internal.* import org.apache.activemq.artemis.utils.ReusableLatch import rx.schedulers.Schedulers @@ -242,7 +243,10 @@ class FlowWorkerServiceHub(override val configuration: NodeConfiguration, overri servicesForResolution.start(networkParameters) persistentNetworkMapCache.start(networkParameters.notaries) - database.startHikariPool(configuration.dataSourceProperties, configuration.database, schemaService) + val isH2Database = isH2Database(configuration.dataSourceProperties.getProperty("dataSource.url", "")) + val schemas = if (isH2Database) schemaService.internalSchemas() else schemaService.schemaOptions.keys + + database.startHikariPool(configuration.dataSourceProperties, configuration.database, schemas) identityService.start(trustRoot, listOf(myInfo.legalIdentitiesAndCerts.first().certificate, nodeCa)) database.transaction { diff --git a/node-api/build.gradle b/node-api/build.gradle index 01452cb19c..2aa8f97de4 100644 --- a/node-api/build.gradle +++ b/node-api/build.gradle @@ -63,11 +63,6 @@ dependencies { // For caches rather than guava compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" - // For db migration - compile "org.liquibase:liquibase-core:$liquibase_version" - compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version" - runtime 'com.mattbertolini:liquibase-slf4j:2.0.0' - // Unit testing helpers. testCompile "junit:junit:$junit_version" testCompile "org.assertj:assertj-core:$assertj_version" diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/MigrationHelpers.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/MigrationHelpers.kt index b098574556..96686008fd 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/MigrationHelpers.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/MigrationHelpers.kt @@ -34,7 +34,7 @@ object MigrationHelpers { } // SchemaName will be transformed from camel case to lower_hyphen then add ".changelog-master" - private fun migrationResourceNameForSchema(schema: MappedSchema): String { + fun migrationResourceNameForSchema(schema: MappedSchema): String { val name: String = schema::class.simpleName!! val fileName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name) return "$MIGRATION_PREFIX/$fileName.$CHANGELOG_NAME" diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt index 0d15b28268..3364c7a468 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/SchemaMigration.kt @@ -42,13 +42,13 @@ class SchemaMigration( * Main entry point to the schema migration. * Called during node startup. */ - fun nodeStartup(existingCheckpoints: Boolean) { + fun nodeStartup(existingCheckpoints: Boolean, isH2Database: Boolean) { when { - databaseConfig.initialiseSchema -> { - //TODO if it's h2 only + databaseConfig.initialiseSchema && isH2Database -> { migrateOlderDatabaseToUseLiquibase(existingCheckpoints) runMigration(existingCheckpoints) } + databaseConfig.initialiseSchema -> runMigration(existingCheckpoints) else -> checkState() } } @@ -66,7 +66,7 @@ class SchemaMigration( /** * Ensures that the database is up to date with the latest migration changes. */ - private fun checkState() = doRunMigration(run = false, outputWriter = null, check = true) + fun checkState() = doRunMigration(run = false, outputWriter = null, check = true) /** * Can be used from an external tool to release the lock in case something went terribly wrong. @@ -138,7 +138,6 @@ class SchemaMigration( check && !run && unRunChanges.isNotEmpty() -> throw OutstandingDatabaseChangesException(unRunChanges.size) check && !run -> {} // Do nothing will be interpreted as "check succeeded" (outputWriter != null) && !check && !run -> liquibase.update(Contexts(), outputWriter) - (outputWriter != null) && !check && !run -> liquibase.update(Contexts(), outputWriter) else -> throw IllegalStateException("Invalid usage.") } } diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index f0de64bf0d..a7fe619f9a 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -149,8 +149,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, configuration.database, identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, - schemaService, - configuration.dataSourceProperties + schemaService ) init { // TODO Break cyclic dependency @@ -1049,11 +1048,10 @@ fun configureDatabase(hikariProperties: Properties, databaseConfig: DatabaseConfig, wellKnownPartyFromX500Name: (CordaX500Name) -> Party?, wellKnownPartyFromAnonymous: (AbstractParty) -> Party?, - schemaService: NodeSchemaService = NodeSchemaService()): CordaPersistence { - + schemaService: SchemaService = NodeSchemaService()): CordaPersistence { val isH2Database = isH2Database(hikariProperties.getProperty("dataSource.url", "")) - val schemas = if (isH2Database) schemaService.internalSchemas() else schemaService.schemaOptions.keys - createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService) + val schemas = if (isH2Database) NodeSchemaService().internalSchemas() else NodeSchemaService().schemaOptions.keys + return createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService) .apply { startHikariPool(hikariProperties, databaseConfig, schemas) } } @@ -1061,16 +1059,14 @@ fun configureDatabase(hikariProperties: Properties, fun createCordaPersistence(databaseConfig: DatabaseConfig, wellKnownPartyFromX500Name: (CordaX500Name) -> Party?, wellKnownPartyFromAnonymous: (AbstractParty) -> Party?, - schemaService: SchemaService, - hikariProperties: Properties): CordaPersistence { + schemaService: SchemaService): CordaPersistence { // Register the AbstractPartyDescriptor so Hibernate doesn't warn when encountering AbstractParty. Unfortunately // Hibernate warns about not being able to find a descriptor if we don't provide one, but won't use it by default // so we end up providing both descriptor and converter. We should re-examine this in later versions to see if // either Hibernate can be convinced to stop warning, use the descriptor by default, or something else. JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous)) val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous)) - val jdbcUrl = hikariProperties.getProperty("dataSource.url", "") - return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, jdbcUrl, attributeConverters) + return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, attributeConverters) } fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set) { @@ -1078,7 +1074,7 @@ fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfi val dataSource = DataSourceFactory.createDataSource(hikariProperties) val jdbcUrl = hikariProperties.getProperty("dataSource.url", "") val schemaMigration = SchemaMigration(schemas, dataSource, databaseConfig) - schemaMigration.nodeStartup(dataSource.connection.use { DBCheckpointStorage().getCheckpointCount(it) != 0L }) + schemaMigration.nodeStartup(dataSource.connection.use { DBCheckpointStorage().getCheckpointCount(it) != 0L }, isH2Database(jdbcUrl)) start(dataSource, jdbcUrl) } catch (ex: Exception) { when { diff --git a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt index 2b60955184..5ba3223ea8 100644 --- a/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt +++ b/node/src/main/kotlin/net/corda/node/services/schema/NodeSchemaService.kt @@ -75,10 +75,13 @@ class NodeSchemaService(private val extraSchemas: Set = emptySet() // Required schemas are those used by internal Corda services private val requiredSchemas: Map = mapOf(Pair(CommonSchemaV1, SchemaOptions()), - Pair(VaultSchemaV1, SchemaOptions()), - Pair(NodeInfoSchemaV1, SchemaOptions()), - Pair(NodeCoreV1, SchemaOptions())) + - if (includeNotarySchemas) mapOf(Pair(NodeNotaryV1, SchemaOptions())) else emptyMap() + Pair(VaultSchemaV1, SchemaOptions()), + Pair(NodeInfoSchemaV1, SchemaOptions()), + Pair(NodeCoreV1, SchemaOptions())) + + if (includeNotarySchemas) mapOf(Pair(NodeNotaryV1, SchemaOptions())) else emptyMap() + + fun internalSchemas() = requiredSchemas.keys + extraSchemas.filter { schema -> // when mapped schemas from the finance module are present, they are considered as internal ones + schema::class.simpleName == "net.corda.finance.schemas.CashSchemaV1" || schema::class.simpleName == "net.corda.finance.schemas.CommercialPaperSchemaV1" } override val schemaOptions: Map = requiredSchemas + extraSchemas.associateBy({ it }, { SchemaOptions() }) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt index 35ecb94c26..ec0289ef68 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/SchemaMigrationTest.kt @@ -60,7 +60,7 @@ class SchemaMigrationTest { val dataSourceProps = MockServices.makeTestDataSourceProperties() //run the migration on the database - val migration = SchemaMigration(schemaService.schemaOptions.keys, HikariDataSource(HikariConfig(dataSourceProps)), true, DatabaseConfig()) + val migration = SchemaMigration(schemaService.schemaOptions.keys, HikariDataSource(HikariConfig(dataSourceProps)), DatabaseConfig()) migration.runMigration(false) //start the node with "runMigration = false" and check that it started correctly diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 59aaf19db4..8c1f5dd7e5 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -114,7 +114,6 @@ open class MockServices private constructor( val cordappLoader = cordappLoaderForPackages(cordappPackages) val dataSourceProps = makeInternalTestDataSourceProperties(initialIdentity.name.organisation, SecureHash.randomSHA256().toString()) val schemaService = NodeSchemaService(cordappLoader.cordappSchemas) - //TODO different schemas based on h2 or not val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(initialIdentity.name.organisation), identityService::wellKnownPartyFromX500Name, identityService::wellKnownPartyFromAnonymous, schemaService) val mockService = database.transaction { object : MockServices(cordappLoader, identityService, networkParameters, initialIdentity, moreKeys) { 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 c282dc289b..4cd857126d 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 @@ -169,12 +169,12 @@ private fun handleCommand(options: OptionSet, baseDirectory: Path, configFile: P val config = parsedConfig.parseAs(Configuration::class, UnknownConfigKeysPolicy.IGNORE::handle) fun runMigrationCommand(withMigration: (SchemaMigration, DataSource) -> Unit): Unit = runWithDataSource(config, baseDirectory, classLoader) { dataSource -> - withMigration(SchemaMigration(schemas, dataSource, true, config.database, classLoader), dataSource) + withMigration(SchemaMigration(schemas, dataSource, config.database, classLoader), dataSource) } when { 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() + SchemaMigration(emptySet(), it, config.database, Thread.currentThread().contextClassLoader).forceReleaseMigrationLock() } options.has(DRY_RUN) -> { val writer = getMigrationOutput(baseDirectory, options)