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 55f72dc451..3472db31b4 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -185,8 +185,9 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, check(started == null) { "Node has already been started" } initCertificate() log.info("Generating nodeInfo ...") - initialiseDatabasePersistence { - makeServices() + val schemaService = NodeSchemaService() + initialiseDatabasePersistence(schemaService) { + makeServices(schemaService) saveOwnNodeInfo() } } @@ -195,9 +196,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, check(started == null) { "Node has already been started" } initCertificate() log.info("Node starting up ...") + val schemaService = NodeSchemaService() // Do all of this in a database transaction so anything that might need a connection has one. - val startedImpl = initialiseDatabasePersistence { - val tokenizableServices = makeServices() + val startedImpl = initialiseDatabasePersistence(schemaService) { + val tokenizableServices = makeServices(schemaService) saveOwnNodeInfo() smm = StateMachineManager(services, checkpointStorage, @@ -391,10 +393,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, * Builds node internal, advertised, and plugin services. * Returns a list of tokenizable services to be added to the serialisation context. */ - private fun makeServices(): MutableList { + private fun makeServices(schemaService: SchemaService): MutableList { checkpointStorage = DBCheckpointStorage() cordappProvider = CordappProviderImpl(cordappLoader) - _services = ServiceHubInternalImpl() + _services = ServiceHubInternalImpl(schemaService) attachments = NodeAttachmentService(services.monitoringService.metrics) cordappProvider.start(attachments) legalIdentity = obtainIdentity() @@ -482,10 +484,10 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, // Specific class so that MockNode can catch it. class DatabaseConfigurationException(msg: String) : CordaException(msg) - protected open fun initialiseDatabasePersistence(insideTransaction: () -> T): T { + protected open fun initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T { val props = configuration.dataSourceProperties if (props.isNotEmpty()) { - this.database = configureDatabase(props, configuration.database, { _services.schemaService }, createIdentityService = { _services.identityService }) + this.database = configureDatabase(props, configuration.database, schemaService, { _services.identityService }) // Now log the vendor string as this will also cause a connection to be tested eagerly. database.transaction { log.info("Connected to ${database.dataSource.connection.metaData.databaseProductName} database.") @@ -689,15 +691,13 @@ abstract class AbstractNode(open val configuration: NodeConfiguration, protected open fun generateKeyPair() = cryptoGenerateKeyPair() - private inner class ServiceHubInternalImpl : ServiceHubInternal, SingletonSerializeAsToken() { - + private inner class ServiceHubInternalImpl(override val schemaService: SchemaService) : ServiceHubInternal, SingletonSerializeAsToken() { override val rpcFlows = ArrayList>>() override val stateMachineRecordedTransactionMapping = DBTransactionMappingStorage() override val auditService = DummyAuditService() override val monitoringService = MonitoringService(MetricRegistry()) override val validatedTransactions = makeTransactionStorage() override val transactionVerifierService by lazy { makeTransactionVerifierService() } - override val schemaService by lazy { NodeSchemaService() } override val networkMapCache by lazy { PersistentNetworkMapCache(this) } override val vaultService by lazy { NodeVaultService(this, database.hibernateConfig) } override val contractUpgradeService by lazy { ContractUpgradeServiceImpl() } diff --git a/node/src/main/kotlin/net/corda/node/internal/Node.kt b/node/src/main/kotlin/net/corda/node/internal/Node.kt index 7a183e2894..31cb1cb27f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/Node.kt +++ b/node/src/main/kotlin/net/corda/node/internal/Node.kt @@ -15,11 +15,11 @@ import net.corda.core.node.ServiceHub import net.corda.core.serialization.SerializationDefaults import net.corda.core.utilities.* import net.corda.node.VersionInfo -import net.corda.node.internal.cordapp.CordappProviderImpl import net.corda.node.serialization.KryoServerSerializationScheme import net.corda.node.serialization.NodeClock import net.corda.node.services.RPCUserService import net.corda.node.services.RPCUserServiceImpl +import net.corda.node.services.api.SchemaService import net.corda.nodeapi.internal.ServiceInfo import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.services.messaging.ArtemisMessagingServer @@ -287,7 +287,7 @@ open class Node(override val configuration: FullNodeConfiguration, * This is not using the H2 "automatic mixed mode" directly but leans on many of the underpinnings. For more details * on H2 URLs and configuration see: http://www.h2database.com/html/features.html#database_url */ - override fun initialiseDatabasePersistence(insideTransaction: () -> T): T { + override fun initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T): T { val databaseUrl = configuration.dataSourceProperties.getProperty("dataSource.url") val h2Prefix = "jdbc:h2:file:" if (databaseUrl != null && databaseUrl.startsWith(h2Prefix)) { @@ -304,7 +304,7 @@ open class Node(override val configuration: FullNodeConfiguration, printBasicNodeInfo("Database connection url is", "jdbc:h2:$url/node") } } - return super.initialiseDatabasePersistence(insideTransaction) + return super.initialiseDatabasePersistence(schemaService, insideTransaction) } private val _startupComplete = openFuture() diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt index cbec0c793c..73d8f77dff 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/HibernateConfiguration.kt @@ -24,7 +24,7 @@ import java.sql.Connection import java.util.* import java.util.concurrent.ConcurrentHashMap -class HibernateConfiguration(createSchemaService: () -> SchemaService, private val databaseProperties: Properties, private val createIdentityScervice: () -> IdentityService) { +class HibernateConfiguration(val schemaService: SchemaService, private val databaseProperties: Properties, private val createIdentityService: () -> IdentityService) { companion object { val logger = loggerFor() } @@ -33,7 +33,6 @@ class HibernateConfiguration(createSchemaService: () -> SchemaService, private v private val sessionFactories = ConcurrentHashMap, SessionFactory>() private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?:"") - var schemaService = createSchemaService() init { logger.info("Init HibernateConfiguration for schemas: ${schemaService.schemaOptions.keys}") @@ -86,7 +85,7 @@ class HibernateConfiguration(createSchemaService: () -> SchemaService, private v } }) // register custom converters - applyAttributeConverter(AbstractPartyToX500NameAsStringConverter(createIdentityScervice)) + applyAttributeConverter(AbstractPartyToX500NameAsStringConverter(createIdentityService)) // Register a tweaked version of `org.hibernate.type.MaterializedBlobType` that truncates logged messages. // to avoid OOM when large blobs might get logged. applyBasicType(CordaMaterializedBlobType, CordaMaterializedBlobType.name) diff --git a/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt b/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt index de78ac1071..c1d6d8d0b7 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/CordaPersistence.kt @@ -23,13 +23,13 @@ import java.util.concurrent.CopyOnWriteArrayList const val NODE_DATABASE_PREFIX = "node_" //HikariDataSource implements Closeable which allows CordaPersistence to be Closeable -class CordaPersistence(var dataSource: HikariDataSource, private var createSchemaService: () -> SchemaService, +class CordaPersistence(var dataSource: HikariDataSource, private val schemaService: SchemaService, private val createIdentityService: ()-> IdentityService, databaseProperties: Properties): Closeable { var transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel")) val hibernateConfig: HibernateConfiguration by lazy { transaction { - HibernateConfiguration(createSchemaService, databaseProperties, createIdentityService) + HibernateConfiguration(schemaService, databaseProperties, createIdentityService) } } @@ -40,8 +40,8 @@ class CordaPersistence(var dataSource: HikariDataSource, private var createSchem } companion object { - fun connect(dataSource: HikariDataSource, createSchemaService: () -> SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence { - return CordaPersistence(dataSource, createSchemaService, createIdentityService, databaseProperties).apply { + fun connect(dataSource: HikariDataSource, schemaService: SchemaService, createIdentityService: () -> IdentityService, databaseProperties: Properties): CordaPersistence { + return CordaPersistence(dataSource, schemaService, createIdentityService, databaseProperties).apply { DatabaseTransactionManager(this) } } @@ -107,10 +107,10 @@ class CordaPersistence(var dataSource: HikariDataSource, private var createSchem } } -fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, createSchemaService: () -> SchemaService = { NodeSchemaService() }, createIdentityService: () -> IdentityService): CordaPersistence { +fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, schemaService: SchemaService = NodeSchemaService(), createIdentityService: () -> IdentityService): CordaPersistence { val config = HikariConfig(dataSourceProperties) val dataSource = HikariDataSource(config) - val persistence = CordaPersistence.connect(dataSource, createSchemaService, createIdentityService, databaseProperties ?: Properties()) + val persistence = CordaPersistence.connect(dataSource, schemaService, createIdentityService, databaseProperties ?: Properties()) // Check not in read-only mode. persistence.transaction { diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt index 4ea017461d..e13460aea9 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/DBTransactionStorageTests.kt @@ -42,11 +42,7 @@ class DBTransactionStorageTests : TestDependencyInjectionBase() { fun setUp() { LogHelper.setLevel(PersistentUniquenessProvider::class) val dataSourceProps = makeTestDataSourceProperties() - - val createSchemaService = { NodeSchemaService() } - - database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), createSchemaService, ::makeTestIdentityService) - + database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), NodeSchemaService(), ::makeTestIdentityService) database.transaction { services = object : MockServices(BOB_KEY) { diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt index a5ac113dc6..79c4650c61 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/HibernateConfigurationTest.kt @@ -77,8 +77,7 @@ class HibernateConfigurationTest : TestDependencyInjectionBase() { issuerServices = MockServices(DUMMY_CASH_ISSUER_KEY, BOB_KEY, BOC_KEY) val dataSourceProps = makeTestDataSourceProperties() val defaultDatabaseProperties = makeTestDatabaseProperties() - val createSchemaService = { NodeSchemaService() } - database = configureDatabase(dataSourceProps, defaultDatabaseProperties, createSchemaService, ::makeTestIdentityService) + database = configureDatabase(dataSourceProps, defaultDatabaseProperties, NodeSchemaService(), ::makeTestIdentityService) database.transaction { hibernateConfig = database.hibernateConfig services = object : MockServices(BOB_KEY, BOC_KEY, DUMMY_NOTARY_KEY) { diff --git a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt b/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt index 7472b66b02..44fc3cb47b 100644 --- a/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt +++ b/node/src/test/kotlin/net/corda/node/services/schema/HibernateObserverTests.kt @@ -70,8 +70,7 @@ class HibernateObserverTests { return parent } } - val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), { schemaService }, createIdentityService = ::makeTestIdentityService) - + val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), schemaService, createIdentityService = ::makeTestIdentityService) @Suppress("UNUSED_VARIABLE") val observer = HibernateObserver(rawUpdatesPublisher, database.hibernateConfig) database.transaction { diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt index ea351fe8f1..92a40391b5 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt @@ -26,6 +26,7 @@ import net.corda.core.utilities.loggerFor import net.corda.finance.utils.WorldMapLocation import net.corda.node.internal.AbstractNode import net.corda.node.internal.StartedNode +import net.corda.node.services.api.SchemaService import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.identity.PersistentIdentityService import net.corda.node.services.keys.E2ETestKeyManagementService @@ -248,7 +249,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, @Suppress("unused") val place: WorldMapLocation get() = findMyLocation()!! private var dbCloser: (() -> Any?)? = null - override fun initialiseDatabasePersistence(insideTransaction: () -> T) = super.initialiseDatabasePersistence { + override fun initialiseDatabasePersistence(schemaService: SchemaService, insideTransaction: () -> T) = super.initialiseDatabasePersistence(schemaService) { dbCloser = database::close insideTransaction() } 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 7338a6c68f..367dcad228 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 @@ -100,9 +100,8 @@ open class MockServices(cordappPackages: List = emptyList(), vararg val cordappPackages: List = emptyList()): Pair { val dataSourceProps = makeTestDataSourceProperties() val databaseProperties = makeTestDatabaseProperties() - val createSchemaService = { NodeSchemaService(customSchemas) } val identityServiceRef: IdentityService by lazy { createIdentityService() } - val database = configureDatabase(dataSourceProps, databaseProperties, createSchemaService, { identityServiceRef }) + val database = configureDatabase(dataSourceProps, databaseProperties, NodeSchemaService(customSchemas), { identityServiceRef }) val mockService = database.transaction { object : MockServices(cordappPackages, *(keys.toTypedArray())) { override val identityService: IdentityService = database.transaction { identityServiceRef } @@ -158,7 +157,7 @@ open class MockServices(cordappPackages: List = emptyList(), vararg val lateinit var hibernatePersister: HibernateObserver - fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration( { NodeSchemaService() }, makeTestDatabaseProperties(), { identityService })): VaultService { + fun makeVaultService(hibernateConfig: HibernateConfiguration = HibernateConfiguration(NodeSchemaService(), makeTestDatabaseProperties(), { identityService })): VaultService { val vaultService = NodeVaultService(this, hibernateConfig) hibernatePersister = HibernateObserver(vaultService.rawUpdates, hibernateConfig) return vaultService diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt index 726b0c5202..cfb1e3a29d 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt @@ -37,7 +37,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort val monitoringService = MonitoringService(MetricRegistry()) val identity: KeyPair = generateKeyPair() val identityService: IdentityService = InMemoryIdentityService(trustRoot = trustRoot) - val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, { NodeSchemaService() }, { InMemoryIdentityService(trustRoot = trustRoot) }) + val database: CordaPersistence = configureDatabase(config.dataSourceProperties, config.database, NodeSchemaService(), { InMemoryIdentityService(trustRoot = trustRoot) }) val keyService: KeyManagementService = E2ETestKeyManagementService(identityService, setOf(identity)) val executor = ServiceAffinityExecutor(config.myLegalName.organisation, 1) // TODO: We should have a dummy service hub rather than change behaviour in tests