decouple Exposed (#1028)

Exposed library decoupled from transaction management and JDBC connection creation for Hibernate and ReQuery
This commit is contained in:
szymonsztuka 2017-07-14 14:39:59 +01:00 committed by GitHub
parent 1996c39b9a
commit 05327f3826
59 changed files with 503 additions and 545 deletions

View File

@ -16,7 +16,6 @@ import net.corda.core.utilities.OpaqueBytes
import net.corda.flows.CashIssueFlow import net.corda.flows.CashIssueFlow
import net.corda.node.internal.CordaRPCOpsImpl import net.corda.node.internal.CordaRPCOpsImpl
import net.corda.node.services.startFlowPermission import net.corda.node.services.startFlowPermission
import net.corda.node.utilities.transaction
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.testing.RPCDriverExposedDSLInterface import net.corda.testing.RPCDriverExposedDSLInterface
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract

View File

@ -7,7 +7,6 @@ import net.corda.core.identity.Party
import net.corda.core.utilities.opaque import net.corda.core.utilities.opaque
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.testing.DUMMY_NOTARY_KEY import net.corda.testing.DUMMY_NOTARY_KEY
import net.corda.node.utilities.transaction
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.MEGA_CORP_KEY import net.corda.testing.MEGA_CORP_KEY
import net.corda.testing.MINI_CORP import net.corda.testing.MINI_CORP

View File

@ -18,7 +18,6 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.persistence.schemas.requery.AttachmentEntity import net.corda.node.services.persistence.schemas.requery.AttachmentEntity
import net.corda.node.services.statemachine.SessionInit import net.corda.node.services.statemachine.SessionInit
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before

View File

@ -10,7 +10,6 @@ import net.corda.testing.DUMMY_NOTARY_KEY
import net.corda.flows.CashIssueFlow import net.corda.flows.CashIssueFlow
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before

View File

@ -14,7 +14,6 @@ import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_NOTARY_KEY import net.corda.testing.DUMMY_NOTARY_KEY
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before

View File

@ -11,7 +11,6 @@ import net.corda.core.node.services.VaultService
import net.corda.core.seconds import net.corda.core.seconds
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
@ -212,8 +211,7 @@ class CommercialPaperTestsGeneric {
fun `issue move and then redeem`() { fun `issue move and then redeem`() {
val dataSourcePropsAlice = makeTestDataSourceProperties() val dataSourcePropsAlice = makeTestDataSourceProperties()
val dataSourceAndDatabaseAlice = configureDatabase(dataSourcePropsAlice) val databaseAlice = configureDatabase(dataSourcePropsAlice)
val databaseAlice = dataSourceAndDatabaseAlice.second
databaseAlice.transaction { databaseAlice.transaction {
aliceServices = object : MockServices(ALICE_KEY) { aliceServices = object : MockServices(ALICE_KEY) {
@ -232,8 +230,7 @@ class CommercialPaperTestsGeneric {
} }
val dataSourcePropsBigCorp = makeTestDataSourceProperties() val dataSourcePropsBigCorp = makeTestDataSourceProperties()
val dataSourceAndDatabaseBigCorp = configureDatabase(dataSourcePropsBigCorp) val databaseBigCorp = configureDatabase(dataSourcePropsBigCorp)
val databaseBigCorp = dataSourceAndDatabaseBigCorp.second
databaseBigCorp.transaction { databaseBigCorp.transaction {
bigCorpServices = object : MockServices(BIG_CORP_KEY) { bigCorpServices = object : MockServices(BIG_CORP_KEY) {

View File

@ -14,16 +14,14 @@ import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.MockKeyManagementService import net.corda.testing.node.MockKeyManagementService
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.jetbrains.exposed.sql.Database
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.security.KeyPair import java.security.KeyPair
import java.util.* import java.util.*
import kotlin.test.* import kotlin.test.*
@ -45,17 +43,14 @@ class CashTests {
lateinit var miniCorpServices: MockServices lateinit var miniCorpServices: MockServices
val vault: VaultService get() = miniCorpServices.vaultService val vault: VaultService get() = miniCorpServices.vaultService
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var vaultStatesUnconsumed: List<StateAndRef<Cash.State>> lateinit var vaultStatesUnconsumed: List<StateAndRef<Cash.State>>
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(NodeVaultService::class) LogHelper.setLevel(NodeVaultService::class)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
miniCorpServices = object : MockServices(MINI_CORP_KEY) { miniCorpServices = object : MockServices(MINI_CORP_KEY) {
override val keyManagementService: MockKeyManagementService = MockKeyManagementService(identityService, MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY) override val keyManagementService: MockKeyManagementService = MockKeyManagementService(identityService, MINI_CORP_KEY, MEGA_CORP_KEY, OUR_KEY)

View File

@ -9,7 +9,6 @@ import net.corda.core.node.services.Vault
import net.corda.core.node.services.trackBy import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.node.utilities.transaction
import net.corda.testing.expect import net.corda.testing.expect
import net.corda.testing.expectEvents import net.corda.testing.expectEvents
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin

View File

@ -14,7 +14,6 @@ import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.flows.IssuerFlow.IssuanceRequester import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.calculateRandomlySizedAmounts import net.corda.testing.contracts.calculateRandomlySizedAmounts
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork

View File

@ -21,7 +21,6 @@ import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.minClusterSize import net.corda.node.services.transactions.minClusterSize
import net.corda.node.services.transactions.minCorrectReplicas import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.node.utilities.ServiceIdentityGenerator import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.node.utilities.transaction
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name

View File

@ -11,7 +11,6 @@ import net.corda.core.getOrThrow
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.map import net.corda.core.map
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
import net.corda.node.utilities.transaction
import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.NodeBasedTest import net.corda.testing.node.NodeBasedTest

View File

@ -12,13 +12,11 @@ import com.google.common.collect.testing.testers.*
import junit.framework.TestSuite import junit.framework.TestSuite
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.Transaction
import org.jetbrains.exposed.sql.transactions.TransactionManager import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.junit.* import org.junit.*
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.Suite import org.junit.runners.Suite
import java.io.Closeable
import java.sql.Connection import java.sql.Connection
import java.util.* import java.util.*
@ -32,9 +30,8 @@ import java.util.*
JDBCHashMapTestSuite.SetConstrained::class) JDBCHashMapTestSuite.SetConstrained::class)
class JDBCHashMapTestSuite { class JDBCHashMapTestSuite {
companion object { companion object {
lateinit var dataSource: Closeable
lateinit var transaction: Transaction lateinit var transaction: Transaction
lateinit var database: Database lateinit var database: CordaPersistence
lateinit var loadOnInitFalseMap: JDBCHashMap<String, String> lateinit var loadOnInitFalseMap: JDBCHashMap<String, String>
lateinit var memoryConstrainedMap: JDBCHashMap<String, String> lateinit var memoryConstrainedMap: JDBCHashMap<String, String>
lateinit var loadOnInitTrueMap: JDBCHashMap<String, String> lateinit var loadOnInitTrueMap: JDBCHashMap<String, String>
@ -45,9 +42,7 @@ class JDBCHashMapTestSuite {
@JvmStatic @JvmStatic
@BeforeClass @BeforeClass
fun before() { fun before() {
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
setUpDatabaseTx() setUpDatabaseTx()
loadOnInitFalseMap = JDBCHashMap<String, String>("test_map_false", loadOnInit = false) loadOnInitFalseMap = JDBCHashMap<String, String>("test_map_false", loadOnInit = false)
memoryConstrainedMap = JDBCHashMap<String, String>("test_map_constrained", loadOnInit = false, maxBuckets = 1) memoryConstrainedMap = JDBCHashMap<String, String>("test_map_constrained", loadOnInit = false, maxBuckets = 1)
@ -61,7 +56,7 @@ class JDBCHashMapTestSuite {
@AfterClass @AfterClass
fun after() { fun after() {
closeDatabaseTx() closeDatabaseTx()
dataSource.close() database.close()
} }
@JvmStatic @JvmStatic
@ -228,19 +223,16 @@ class JDBCHashMapTestSuite {
private val transientMapForComparison = applyOpsToMap(LinkedHashMap()) private val transientMapForComparison = applyOpsToMap(LinkedHashMap())
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun before() { fun before() {
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
} }
@After @After
fun after() { fun after() {
dataSource.close() database.close()
} }

View File

@ -63,7 +63,6 @@ import net.corda.node.utilities.*
import net.corda.node.utilities.AddOrRemove.ADD import net.corda.node.utilities.AddOrRemove.ADD
import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.activemq.artemis.utils.ReusableLatch
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.slf4j.Logger import org.slf4j.Logger
import rx.Observable import rx.Observable
import java.io.IOException import java.io.IOException
@ -131,7 +130,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
var inNodeNetworkMapService: NetworkMapService? = null var inNodeNetworkMapService: NetworkMapService? = null
lateinit var network: MessagingService lateinit var network: MessagingService
protected val runOnStop = ArrayList<() -> Any?>() protected val runOnStop = ArrayList<() -> Any?>()
lateinit var database: Database lateinit var database: CordaPersistence
protected var dbCloser: (() -> Any?)? = null protected var dbCloser: (() -> Any?)? = null
var isPreviousCheckpointsPresent = false var isPreviousCheckpointsPresent = false
@ -547,11 +546,12 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
protected open fun initialiseDatabasePersistence(insideTransaction: () -> Unit) { protected open fun initialiseDatabasePersistence(insideTransaction: () -> Unit) {
val props = configuration.dataSourceProperties val props = configuration.dataSourceProperties
if (props.isNotEmpty()) { if (props.isNotEmpty()) {
val (toClose, database) = configureDatabase(props) this.database = configureDatabase(props)
this.database = database
// Now log the vendor string as this will also cause a connection to be tested eagerly. // Now log the vendor string as this will also cause a connection to be tested eagerly.
log.info("Connected to ${database.vendor} database.") database.transaction {
toClose::close.let { log.info("Connected to ${database.database.vendor} database.")
}
this.database::close.let {
dbCloser = it dbCloser = it
runOnStop += it runOnStop += it
} }
@ -811,7 +811,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
override val clock: Clock get() = platformClock override val clock: Clock get() = platformClock
override val myInfo: NodeInfo get() = info override val myInfo: NodeInfo get() = info
override val schemaService by lazy { NodeSchemaService(pluginRegistries.flatMap { it.requiredSchemas }.toSet()) } override val schemaService by lazy { NodeSchemaService(pluginRegistries.flatMap { it.requiredSchemas }.toSet()) }
override val database: Database get() = this@AbstractNode.database override val database: CordaPersistence get() = this@AbstractNode.database
override val configuration: NodeConfiguration get() = this@AbstractNode.configuration override val configuration: NodeConfiguration get() = this@AbstractNode.configuration
override fun <T : SerializeAsToken> cordaService(type: Class<T>): T { override fun <T : SerializeAsToken> cordaService(type: Class<T>): T {

View File

@ -24,9 +24,8 @@ import net.corda.node.services.messaging.requirePermission
import net.corda.node.services.startFlowPermission import net.corda.node.services.startFlowPermission
import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.utilities.transaction import net.corda.node.utilities.CordaPersistence
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import rx.Observable import rx.Observable
import java.io.InputStream import java.io.InputStream
import java.security.PublicKey import java.security.PublicKey
@ -40,7 +39,7 @@ import java.util.*
class CordaRPCOpsImpl( class CordaRPCOpsImpl(
private val services: ServiceHubInternal, private val services: ServiceHubInternal,
private val smm: StateMachineManager, private val smm: StateMachineManager,
private val database: Database private val database: CordaPersistence
) : CordaRPCOps { ) : CordaRPCOps {
override fun networkMapFeed(): DataFeed<List<NodeInfo>, NetworkMapCache.MapChange> { override fun networkMapFeed(): DataFeed<List<NodeInfo>, NetworkMapCache.MapChange> {
return database.transaction { return database.transaction {

View File

@ -23,7 +23,7 @@ import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.FlowStateMachineImpl
import org.jetbrains.exposed.sql.Database import net.corda.node.utilities.CordaPersistence
interface NetworkMapCacheInternal : NetworkMapCache { interface NetworkMapCacheInternal : NetworkMapCache {
/** /**
@ -81,7 +81,7 @@ interface ServiceHubInternal : PluginServiceHub {
val auditService: AuditService val auditService: AuditService
val rpcFlows: List<Class<out FlowLogic<*>>> val rpcFlows: List<Class<out FlowLogic<*>>>
val networkService: MessagingService val networkService: MessagingService
val database: Database val database: CordaPersistence
val configuration: NodeConfiguration val configuration: NodeConfiguration
@Suppress("DEPRECATION") @Suppress("DEPRECATION")

View File

@ -1,9 +1,9 @@
package net.corda.node.services.database package net.corda.node.services.database
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.services.api.SchemaService import net.corda.node.services.api.SchemaService
import net.corda.node.utilities.DatabaseTransactionManager
import org.hibernate.SessionFactory import org.hibernate.SessionFactory
import org.hibernate.boot.MetadataSources import org.hibernate.boot.MetadataSources
import org.hibernate.boot.model.naming.Identifier import org.hibernate.boot.model.naming.Identifier
@ -13,7 +13,6 @@ import org.hibernate.cfg.Configuration
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
import org.hibernate.service.UnknownUnwrapTypeException import org.hibernate.service.UnknownUnwrapTypeException
import org.jetbrains.exposed.sql.transactions.TransactionManager
import java.sql.Connection import java.sql.Connection
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -94,17 +93,15 @@ class HibernateConfiguration(val schemaService: SchemaService, val useDefaultLog
// during schema creation / update. // during schema creation / update.
class NodeDatabaseConnectionProvider : ConnectionProvider { class NodeDatabaseConnectionProvider : ConnectionProvider {
override fun closeConnection(conn: Connection) { override fun closeConnection(conn: Connection) {
val tx = TransactionManager.current() val tx = DatabaseTransactionManager.current()
tx.commit() tx.commit()
tx.close() tx.close()
} }
override fun supportsAggressiveRelease(): Boolean = true override fun supportsAggressiveRelease(): Boolean = true
override fun getConnection(): Connection { override fun getConnection(): Connection =
val tx = TransactionManager.manager.newTransaction(Connection.TRANSACTION_REPEATABLE_READ) DatabaseTransactionManager.newTransaction(Connection.TRANSACTION_REPEATABLE_READ).connection
return tx.connection
}
override fun <T : Any?> unwrap(unwrapType: Class<T>): T { override fun <T : Any?> unwrap(unwrapType: Class<T>): T {
try { try {

View File

@ -13,7 +13,7 @@ import net.corda.core.schemas.requery.converters.InstantConverter
import net.corda.core.schemas.requery.converters.SecureHashConverter import net.corda.core.schemas.requery.converters.SecureHashConverter
import net.corda.core.schemas.requery.converters.StateRefConverter import net.corda.core.schemas.requery.converters.StateRefConverter
import net.corda.core.schemas.requery.converters.VaultStateStatusConverter import net.corda.core.schemas.requery.converters.VaultStateStatusConverter
import org.jetbrains.exposed.sql.transactions.TransactionManager import net.corda.node.utilities.DatabaseTransactionManager
import java.sql.Connection import java.sql.Connection
import java.util.* import java.util.*
import java.util.concurrent.Executor import java.util.concurrent.Executor
@ -128,12 +128,7 @@ class KotlinConfigurationTransactionWrapper(private val model: EntityModel,
} }
class CordaDataSourceConnectionProvider(val dataSource: DataSource) : ConnectionProvider { class CordaDataSourceConnectionProvider(val dataSource: DataSource) : ConnectionProvider {
override fun getConnection(): Connection { override fun getConnection(): Connection = CordaConnection(DatabaseTransactionManager.current().connection)
val tx = TransactionManager.manager.currentOrNull()
return CordaConnection(
tx?.connection ?: throw IllegalStateException("Was expecting to find database transaction: must wrap calling code within a transaction.")
)
}
} }
class CordaConnection(val connection: Connection) : Connection by connection { class CordaConnection(val connection: Connection) : Connection by connection {

View File

@ -8,7 +8,7 @@ import io.requery.sql.KotlinEntityDataStore
import io.requery.sql.SchemaModifier import io.requery.sql.SchemaModifier
import io.requery.sql.TableCreationMode import io.requery.sql.TableCreationMode
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import org.jetbrains.exposed.sql.transactions.TransactionManager import net.corda.node.utilities.DatabaseTransactionManager
import java.sql.Connection import java.sql.Connection
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@ -46,9 +46,5 @@ class RequeryConfiguration(val properties: Properties, val useDefaultLogging: Bo
} }
// TODO: remove once Requery supports QUERY WITH COMPOSITE_KEY IN // TODO: remove once Requery supports QUERY WITH COMPOSITE_KEY IN
fun jdbcSession(): Connection { fun jdbcSession(): Connection = DatabaseTransactionManager.current().connection
val ctx = TransactionManager.manager.currentOrNull()
return ctx?.connection ?: throw IllegalStateException("Was expecting to find database transaction: must wrap calling code within a transaction.")
}
} }

View File

@ -37,7 +37,6 @@ import org.apache.activemq.artemis.api.core.client.*
import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE import org.apache.activemq.artemis.api.core.client.ActiveMQClient.DEFAULT_ACK_BATCH_SIZE
import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.statements.InsertStatement import org.jetbrains.exposed.sql.statements.InsertStatement
import java.security.PublicKey import java.security.PublicKey
@ -74,7 +73,7 @@ class NodeMessagingClient(override val config: NodeConfiguration,
val serverAddress: NetworkHostAndPort, val serverAddress: NetworkHostAndPort,
val myIdentity: PublicKey?, val myIdentity: PublicKey?,
val nodeExecutor: AffinityExecutor.ServiceAffinityExecutor, val nodeExecutor: AffinityExecutor.ServiceAffinityExecutor,
val database: Database, val database: CordaPersistence,
val networkMapRegistrationFuture: ListenableFuture<Unit>, val networkMapRegistrationFuture: ListenableFuture<Unit>,
val monitoringService: MonitoringService, val monitoringService: MonitoringService,
advertisedAddress: NetworkHostAndPort = serverAddress advertisedAddress: NetworkHostAndPort = serverAddress

View File

@ -18,11 +18,7 @@ import net.corda.core.utilities.*
import net.corda.node.services.api.FlowAppAuditEvent import net.corda.node.services.api.FlowAppAuditEvent
import net.corda.node.services.api.FlowPermissionAuditEvent import net.corda.node.services.api.FlowPermissionAuditEvent
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.StrandLocalTransactionManager import net.corda.node.utilities.*
import net.corda.node.utilities.createTransaction
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Transaction
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.sql.Connection import java.sql.Connection
@ -53,23 +49,23 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
@Suspendable @Suspendable
inline fun sleep(millis: Long) { inline fun sleep(millis: Long) {
if (currentStateMachine() != null) { if (currentStateMachine() != null) {
val db = StrandLocalTransactionManager.database val db = DatabaseTransactionManager.dataSource
TransactionManager.current().commit() DatabaseTransactionManager.current().commit()
TransactionManager.current().close() DatabaseTransactionManager.current().close()
Strand.sleep(millis) Strand.sleep(millis)
StrandLocalTransactionManager.database = db DatabaseTransactionManager.dataSource = db
TransactionManager.manager.newTransaction(Connection.TRANSACTION_REPEATABLE_READ) DatabaseTransactionManager.newTransaction(Connection.TRANSACTION_REPEATABLE_READ)
} else Strand.sleep(millis) } else Strand.sleep(millis)
} }
} }
// These fields shouldn't be serialised, so they are marked @Transient. // These fields shouldn't be serialised, so they are marked @Transient.
@Transient override lateinit var serviceHub: ServiceHubInternal @Transient override lateinit var serviceHub: ServiceHubInternal
@Transient internal lateinit var database: Database @Transient internal lateinit var database: CordaPersistence
@Transient internal lateinit var actionOnSuspend: (FlowIORequest) -> Unit @Transient internal lateinit var actionOnSuspend: (FlowIORequest) -> Unit
@Transient internal lateinit var actionOnEnd: (Try<R>, Boolean) -> Unit @Transient internal lateinit var actionOnEnd: (Try<R>, Boolean) -> Unit
@Transient internal var fromCheckpoint: Boolean = false @Transient internal var fromCheckpoint: Boolean = false
@Transient private var txTrampoline: Transaction? = null @Transient private var txTrampoline: DatabaseTransaction? = null
/** /**
* Return the logger for this state machine. The logger name incorporates [id] and so including it in the log message * Return the logger for this state machine. The logger name incorporates [id] and so including it in the log message
@ -130,7 +126,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
private fun createTransaction() { private fun createTransaction() {
// Make sure we have a database transaction // Make sure we have a database transaction
database.createTransaction() database.createTransaction()
logger.trace { "Starting database transaction ${TransactionManager.currentOrNull()} on ${Strand.currentStrand()}" } logger.trace { "Starting database transaction ${DatabaseTransactionManager.currentOrNull()} on ${Strand.currentStrand()}" }
} }
private fun processException(exception: Throwable, propagated: Boolean) { private fun processException(exception: Throwable, propagated: Boolean) {
@ -140,7 +136,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
} }
internal fun commitTransaction() { internal fun commitTransaction() {
val transaction = TransactionManager.current() val transaction = DatabaseTransactionManager.current()
try { try {
logger.trace { "Committing database transaction $transaction on ${Strand.currentStrand()}." } logger.trace { "Committing database transaction $transaction on ${Strand.currentStrand()}." }
transaction.commit() transaction.commit()
@ -383,8 +379,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
private fun suspend(ioRequest: FlowIORequest) { private fun suspend(ioRequest: FlowIORequest) {
// We have to pass the thread local database transaction across via a transient field as the fiber park // We have to pass the thread local database transaction across via a transient field as the fiber park
// swaps them out. // swaps them out.
txTrampoline = TransactionManager.currentOrNull() txTrampoline = DatabaseTransactionManager.setThreadLocalTx(null)
StrandLocalTransactionManager.setThreadLocalTx(null)
if (ioRequest is WaitingRequest) if (ioRequest is WaitingRequest)
waitingForResponse = ioRequest waitingForResponse = ioRequest
@ -393,7 +388,7 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
logger.trace { "Suspended on $ioRequest" } logger.trace { "Suspended on $ioRequest" }
// restore the Tx onto the ThreadLocal so that we can commit the ensuing checkpoint to the DB // restore the Tx onto the ThreadLocal so that we can commit the ensuing checkpoint to the DB
try { try {
StrandLocalTransactionManager.setThreadLocalTx(txTrampoline) DatabaseTransactionManager.setThreadLocalTx(txTrampoline)
txTrampoline = null txTrampoline = null
actionOnSuspend(ioRequest) actionOnSuspend(ioRequest)
} catch (t: Throwable) { } catch (t: Throwable) {

View File

@ -39,7 +39,6 @@ import net.corda.node.services.messaging.ReceivedMessage
import net.corda.node.services.messaging.TopicSession import net.corda.node.services.messaging.TopicSession
import net.corda.node.utilities.* import net.corda.node.utilities.*
import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.activemq.artemis.utils.ReusableLatch
import org.jetbrains.exposed.sql.Database
import org.slf4j.Logger import org.slf4j.Logger
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
@ -76,7 +75,7 @@ import kotlin.collections.ArrayList
class StateMachineManager(val serviceHub: ServiceHubInternal, class StateMachineManager(val serviceHub: ServiceHubInternal,
val checkpointStorage: CheckpointStorage, val checkpointStorage: CheckpointStorage,
val executor: AffinityExecutor, val executor: AffinityExecutor,
val database: Database, val database: CordaPersistence,
private val unfinishedFibers: ReusableLatch = ReusableLatch()) { private val unfinishedFibers: ReusableLatch = ReusableLatch()) {
inner class FiberScheduler : FiberExecutorScheduler("Same thread scheduler", executor) inner class FiberScheduler : FiberExecutorScheduler("Same thread scheduler", executor)

View File

@ -36,7 +36,6 @@ import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.transactions.BFTSMaRt.Client import net.corda.node.services.transactions.BFTSMaRt.Client
import net.corda.node.services.transactions.BFTSMaRt.Replica import net.corda.node.services.transactions.BFTSMaRt.Replica
import net.corda.node.utilities.JDBCHashMap import net.corda.node.utilities.JDBCHashMap
import net.corda.node.utilities.transaction
import java.nio.file.Path import java.nio.file.Path
import java.util.* import java.util.*

View File

@ -8,9 +8,8 @@ import io.atomix.copycat.server.StateMachine
import io.atomix.copycat.server.storage.snapshot.SnapshotReader import io.atomix.copycat.server.storage.snapshot.SnapshotReader
import io.atomix.copycat.server.storage.snapshot.SnapshotWriter import io.atomix.copycat.server.storage.snapshot.SnapshotWriter
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.JDBCHashMap import net.corda.node.utilities.JDBCHashMap
import net.corda.node.utilities.transaction
import org.jetbrains.exposed.sql.Database
import java.util.* import java.util.*
/** /**
@ -21,7 +20,7 @@ import java.util.*
* to disk, and sharing them across the cluster. A new node joining the cluster will have to obtain and install a snapshot * to disk, and sharing them across the cluster. A new node joining the cluster will have to obtain and install a snapshot
* containing the entire JDBC table contents. * containing the entire JDBC table contents.
*/ */
class DistributedImmutableMap<K : Any, V : Any>(val db: Database, tableName: String) : StateMachine(), Snapshottable { class DistributedImmutableMap<K : Any, V : Any>(val db: CordaPersistence, tableName: String) : StateMachine(), Snapshottable {
companion object { companion object {
private val log = loggerFor<DistributedImmutableMap<*, *>>() private val log = loggerFor<DistributedImmutableMap<*, *>>()
} }

View File

@ -23,8 +23,8 @@ import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.CordaPersistence
import net.corda.nodeapi.config.SSLConfiguration import net.corda.nodeapi.config.SSLConfiguration
import org.jetbrains.exposed.sql.Database
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import javax.annotation.concurrent.ThreadSafe import javax.annotation.concurrent.ThreadSafe
@ -55,7 +55,7 @@ class RaftUniquenessProvider(services: ServiceHubInternal) : UniquenessProvider,
*/ */
private val clusterAddresses = services.configuration.notaryClusterAddresses private val clusterAddresses = services.configuration.notaryClusterAddresses
/** The database to store the state machine state in */ /** The database to store the state machine state in */
private val db: Database = services.database private val db: CordaPersistence = services.database
/** SSL configuration */ /** SSL configuration */
private val transportConfiguration: SSLConfiguration = services.configuration private val transportConfiguration: SSLConfiguration = services.configuration

View File

@ -3,14 +3,13 @@ package net.corda.node.services.vault
import com.codahale.metrics.Gauge import com.codahale.metrics.Gauge
import net.corda.core.node.services.VaultService import net.corda.core.node.services.VaultService
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.utilities.transaction import net.corda.node.utilities.CordaPersistence
import org.jetbrains.exposed.sql.Database
import java.util.* import java.util.*
/** /**
* This class observes the vault and reflect current cash balances as exposed metrics in the monitoring service. * This class observes the vault and reflect current cash balances as exposed metrics in the monitoring service.
*/ */
class CashBalanceAsMetricsObserver(val serviceHubInternal: ServiceHubInternal, val database: Database) { class CashBalanceAsMetricsObserver(val serviceHubInternal: ServiceHubInternal, val database: CordaPersistence) {
init { init {
// TODO: Need to consider failure scenarios. This needs to run if the TX is successfully recorded // TODO: Need to consider failure scenarios. This needs to run if the TX is successfully recorded
serviceHubInternal.vaultService.updates.subscribe { _ -> serviceHubInternal.vaultService.updates.subscribe { _ ->

View File

@ -0,0 +1,193 @@
package net.corda.node.utilities
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.jetbrains.exposed.sql.Database
import rx.Observable
import rx.Subscriber
import rx.subjects.UnicastSubject
import java.io.Closeable
import java.sql.Connection
import java.sql.SQLException
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
//HikariDataSource implements also Closeable which allows CordaPersistence to be Closeable
class CordaPersistence(var dataSource: HikariDataSource): Closeable {
/** Holds Exposed database, the field will be removed once Exposed library is removed */
lateinit var database: Database
companion object {
fun connect(dataSource: HikariDataSource): CordaPersistence {
return CordaPersistence(dataSource).apply {
DatabaseTransactionManager(this)
}
}
}
fun createTransaction(): DatabaseTransaction {
// We need to set the database for the current [Thread] or [Fiber] here as some tests share threads across databases.
DatabaseTransactionManager.dataSource = this
return DatabaseTransactionManager.currentOrNew(Connection.TRANSACTION_REPEATABLE_READ)
}
fun <T> isolatedTransaction(block: DatabaseTransaction.() -> T): T {
val context = DatabaseTransactionManager.setThreadLocalTx(null)
return try {
transaction(block)
} finally {
DatabaseTransactionManager.restoreThreadLocalTx(context)
}
}
fun <T> transaction(statement: DatabaseTransaction.() -> T): T {
DatabaseTransactionManager.dataSource = this
return transaction(Connection.TRANSACTION_REPEATABLE_READ, 3, statement)
}
private fun <T> transaction(transactionIsolation: Int, repetitionAttempts: Int, statement: DatabaseTransaction.() -> T): T {
val outer = DatabaseTransactionManager.currentOrNull()
return if (outer != null) {
outer.statement()
}
else {
inTopLevelTransaction(transactionIsolation, repetitionAttempts, statement)
}
}
private fun <T> inTopLevelTransaction(transactionIsolation: Int, repetitionAttempts: Int, statement: DatabaseTransaction.() -> T): T {
var repetitions = 0
while (true) {
val transaction = DatabaseTransactionManager.currentOrNew(transactionIsolation)
try {
val answer = transaction.statement()
transaction.commit()
return answer
}
catch (e: SQLException) {
transaction.rollback()
repetitions++
if (repetitions >= repetitionAttempts) {
throw e
}
}
catch (e: Throwable) {
transaction.rollback()
throw e
}
finally {
transaction.close()
}
}
}
override fun close() {
dataSource.close()
}
}
fun configureDatabase(props: Properties): CordaPersistence {
val config = HikariConfig(props)
val dataSource = HikariDataSource(config)
val persistence = CordaPersistence.connect(dataSource)
//org.jetbrains.exposed.sql.Database will be removed once Exposed library is removed
val database = Database.connect(dataSource) { _ -> ExposedTransactionManager() }
persistence.database = database
// Check not in read-only mode.
persistence.transaction {
persistence.dataSource.connection.use {
check(!it.metaData.isReadOnly) { "Database should not be readonly." }
}
}
return persistence
}
/**
* Buffer observations until after the current database transaction has been closed. Observations are never
* dropped, simply delayed.
*
* Primarily for use by component authors to publish observations during database transactions without racing against
* closing the database transaction.
*
* For examples, see the call hierarchy of this function.
*/
fun <T : Any> rx.Observer<T>.bufferUntilDatabaseCommit(): rx.Observer<T> {
val currentTxId = DatabaseTransactionManager.transactionId
val databaseTxBoundary: Observable<DatabaseTransactionManager.Boundary> = DatabaseTransactionManager.transactionBoundaries.filter { it.txId == currentTxId }.first()
val subject = UnicastSubject.create<T>()
subject.delaySubscription(databaseTxBoundary).subscribe(this)
databaseTxBoundary.doOnCompleted { subject.onCompleted() }
return subject
}
// A subscriber that delegates to multiple others, wrapping a database transaction around the combination.
private class DatabaseTransactionWrappingSubscriber<U>(val db: CordaPersistence?) : Subscriber<U>() {
// Some unsubscribes happen inside onNext() so need something that supports concurrent modification.
val delegates = CopyOnWriteArrayList<Subscriber<in U>>()
fun forEachSubscriberWithDbTx(block: Subscriber<in U>.() -> Unit) {
(db ?: DatabaseTransactionManager.dataSource).transaction {
delegates.filter { !it.isUnsubscribed }.forEach {
it.block()
}
}
}
override fun onCompleted() = forEachSubscriberWithDbTx { onCompleted() }
override fun onError(e: Throwable?) = forEachSubscriberWithDbTx { onError(e) }
override fun onNext(s: U) = forEachSubscriberWithDbTx { onNext(s) }
override fun onStart() = forEachSubscriberWithDbTx { onStart() }
fun cleanUp() {
if (delegates.removeIf { it.isUnsubscribed }) {
if (delegates.isEmpty()) {
unsubscribe()
}
}
}
}
// A subscriber that wraps another but does not pass on observations to it.
private class NoOpSubscriber<U>(t: Subscriber<in U>) : Subscriber<U>(t) {
override fun onCompleted() {
}
override fun onError(e: Throwable?) {
}
override fun onNext(s: U) {
}
}
/**
* Wrap delivery of observations in a database transaction. Multiple subscribers will receive the observations inside
* the same database transaction. This also lazily subscribes to the source [rx.Observable] to preserve any buffering
* that might be in place.
*/
fun <T : Any> rx.Observable<T>.wrapWithDatabaseTransaction(db: CordaPersistence? = null): rx.Observable<T> {
var wrappingSubscriber = DatabaseTransactionWrappingSubscriber<T>(db)
// Use lift to add subscribers to a special subscriber that wraps a database transaction around observations.
// Each subscriber will be passed to this lambda when they subscribe, at which point we add them to wrapping subscriber.
return this.lift { toBeWrappedInDbTx: Subscriber<in T> ->
// Add the subscriber to the wrapping subscriber, which will invoke the original subscribers together inside a database transaction.
wrappingSubscriber.delegates.add(toBeWrappedInDbTx)
// If we are the first subscriber, return the shared subscriber, otherwise return a subscriber that does nothing.
if (wrappingSubscriber.delegates.size == 1) wrappingSubscriber else NoOpSubscriber(toBeWrappedInDbTx)
// Clean up the shared list of subscribers when they unsubscribe.
}.doOnUnsubscribe {
wrappingSubscriber.cleanUp()
// If cleanup removed the last subscriber reset the system, as future subscribers might need the stream again
if (wrappingSubscriber.delegates.isEmpty()) {
wrappingSubscriber = DatabaseTransactionWrappingSubscriber<T>(db)
}
}
}

View File

@ -1,277 +1,26 @@
package net.corda.node.utilities package net.corda.node.utilities
import co.paralleluniverse.strands.Strand
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.crypto.parsePublicKeyBase58
import net.corda.core.crypto.toBase58String import net.corda.core.crypto.toBase58String
import net.corda.node.utilities.StrandLocalTransactionManager.Boundary
import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509CertificateHolder
import org.h2.jdbc.JdbcBlob import org.h2.jdbc.JdbcBlob
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.TransactionInterface
import org.jetbrains.exposed.sql.transactions.TransactionManager
import rx.Observable
import rx.Subscriber
import rx.subjects.PublishSubject
import rx.subjects.Subject
import rx.subjects.UnicastSubject
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.Closeable
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath import java.security.cert.CertPath
import java.security.cert.CertificateFactory import java.security.cert.CertificateFactory
import java.sql.Connection
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneOffset import java.time.ZoneOffset
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
/** /**
* Table prefix for all tables owned by the node module. * Table prefix for all tables owned by the node module.
*/ */
const val NODE_DATABASE_PREFIX = "node_" const val NODE_DATABASE_PREFIX = "node_"
@Deprecated("Use Database.transaction instead.")
fun <T> databaseTransaction(db: Database, statement: Transaction.() -> T) = db.transaction(statement)
// TODO: Handle commit failure due to database unavailable. Better to shutdown and await database reconnect/recovery.
fun <T> Database.transaction(statement: Transaction.() -> T): T {
// We need to set the database for the current [Thread] or [Fiber] here as some tests share threads across databases.
StrandLocalTransactionManager.database = this
return org.jetbrains.exposed.sql.transactions.transaction(Connection.TRANSACTION_REPEATABLE_READ, 1, statement)
}
fun Database.createTransaction(): Transaction {
// We need to set the database for the current [Thread] or [Fiber] here as some tests share threads across databases.
StrandLocalTransactionManager.database = this
return TransactionManager.currentOrNew(Connection.TRANSACTION_REPEATABLE_READ)
}
fun configureDatabase(props: Properties): Pair<Closeable, Database> {
val config = HikariConfig(props)
val dataSource = HikariDataSource(config)
val database = Database.connect(dataSource) { db -> StrandLocalTransactionManager(db) }
// Check not in read-only mode.
database.transaction {
check(!database.metadata.isReadOnly) { "Database should not be readonly." }
}
return Pair(dataSource, database)
}
fun <T> Database.isolatedTransaction(block: Transaction.() -> T): T {
val oldContext = StrandLocalTransactionManager.setThreadLocalTx(null)
return try {
transaction(block)
} finally {
StrandLocalTransactionManager.restoreThreadLocalTx(oldContext)
}
}
/**
* A relatively close copy of the [org.jetbrains.exposed.sql.transactions.ThreadLocalTransactionManager]
* in Exposed but with the following adjustments to suit our environment:
*
* Because the construction of a [Database] instance results in replacing the singleton [TransactionManager] instance,
* our tests involving two [MockNode]s effectively replace the database instances of each other and continue to trample
* over each other. So here we use a companion object to hold them as [ThreadLocal] and [StrandLocalTransactionManager]
* is otherwise effectively stateless so it's replacement does not matter. The [ThreadLocal] is then set correctly and
* explicitly just prior to initiating a transaction in [transaction] and [createTransaction] above.
*
* The [StrandLocalTransactionManager] instances have an [Observable] of the transaction close [Boundary]s which
* facilitates the use of [Observable.afterDatabaseCommit] to create event streams that only emit once the database
* transaction is closed and the data has been persisted and becomes visible to other observers.
*/
class StrandLocalTransactionManager(initWithDatabase: Database) : TransactionManager {
companion object {
private val TX_ID = Key<UUID>()
private val threadLocalDb = ThreadLocal<Database>()
private val threadLocalTx = ThreadLocal<Transaction>()
private val databaseToInstance = ConcurrentHashMap<Database, StrandLocalTransactionManager>()
fun setThreadLocalTx(tx: Transaction?): Pair<Database?, Transaction?> {
val oldTx = threadLocalTx.get()
threadLocalTx.set(tx)
return Pair(threadLocalDb.get(), oldTx)
}
fun restoreThreadLocalTx(context: Pair<Database?, Transaction?>) {
threadLocalDb.set(context.first)
threadLocalTx.set(context.second)
}
var database: Database
get() = threadLocalDb.get() ?: throw IllegalStateException("Was expecting to find database set on current strand: ${Strand.currentStrand()}")
set(value) {
threadLocalDb.set(value)
}
val transactionId: UUID
get() = threadLocalTx.get()?.getUserData(TX_ID) ?: throw IllegalStateException("Was expecting to find transaction set on current strand: ${Strand.currentStrand()}")
val manager: StrandLocalTransactionManager get() = databaseToInstance[database]!!
val transactionBoundaries: Subject<Boundary, Boundary> get() = manager._transactionBoundaries
}
data class Boundary(val txId: UUID)
private val _transactionBoundaries = PublishSubject.create<Boundary>().toSerialized()
init {
// Found a unit test that was forgetting to close the database transactions. When you close() on the top level
// database transaction it will reset the threadLocalTx back to null, so if it isn't then there is still a
// databae transaction open. The [transaction] helper above handles this in a finally clause for you
// but any manual database transaction management is liable to have this problem.
if (threadLocalTx.get() != null) {
throw IllegalStateException("Was not expecting to find existing database transaction on current strand when setting database: ${Strand.currentStrand()}, ${threadLocalTx.get()}")
}
database = initWithDatabase
databaseToInstance[database] = this
}
override fun newTransaction(isolation: Int): Transaction {
val impl = StrandLocalTransaction(database, isolation, threadLocalTx, transactionBoundaries)
return Transaction(impl).apply {
threadLocalTx.set(this)
putUserData(TX_ID, impl.id)
}
}
override fun currentOrNull(): Transaction? = threadLocalTx.get()
// Direct copy of [ThreadLocalTransaction].
private class StrandLocalTransaction(override val db: Database, isolation: Int, val threadLocal: ThreadLocal<Transaction>, val transactionBoundaries: Subject<Boundary, Boundary>) : TransactionInterface {
val id = UUID.randomUUID()
override val connection: Connection by lazy(LazyThreadSafetyMode.NONE) {
db.connector().apply {
autoCommit = false
transactionIsolation = isolation
}
}
override val outerTransaction = threadLocal.get()
override fun commit() {
connection.commit()
}
override fun rollback() {
if (!connection.isClosed) {
connection.rollback()
}
}
override fun close() {
connection.close()
threadLocal.set(outerTransaction)
if (outerTransaction == null) {
transactionBoundaries.onNext(Boundary(id))
}
}
}
}
/**
* Buffer observations until after the current database transaction has been closed. Observations are never
* dropped, simply delayed.
*
* Primarily for use by component authors to publish observations during database transactions without racing against
* closing the database transaction.
*
* For examples, see the call hierarchy of this function.
*/
fun <T : Any> rx.Observer<T>.bufferUntilDatabaseCommit(): rx.Observer<T> {
val currentTxId = StrandLocalTransactionManager.transactionId
val databaseTxBoundary: Observable<StrandLocalTransactionManager.Boundary> = StrandLocalTransactionManager.transactionBoundaries.filter { it.txId == currentTxId }.first()
val subject = UnicastSubject.create<T>()
subject.delaySubscription(databaseTxBoundary).subscribe(this)
databaseTxBoundary.doOnCompleted { subject.onCompleted() }
return subject
}
// A subscriber that delegates to multiple others, wrapping a database transaction around the combination.
private class DatabaseTransactionWrappingSubscriber<U>(val db: Database?) : Subscriber<U>() {
// Some unsubscribes happen inside onNext() so need something that supports concurrent modification.
val delegates = CopyOnWriteArrayList<Subscriber<in U>>()
fun forEachSubscriberWithDbTx(block: Subscriber<in U>.() -> Unit) {
(db ?: StrandLocalTransactionManager.database).transaction {
delegates.filter { !it.isUnsubscribed }.forEach {
it.block()
}
}
}
override fun onCompleted() {
forEachSubscriberWithDbTx { onCompleted() }
}
override fun onError(e: Throwable?) {
forEachSubscriberWithDbTx { onError(e) }
}
override fun onNext(s: U) {
forEachSubscriberWithDbTx { onNext(s) }
}
override fun onStart() {
forEachSubscriberWithDbTx { onStart() }
}
fun cleanUp() {
if (delegates.removeIf { it.isUnsubscribed }) {
if (delegates.isEmpty()) {
unsubscribe()
}
}
}
}
// A subscriber that wraps another but does not pass on observations to it.
private class NoOpSubscriber<U>(t: Subscriber<in U>) : Subscriber<U>(t) {
override fun onCompleted() {
}
override fun onError(e: Throwable?) {
}
override fun onNext(s: U) {
}
}
/**
* Wrap delivery of observations in a database transaction. Multiple subscribers will receive the observations inside
* the same database transaction. This also lazily subscribes to the source [rx.Observable] to preserve any buffering
* that might be in place.
*/
fun <T : Any> rx.Observable<T>.wrapWithDatabaseTransaction(db: Database? = null): rx.Observable<T> {
var wrappingSubscriber = DatabaseTransactionWrappingSubscriber<T>(db)
// Use lift to add subscribers to a special subscriber that wraps a database transaction around observations.
// Each subscriber will be passed to this lambda when they subscribe, at which point we add them to wrapping subscriber.
return this.lift { toBeWrappedInDbTx: Subscriber<in T> ->
// Add the subscriber to the wrapping subscriber, which will invoke the original subscribers together inside a database transaction.
wrappingSubscriber.delegates.add(toBeWrappedInDbTx)
// If we are the first subscriber, return the shared subscriber, otherwise return a subscriber that does nothing.
if (wrappingSubscriber.delegates.size == 1) wrappingSubscriber else NoOpSubscriber(toBeWrappedInDbTx)
// Clean up the shared list of subscribers when they unsubscribe.
}.doOnUnsubscribe {
wrappingSubscriber.cleanUp()
// If cleanup removed the last subscriber reset the system, as future subscribers might need the stream again
if (wrappingSubscriber.delegates.isEmpty()) {
wrappingSubscriber = DatabaseTransactionWrappingSubscriber<T>(db)
}
}
}
// Composite columns for use with below Exposed helpers. // Composite columns for use with below Exposed helpers.
data class PartyColumns(val name: Column<String>, val owningKey: Column<PublicKey>) data class PartyColumns(val name: Column<String>, val owningKey: Column<PublicKey>)
data class PartyAndCertificateColumns(val name: Column<String>, val owningKey: Column<PublicKey>, data class PartyAndCertificateColumns(val name: Column<String>, val owningKey: Column<PublicKey>,

View File

@ -0,0 +1,106 @@
package net.corda.node.utilities
import co.paralleluniverse.strands.Strand
import rx.subjects.PublishSubject
import rx.subjects.Subject
import java.sql.Connection
import java.util.*
import java.util.concurrent.ConcurrentHashMap
class DatabaseTransaction(isolation: Int, val threadLocal: ThreadLocal<DatabaseTransaction>,
val transactionBoundaries: Subject<DatabaseTransactionManager.Boundary, DatabaseTransactionManager.Boundary>,
val cordaPersistence: CordaPersistence) {
val id: UUID = UUID.randomUUID()
val connection: Connection by lazy(LazyThreadSafetyMode.NONE) {
cordaPersistence.dataSource.connection
.apply {
autoCommit = false
transactionIsolation = isolation
}
}
val outerTransaction: DatabaseTransaction? = threadLocal.get()
fun commit() {
connection.commit()
}
fun rollback() {
if (!connection.isClosed) {
connection.rollback()
}
}
fun close() {
connection.close()
threadLocal.set(outerTransaction)
if (outerTransaction == null) {
transactionBoundaries.onNext(DatabaseTransactionManager.Boundary(id))
}
}
}
class DatabaseTransactionManager(initDataSource: CordaPersistence) {
companion object {
private val threadLocalDb = ThreadLocal<CordaPersistence>()
private val threadLocalTx = ThreadLocal<DatabaseTransaction>()
private val databaseToInstance = ConcurrentHashMap<CordaPersistence, DatabaseTransactionManager>()
fun setThreadLocalTx(tx: DatabaseTransaction?): DatabaseTransaction? {
val oldTx = threadLocalTx.get()
threadLocalTx.set(tx)
return oldTx
}
fun restoreThreadLocalTx(context: DatabaseTransaction?) {
if (context != null) {
threadLocalDb.set(context.cordaPersistence)
}
threadLocalTx.set(context)
}
var dataSource: CordaPersistence
get() = threadLocalDb.get() ?: throw IllegalStateException("Was expecting to find CordaPersistence set on current thread: ${Strand.currentStrand()}")
set(value) = threadLocalDb.set(value)
val transactionId: UUID
get() = threadLocalTx.get()?.id ?: throw IllegalStateException("Was expecting to find transaction set on current strand: ${Strand.currentStrand()}")
val manager: DatabaseTransactionManager get() = databaseToInstance[dataSource]!!
val transactionBoundaries: Subject<Boundary, Boundary> get() = manager._transactionBoundaries
fun currentOrNull(): DatabaseTransaction? = manager.currentOrNull()
fun currentOrNew(isolation: Int) = currentOrNull() ?: manager.newTransaction(isolation)
fun current(): DatabaseTransaction = currentOrNull() ?: error("No transaction in context.")
fun newTransaction(isolation: Int) = manager.newTransaction(isolation)
}
data class Boundary(val txId: UUID)
private val _transactionBoundaries = PublishSubject.create<Boundary>().toSerialized()
init {
// Found a unit test that was forgetting to close the database transactions. When you close() on the top level
// database transaction it will reset the threadLocalTx back to null, so if it isn't then there is still a
// database transaction open. The [transaction] helper above handles this in a finally clause for you
// but any manual database transaction management is liable to have this problem.
if (threadLocalTx.get() != null) {
throw IllegalStateException("Was not expecting to find existing database transaction on current strand when setting database: ${Strand.currentStrand()}, ${threadLocalTx.get()}")
}
dataSource = initDataSource
databaseToInstance[dataSource] = this
}
private fun newTransaction(isolation: Int) =
DatabaseTransaction(isolation, threadLocalTx, transactionBoundaries, dataSource).apply {
threadLocalTx.set(this)
}
private fun currentOrNull(): DatabaseTransaction? = threadLocalTx.get()
}

View File

@ -0,0 +1,54 @@
package net.corda.node.utilities
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Transaction
import org.jetbrains.exposed.sql.transactions.TransactionInterface
import org.jetbrains.exposed.sql.transactions.TransactionManager
import java.sql.Connection
/**
* Wrapper of [DatabaseTransaction], because the class is effectively used for [ExposedTransaction.connection] method only not all methods are implemented.
* The class will obsolete when Exposed library is phased out.
*/
class ExposedTransaction(override val db: Database, val databaseTransaction: DatabaseTransaction): TransactionInterface {
override val outerTransaction: Transaction?
get() = throw UnsupportedOperationException()
override val connection: Connection by lazy(LazyThreadSafetyMode.NONE) {
databaseTransaction.connection
}
override fun commit() {
databaseTransaction.commit()
}
override fun rollback() {
databaseTransaction.rollback()
}
override fun close() {
databaseTransaction.close()
}
}
/**
* Delegates methods to [DatabaseTransactionManager].
* The class will obsolete when Exposed library is phased out.
*/
class ExposedTransactionManager: TransactionManager {
companion object {
val database: Database
get() = DatabaseTransactionManager.dataSource.database
}
override fun newTransaction(isolation: Int): Transaction {
var databaseTransaction = DatabaseTransactionManager.newTransaction(isolation)
return Transaction(ExposedTransaction(database, databaseTransaction))
}
override fun currentOrNull(): Transaction? {
val databaseTransaction = DatabaseTransactionManager.currentOrNull()
return if (databaseTransaction != null) Transaction(ExposedTransaction(database, databaseTransaction)) else null
}
}

View File

@ -8,7 +8,6 @@ import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.trace import net.corda.core.utilities.trace
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.InsertStatement import org.jetbrains.exposed.sql.statements.InsertStatement
import org.jetbrains.exposed.sql.transactions.TransactionManager
import java.sql.Blob import java.sql.Blob
import java.util.* import java.util.*
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@ -60,7 +59,7 @@ class JDBCHashMap<K : Any, V : Any>(tableName: String,
} }
fun bytesToBlob(value: SerializedBytes<*>, finalizables: MutableList<() -> Unit>): Blob { fun bytesToBlob(value: SerializedBytes<*>, finalizables: MutableList<() -> Unit>): Blob {
val blob = TransactionManager.current().connection.createBlob() val blob = DatabaseTransactionManager.current().connection.createBlob()
finalizables += { blob.free() } finalizables += { blob.free() }
blob.setBytes(1, value.bytes) blob.setBytes(1, value.bytes)
return blob return blob

View File

@ -11,9 +11,11 @@ import net.corda.core.messaging.*;
import net.corda.core.node.services.*; import net.corda.core.node.services.*;
import net.corda.core.node.services.vault.*; import net.corda.core.node.services.vault.*;
import net.corda.core.node.services.vault.QueryCriteria.*; import net.corda.core.node.services.vault.QueryCriteria.*;
import net.corda.testing.contracts.DummyLinearContract;
import net.corda.core.schemas.*; import net.corda.core.schemas.*;
import net.corda.core.transactions.*; import net.corda.core.transactions.*;
import net.corda.core.utilities.*; import net.corda.core.utilities.*;
import net.corda.node.utilities.CordaPersistence;
import net.corda.node.services.database.*; import net.corda.node.services.database.*;
import net.corda.node.services.schema.*; import net.corda.node.services.schema.*;
import net.corda.schemas.*; import net.corda.schemas.*;
@ -22,7 +24,6 @@ import net.corda.testing.contracts.*;
import net.corda.testing.node.*; import net.corda.testing.node.*;
import net.corda.testing.schemas.DummyLinearStateSchemaV1; import net.corda.testing.schemas.DummyLinearStateSchemaV1;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
import org.jetbrains.exposed.sql.*;
import org.junit.*; import org.junit.*;
import rx.Observable; import rx.Observable;
@ -34,8 +35,7 @@ import java.util.stream.*;
import static net.corda.contracts.asset.CashKt.*; import static net.corda.contracts.asset.CashKt.*;
import static net.corda.core.contracts.ContractsDSL.*; import static net.corda.core.contracts.ContractsDSL.*;
import static net.corda.core.node.services.vault.QueryCriteriaUtils.*; import static net.corda.core.node.services.vault.QueryCriteriaUtils.*;
import static net.corda.node.utilities.DatabaseSupportKt.*; import static net.corda.node.utilities.CordaPersistenceKt.configureDatabase;
import static net.corda.node.utilities.DatabaseSupportKt.transaction;
import static net.corda.testing.CoreTestUtils.*; import static net.corda.testing.CoreTestUtils.*;
import static net.corda.testing.node.MockServicesKt.*; import static net.corda.testing.node.MockServicesKt.*;
import static net.corda.core.utilities.ByteArrays.toHexString; import static net.corda.core.utilities.ByteArrays.toHexString;
@ -46,19 +46,16 @@ public class VaultQueryJavaTests {
private MockServices services; private MockServices services;
private VaultService vaultSvc; private VaultService vaultSvc;
private VaultQueryService vaultQuerySvc; private VaultQueryService vaultQuerySvc;
private Closeable dataSource; private CordaPersistence database;
private Database database;
@Before @Before
public void setUp() { public void setUp() {
Properties dataSourceProps = makeTestDataSourceProperties(SecureHash.randomSHA256().toString()); Properties dataSourceProps = makeTestDataSourceProperties(SecureHash.randomSHA256().toString());
Pair<Closeable, Database> dataSourceAndDatabase = configureDatabase(dataSourceProps); database = configureDatabase(dataSourceProps);
dataSource = dataSourceAndDatabase.getFirst();
database = dataSourceAndDatabase.getSecond();
Set<MappedSchema> customSchemas = new HashSet<>(Collections.singletonList(DummyLinearStateSchemaV1.INSTANCE)); Set<MappedSchema> customSchemas = new HashSet<>(Collections.singletonList(DummyLinearStateSchemaV1.INSTANCE));
HibernateConfiguration hibernateConfig = new HibernateConfiguration(new NodeSchemaService(customSchemas)); HibernateConfiguration hibernateConfig = new HibernateConfiguration(new NodeSchemaService(customSchemas));
transaction(database, database.transaction(
statement -> { services = new MockServices(getMEGA_CORP_KEY()) { statement -> { services = new MockServices(getMEGA_CORP_KEY()) {
@NotNull @NotNull
@Override @Override
@ -91,7 +88,7 @@ public class VaultQueryJavaTests {
@After @After
public void cleanUp() throws IOException { public void cleanUp() throws IOException {
dataSource.close(); database.close();
} }
/** /**
@ -104,7 +101,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void unconsumedLinearStates() throws VaultQueryException { public void unconsumedLinearStates() throws VaultQueryException {
transaction(database, tx -> { database.transaction(tx -> {
VaultFiller.fillWithSomeTestLinearStates(services, 3); VaultFiller.fillWithSomeTestLinearStates(services, 3);
@ -120,7 +117,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void unconsumedStatesForStateRefsSortedByTxnId() { public void unconsumedStatesForStateRefsSortedByTxnId() {
transaction(database, tx -> { database.transaction(tx -> {
VaultFiller.fillWithSomeTestLinearStates(services, 8); VaultFiller.fillWithSomeTestLinearStates(services, 8);
Vault<LinearState> issuedStates = VaultFiller.fillWithSomeTestLinearStates(services, 2); Vault<LinearState> issuedStates = VaultFiller.fillWithSomeTestLinearStates(services, 2);
@ -145,7 +142,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void consumedCashStates() { public void consumedCashStates() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> amount = new Amount<>(100, Currency.getInstance("USD")); Amount<Currency> amount = new Amount<>(100, Currency.getInstance("USD"));
@ -175,7 +172,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void consumedDealStatesPagedSorted() throws VaultQueryException { public void consumedDealStatesPagedSorted() throws VaultQueryException {
transaction(database, tx -> { database.transaction(tx -> {
Vault<LinearState> states = VaultFiller.fillWithSomeTestLinearStates(services, 10, null); Vault<LinearState> states = VaultFiller.fillWithSomeTestLinearStates(services, 10, null);
StateAndRef<LinearState> linearState = states.getStates().iterator().next(); StateAndRef<LinearState> linearState = states.getStates().iterator().next();
@ -217,7 +214,7 @@ public class VaultQueryJavaTests {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void customQueryForCashStatesWithAmountOfCurrencyGreaterOrEqualThanQuantity() { public void customQueryForCashStatesWithAmountOfCurrencyGreaterOrEqualThanQuantity() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> pounds = new Amount<>(100, Currency.getInstance("GBP")); Amount<Currency> pounds = new Amount<>(100, Currency.getInstance("GBP"));
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD")); Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
@ -261,7 +258,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void trackCashStates() { public void trackCashStates() {
transaction(database, tx -> { database.transaction(tx -> {
VaultFiller.fillWithSomeTestCash(services, VaultFiller.fillWithSomeTestCash(services,
new Amount<>(100, Currency.getInstance("USD")), new Amount<>(100, Currency.getInstance("USD")),
TestConstants.getDUMMY_NOTARY(), TestConstants.getDUMMY_NOTARY(),
@ -292,7 +289,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void trackDealStatesPagedSorted() { public void trackDealStatesPagedSorted() {
transaction(database, tx -> { database.transaction(tx -> {
Vault<LinearState> states = VaultFiller.fillWithSomeTestLinearStates(services, 10, null); Vault<LinearState> states = VaultFiller.fillWithSomeTestLinearStates(services, 10, null);
UniqueIdentifier uid = states.getStates().iterator().next().component1().getData().getLinearId(); UniqueIdentifier uid = states.getStates().iterator().next().component1().getData().getLinearId();
@ -333,7 +330,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void consumedStatesDeprecated() { public void consumedStatesDeprecated() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> amount = new Amount<>(100, USD); Amount<Currency> amount = new Amount<>(100, USD);
VaultFiller.fillWithSomeTestCash(services, VaultFiller.fillWithSomeTestCash(services,
new Amount<>(100, USD), new Amount<>(100, USD),
@ -365,7 +362,7 @@ public class VaultQueryJavaTests {
@Test @Test
public void consumedStatesForLinearIdDeprecated() { public void consumedStatesForLinearIdDeprecated() {
transaction(database, tx -> { database.transaction(tx -> {
Vault<LinearState> linearStates = VaultFiller.fillWithSomeTestLinearStates(services, 4,null); Vault<LinearState> linearStates = VaultFiller.fillWithSomeTestLinearStates(services, 4,null);
linearStates.getStates().iterator().next().component1().getData().getLinearId(); linearStates.getStates().iterator().next().component1().getData().getLinearId();
@ -394,7 +391,7 @@ public class VaultQueryJavaTests {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void aggregateFunctionsWithoutGroupClause() { public void aggregateFunctionsWithoutGroupClause() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD")); Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD")); Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD"));
@ -439,7 +436,7 @@ public class VaultQueryJavaTests {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void aggregateFunctionsWithSingleGroupClause() { public void aggregateFunctionsWithSingleGroupClause() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD")); Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD")); Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD"));
@ -510,7 +507,7 @@ public class VaultQueryJavaTests {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void aggregateFunctionsSumByIssuerAndCurrencyAndSortByAggregateSum() { public void aggregateFunctionsSumByIssuerAndCurrencyAndSortByAggregateSum() {
transaction(database, tx -> { database.transaction(tx -> {
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD")); Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD")); Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD"));

View File

@ -22,7 +22,6 @@ import net.corda.node.services.messaging.RpcContext
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.startFlowPermission import net.corda.node.services.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.utilities.transaction
import net.corda.nodeapi.PermissionException import net.corda.nodeapi.PermissionException
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.testing.expect import net.corda.testing.expect

View File

@ -13,16 +13,13 @@ import net.corda.node.services.database.RequeryConfiguration
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.persistence.schemas.requery.AttachmentEntity import net.corda.node.services.persistence.schemas.requery.AttachmentEntity
import net.corda.node.services.transactions.SimpleNotaryService import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.Closeable
import java.math.BigInteger import java.math.BigInteger
import java.security.KeyPair import java.security.KeyPair
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
@ -32,8 +29,6 @@ import kotlin.test.assertFailsWith
class AttachmentTests { class AttachmentTests {
lateinit var mockNet: MockNetwork lateinit var mockNet: MockNetwork
lateinit var dataSource: Closeable
lateinit var database: Database
lateinit var configuration: RequeryConfiguration lateinit var configuration: RequeryConfiguration
@Before @Before

View File

@ -35,14 +35,13 @@ import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.services.persistence.checkpoints import net.corda.node.services.persistence.checkpoints
import net.corda.node.utilities.transaction import net.corda.node.utilities.CordaPersistence
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -681,7 +680,7 @@ class TwoPartyTradeFlowTests {
} }
class RecordingTransactionStorage(val database: Database, val delegate: WritableTransactionStorage) : WritableTransactionStorage { class RecordingTransactionStorage(val database: CordaPersistence, val delegate: WritableTransactionStorage) : WritableTransactionStorage {
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> { override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
return database.transaction { return database.transaction {
delegate.track() delegate.track()

View File

@ -15,16 +15,16 @@ import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.statemachine.FlowStateMachineImpl import net.corda.node.services.statemachine.FlowStateMachineImpl
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.InMemoryTransactionVerifierService import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.utilities.CordaPersistence
import net.corda.testing.MOCK_IDENTITY_SERVICE import net.corda.testing.MOCK_IDENTITY_SERVICE
import net.corda.testing.node.MockAttachmentStorage import net.corda.testing.node.MockAttachmentStorage
import net.corda.testing.node.MockNetworkMapCache import net.corda.testing.node.MockNetworkMapCache
import net.corda.testing.node.MockStateMachineRecordedTransactionMappingStorage import net.corda.testing.node.MockStateMachineRecordedTransactionMappingStorage
import net.corda.testing.node.MockTransactionStorage import net.corda.testing.node.MockTransactionStorage
import org.jetbrains.exposed.sql.Database
import java.time.Clock import java.time.Clock
open class MockServiceHubInternal( open class MockServiceHubInternal(
override val database: Database, override val database: CordaPersistence,
override val configuration: NodeConfiguration, override val configuration: NodeConfiguration,
val customVault: VaultService? = null, val customVault: VaultService? = null,
val customVaultQuery: VaultQueryService? = null, val customVaultQuery: VaultQueryService? = null,

View File

@ -14,7 +14,6 @@ import net.corda.core.node.services.VaultService
import net.corda.core.schemas.PersistentStateRef import net.corda.core.schemas.PersistentStateRef
import net.corda.testing.schemas.DummyLinearStateSchemaV1 import net.corda.testing.schemas.DummyLinearStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV2 import net.corda.testing.schemas.DummyLinearStateSchemaV2
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.storageKryo import net.corda.core.serialization.storageKryo
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.testing.ALICE import net.corda.testing.ALICE
@ -25,9 +24,10 @@ import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.NodeVaultService
import net.corda.core.schemas.CommonSchemaV1 import net.corda.core.schemas.CommonSchemaV1
import net.corda.core.serialization.deserialize
import net.corda.node.services.vault.VaultSchemaV1 import net.corda.node.services.vault.VaultSchemaV1
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.schemas.CashSchemaV1 import net.corda.schemas.CashSchemaV1
import net.corda.schemas.SampleCashSchemaV2 import net.corda.schemas.SampleCashSchemaV2
import net.corda.schemas.SampleCashSchemaV3 import net.corda.schemas.SampleCashSchemaV3
@ -39,11 +39,9 @@ import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.hibernate.SessionFactory import org.hibernate.SessionFactory
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
import javax.persistence.EntityManager import javax.persistence.EntityManager
@ -53,8 +51,7 @@ import javax.persistence.criteria.CriteriaBuilder
class HibernateConfigurationTest { class HibernateConfigurationTest {
lateinit var services: MockServices lateinit var services: MockServices
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
val vault: VaultService get() = services.vaultService val vault: VaultService get() = services.vaultService
// Hibernate configuration objects // Hibernate configuration objects
@ -70,11 +67,9 @@ class HibernateConfigurationTest {
@Before @Before
fun setUp() { fun setUp() {
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
val customSchemas = setOf(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3) val customSchemas = setOf(VaultSchemaV1, CashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas)) hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas))
@ -104,7 +99,7 @@ class HibernateConfigurationTest {
@After @After
fun cleanUp() { fun cleanUp() {
dataSource.close() database.close()
} }
private fun setUpDb() { private fun setUpDb() {

View File

@ -23,40 +23,35 @@ import net.corda.node.services.vault.schemas.requery.Models
import net.corda.node.services.vault.schemas.requery.VaultCashBalancesEntity import net.corda.node.services.vault.schemas.requery.VaultCashBalancesEntity
import net.corda.node.services.vault.schemas.requery.VaultSchema import net.corda.node.services.vault.schemas.requery.VaultSchema
import net.corda.node.services.vault.schemas.requery.VaultStatesEntity import net.corda.node.services.vault.schemas.requery.VaultStatesEntity
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.time.Instant import java.time.Instant
import java.util.* import java.util.*
class RequeryConfigurationTest { class RequeryConfigurationTest {
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var transactionStorage: DBTransactionStorage lateinit var transactionStorage: DBTransactionStorage
lateinit var requerySession: KotlinEntityDataStore<Persistable> lateinit var requerySession: KotlinEntityDataStore<Persistable>
@Before @Before
fun setUp() { fun setUp() {
val dataSourceProperties = makeTestDataSourceProperties() val dataSourceProperties = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProperties) database = configureDatabase(dataSourceProperties)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
newTransactionStorage() newTransactionStorage()
newRequeryStorage(dataSourceProperties) newRequeryStorage(dataSourceProperties)
} }
@After @After
fun cleanUp() { fun cleanUp() {
dataSource.close() database.close()
} }
@Test @Test

View File

@ -18,9 +18,7 @@ import net.corda.node.services.persistence.DBCheckpointStorage
import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl import net.corda.node.services.statemachine.FlowLogicRefFactoryImpl
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.*
import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.getTestX509Name import net.corda.testing.getTestX509Name
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockKeyManagementService import net.corda.testing.node.MockKeyManagementService
@ -29,11 +27,9 @@ import net.corda.testing.node.makeTestDataSourceProperties
import net.corda.testing.testNodeConfiguration import net.corda.testing.testNodeConfiguration
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.nio.file.Paths import java.nio.file.Paths
import java.security.PublicKey import java.security.PublicKey
import java.time.Clock import java.time.Clock
@ -54,8 +50,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
lateinit var scheduler: NodeSchedulerService lateinit var scheduler: NodeSchedulerService
lateinit var smmExecutor: AffinityExecutor.ServiceAffinityExecutor lateinit var smmExecutor: AffinityExecutor.ServiceAffinityExecutor
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var countDown: CountDownLatch lateinit var countDown: CountDownLatch
lateinit var smmHasRemovedAllFlows: CountDownLatch lateinit var smmHasRemovedAllFlows: CountDownLatch
@ -76,9 +71,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
smmHasRemovedAllFlows = CountDownLatch(1) smmHasRemovedAllFlows = CountDownLatch(1)
calls = 0 calls = 0
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
val identityService = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate) val identityService = InMemoryIdentityService(trustRoot = DUMMY_CA.certificate)
val kms = MockKeyManagementService(identityService, ALICE_KEY) val kms = MockKeyManagementService(identityService, ALICE_KEY)
@ -120,7 +113,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
} }
smmExecutor.shutdown() smmExecutor.shutdown()
smmExecutor.awaitTermination(60, TimeUnit.SECONDS) smmExecutor.awaitTermination(60, TimeUnit.SECONDS)
dataSource.close() database.close()
} }
class TestState(val flowLogicRef: FlowLogicRef, val instant: Instant) : LinearState, SchedulableState { class TestState(val flowLogicRef: FlowLogicRef, val instant: Instant) : LinearState, SchedulableState {

View File

@ -11,7 +11,6 @@ import net.corda.core.node.services.linearHeadsOfType
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork

View File

@ -19,8 +19,8 @@ import net.corda.node.services.network.InMemoryNetworkMapCache
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.freeLocalHostAndPort import net.corda.testing.freeLocalHostAndPort
import net.corda.testing.freePort import net.corda.testing.freePort
import net.corda.testing.node.MOCK_VERSION_INFO import net.corda.testing.node.MOCK_VERSION_INFO
@ -28,13 +28,11 @@ import net.corda.testing.node.makeTestDataSourceProperties
import net.corda.testing.testNodeConfiguration import net.corda.testing.testNodeConfiguration
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
import java.io.Closeable
import java.net.ServerSocket import java.net.ServerSocket
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit.MILLISECONDS import java.util.concurrent.TimeUnit.MILLISECONDS
@ -52,8 +50,7 @@ class ArtemisMessagingTests {
val identity = generateKeyPair() val identity = generateKeyPair()
lateinit var config: NodeConfiguration lateinit var config: NodeConfiguration
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var userService: RPCUserService lateinit var userService: RPCUserService
lateinit var networkMapRegistrationFuture: ListenableFuture<Unit> lateinit var networkMapRegistrationFuture: ListenableFuture<Unit>
@ -75,9 +72,7 @@ class ArtemisMessagingTests {
baseDirectory = baseDirectory, baseDirectory = baseDirectory,
myLegalName = ALICE.name) myLegalName = ALICE.name)
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
networkMapRegistrationFuture = Futures.immediateFuture(Unit) networkMapRegistrationFuture = Futures.immediateFuture(Unit)
} }
@ -87,7 +82,7 @@ class ArtemisMessagingTests {
messagingServer?.stop() messagingServer?.stop()
messagingClient = null messagingClient = null
messagingServer = null messagingServer = null
dataSource.close() database.close()
LogHelper.reset(PersistentUniquenessProvider::class) LogHelper.reset(PersistentUniquenessProvider::class)
} }

View File

@ -5,7 +5,6 @@ import net.corda.core.node.services.NetworkMapCache
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.testing.ALICE import net.corda.testing.ALICE
import net.corda.testing.BOB import net.corda.testing.BOB
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test

View File

@ -4,7 +4,6 @@ import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.utilities.transaction
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode import net.corda.testing.node.MockNetwork.MockNode
import java.math.BigInteger import java.math.BigInteger

View File

@ -6,16 +6,14 @@ import net.corda.testing.LogHelper
import net.corda.node.services.api.Checkpoint import net.corda.node.services.api.Checkpoint
import net.corda.node.services.api.CheckpointStorage import net.corda.node.services.api.CheckpointStorage
import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
internal fun CheckpointStorage.checkpoints(): List<Checkpoint> { internal fun CheckpointStorage.checkpoints(): List<Checkpoint> {
val checkpoints = mutableListOf<Checkpoint>() val checkpoints = mutableListOf<Checkpoint>()
@ -28,21 +26,18 @@ internal fun CheckpointStorage.checkpoints(): List<Checkpoint> {
class DBCheckpointStorageTests { class DBCheckpointStorageTests {
lateinit var checkpointStorage: DBCheckpointStorage lateinit var checkpointStorage: DBCheckpointStorage
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
newCheckpointStorage() newCheckpointStorage()
} }
@After @After
fun cleanUp() { fun cleanUp() {
dataSource.close() database.close()
LogHelper.reset(PersistentUniquenessProvider::class) LogHelper.reset(PersistentUniquenessProvider::class)
} }

View File

@ -11,35 +11,30 @@ import net.corda.core.transactions.WireTransaction
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.LogHelper import net.corda.testing.LogHelper
import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals import kotlin.test.assertEquals
class DBTransactionStorageTests { class DBTransactionStorageTests {
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var transactionStorage: DBTransactionStorage lateinit var transactionStorage: DBTransactionStorage
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
newTransactionStorage() newTransactionStorage()
} }
@After @After
fun cleanUp() { fun cleanUp() {
dataSource.close() database.close()
LogHelper.reset(PersistentUniquenessProvider::class) LogHelper.reset(PersistentUniquenessProvider::class)
} }

View File

@ -14,7 +14,6 @@ import net.corda.core.identity.Party
import net.corda.core.node.services.unconsumedStates import net.corda.core.node.services.unconsumedStates
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.node.services.NotifyTransactionHandler import net.corda.node.services.NotifyTransactionHandler
import net.corda.node.utilities.transaction
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork

View File

@ -13,14 +13,12 @@ import net.corda.core.writeLines
import net.corda.node.services.database.RequeryConfiguration import net.corda.node.services.database.RequeryConfiguration
import net.corda.node.services.persistence.schemas.requery.AttachmentEntity import net.corda.node.services.persistence.schemas.requery.AttachmentEntity
import net.corda.node.services.transactions.PersistentUniquenessProvider import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.file.FileAlreadyExistsException import java.nio.file.FileAlreadyExistsException
import java.nio.file.FileSystem import java.nio.file.FileSystem
@ -35,8 +33,7 @@ import kotlin.test.assertNull
class NodeAttachmentStorageTest { class NodeAttachmentStorageTest {
// Use an in memory file system for testing attachment storage. // Use an in memory file system for testing attachment storage.
lateinit var fs: FileSystem lateinit var fs: FileSystem
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
lateinit var dataSourceProperties: Properties lateinit var dataSourceProperties: Properties
lateinit var configuration: RequeryConfiguration lateinit var configuration: RequeryConfiguration
@ -45,9 +42,7 @@ class NodeAttachmentStorageTest {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
dataSourceProperties = makeTestDataSourceProperties() dataSourceProperties = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProperties) database = configureDatabase(dataSourceProperties)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
configuration = RequeryConfiguration(dataSourceProperties) configuration = RequeryConfiguration(dataSourceProperties)
fs = Jimfs.newFileSystem(Configuration.unix()) fs = Jimfs.newFileSystem(Configuration.unix())
@ -55,7 +50,7 @@ class NodeAttachmentStorageTest {
@After @After
fun tearDown() { fun tearDown() {
dataSource.close() database.close()
} }
@Test @Test

View File

@ -10,38 +10,33 @@ import net.corda.core.schemas.QueryableState
import net.corda.testing.LogHelper import net.corda.testing.LogHelper
import net.corda.node.services.api.SchemaService import net.corda.node.services.api.SchemaService
import net.corda.node.services.database.HibernateConfiguration import net.corda.node.services.database.HibernateConfiguration
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.hibernate.annotations.Cascade import org.hibernate.annotations.Cascade
import org.hibernate.annotations.CascadeType import org.hibernate.annotations.CascadeType
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.transactions.TransactionManager import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.io.Closeable
import javax.persistence.* import javax.persistence.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
class HibernateObserverTests { class HibernateObserverTests {
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(HibernateObserver::class) LogHelper.setLevel(HibernateObserver::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
} }
@After @After
fun cleanUp() { fun cleanUp() {
dataSource.close() database.close()
LogHelper.reset(HibernateObserver::class) LogHelper.reset(HibernateObserver::class)
} }

View File

@ -33,7 +33,6 @@ import net.corda.flows.CashPaymentFlow
import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.services.persistence.checkpoints import net.corda.node.services.persistence.checkpoints
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.DummyState import net.corda.testing.contracts.DummyState
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
@ -90,6 +89,7 @@ class FlowFrameworkTests {
@After @After
fun cleanUp() { fun cleanUp() {
mockNet.stopNodes() mockNet.stopNodes()
sessionTransfers.clear()
} }
@Test @Test

View File

@ -10,15 +10,14 @@ import net.corda.core.getOrThrow
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.testing.LogHelper import net.corda.testing.LogHelper
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.testing.freeLocalHostAndPort import net.corda.testing.freeLocalHostAndPort
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Transaction import org.jetbrains.exposed.sql.Transaction
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -27,17 +26,14 @@ class DistributedImmutableMapTests {
data class Member(val client: CopycatClient, val server: CopycatServer) data class Member(val client: CopycatClient, val server: CopycatServer)
lateinit var cluster: List<Member> lateinit var cluster: List<Member>
lateinit var dataSource: Closeable
lateinit var transaction: Transaction lateinit var transaction: Transaction
lateinit var database: Database lateinit var database: CordaPersistence
@Before @Before
fun setup() { fun setup() {
LogHelper.setLevel("-org.apache.activemq") LogHelper.setLevel("-org.apache.activemq")
LogHelper.setLevel(NetworkMapService::class) LogHelper.setLevel(NetworkMapService::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
cluster = setUpCluster() cluster = setUpCluster()
} }
@ -49,7 +45,7 @@ class DistributedImmutableMapTests {
it.client.close() it.client.close()
it.server.shutdown() it.server.shutdown()
} }
dataSource.close() database.close()
} }
@Test @Test

View File

@ -2,17 +2,15 @@ package net.corda.node.services.transactions
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.node.services.UniquenessException import net.corda.core.node.services.UniquenessException
import net.corda.testing.LogHelper import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction import net.corda.testing.LogHelper
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.generateStateRef import net.corda.testing.generateStateRef
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@ -20,20 +18,17 @@ class PersistentUniquenessProviderTests {
val identity = MEGA_CORP val identity = MEGA_CORP
val txID = SecureHash.randomSHA256() val txID = SecureHash.randomSHA256()
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class) LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
} }
@After @After
fun tearDown() { fun tearDown() {
dataSource.close() database.close()
LogHelper.reset(PersistentUniquenessProvider::class) LogHelper.reset(PersistentUniquenessProvider::class)
} }

View File

@ -14,19 +14,17 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.NonEmptySet import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.util.* import java.util.*
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -38,16 +36,13 @@ import kotlin.test.assertTrue
class NodeVaultServiceTest { class NodeVaultServiceTest {
lateinit var services: MockServices lateinit var services: MockServices
val vaultSvc: VaultService get() = services.vaultService val vaultSvc: VaultService get() = services.vaultService
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(NodeVaultService::class) LogHelper.setLevel(NodeVaultService::class)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
services = object : MockServices() { services = object : MockServices() {
override val vaultService: VaultService = makeVaultService(dataSourceProps) override val vaultService: VaultService = makeVaultService(dataSourceProps)
@ -65,7 +60,7 @@ class NodeVaultServiceTest {
@After @After
fun tearDown() { fun tearDown() {
dataSource.close() database.close()
LogHelper.reset(NodeVaultService::class) LogHelper.reset(NodeVaultService::class)
} }

View File

@ -20,8 +20,8 @@ import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.toHexString import net.corda.core.utilities.toHexString
import net.corda.node.services.database.HibernateConfiguration import net.corda.node.services.database.HibernateConfiguration
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.schemas.CashSchemaV1 import net.corda.schemas.CashSchemaV1
import net.corda.schemas.CashSchemaV1.PersistentCashState import net.corda.schemas.CashSchemaV1.PersistentCashState
import net.corda.schemas.CommercialPaperSchemaV1 import net.corda.schemas.CommercialPaperSchemaV1
@ -35,10 +35,8 @@ import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.junit.* import org.junit.*
import org.junit.rules.ExpectedException import org.junit.rules.ExpectedException
import java.io.Closeable
import java.lang.Thread.sleep import java.lang.Thread.sleep
import java.math.BigInteger import java.math.BigInteger
import java.security.KeyPair import java.security.KeyPair
@ -53,15 +51,12 @@ class VaultQueryTests {
lateinit var services: MockServices lateinit var services: MockServices
val vaultSvc: VaultService get() = services.vaultService val vaultSvc: VaultService get() = services.vaultService
val vaultQuerySvc: VaultQueryService get() = services.vaultQueryService val vaultQuerySvc: VaultQueryService get() = services.vaultQueryService
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
@Before @Before
fun setUp() { fun setUp() {
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
val customSchemas = setOf(CommercialPaperSchemaV1, DummyLinearStateSchemaV1) val customSchemas = setOf(CommercialPaperSchemaV1, DummyLinearStateSchemaV1)
val hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas)) val hibernateConfig = HibernateConfiguration(NodeSchemaService(customSchemas))
@ -82,7 +77,7 @@ class VaultQueryTests {
@After @After
fun tearDown() { fun tearDown() {
dataSource.close() database.close()
} }
/** /**
@ -91,16 +86,14 @@ class VaultQueryTests {
@Ignore @Ignore
@Test @Test
fun createPersistentTestDb() { fun createPersistentTestDb() {
val dataSourceAndDatabase = configureDatabase(makePersistentDataSourceProperties()) val database = configureDatabase(makePersistentDataSourceProperties())
val dataSource = dataSourceAndDatabase.first
val database = dataSourceAndDatabase.second
setUpDb(database, 5000) setUpDb(database, 5000)
dataSource.close() database.close()
} }
private fun setUpDb(_database: Database, delay: Long = 0) { private fun setUpDb(_database: CordaPersistence, delay: Long = 0) {
_database.transaction { _database.transaction {

View File

@ -13,23 +13,21 @@ import net.corda.core.node.services.VaultService
import net.corda.core.node.services.consumedStates import net.corda.core.node.services.consumedStates
import net.corda.core.node.services.unconsumedStates import net.corda.core.node.services.unconsumedStates
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.BOB import net.corda.testing.BOB
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_NOTARY_KEY import net.corda.testing.DUMMY_NOTARY_KEY
import net.corda.testing.LogHelper import net.corda.testing.LogHelper
import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP
import net.corda.testing.MEGA_CORP_KEY import net.corda.testing.MEGA_CORP_KEY
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.util.* import java.util.*
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -41,17 +39,14 @@ import kotlin.test.assertNull
class VaultWithCashTest { class VaultWithCashTest {
lateinit var services: MockServices lateinit var services: MockServices
val vault: VaultService get() = services.vaultService val vault: VaultService get() = services.vaultService
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
val notaryServices = MockServices(DUMMY_NOTARY_KEY) val notaryServices = MockServices(DUMMY_NOTARY_KEY)
@Before @Before
fun setUp() { fun setUp() {
LogHelper.setLevel(VaultWithCashTest::class) LogHelper.setLevel(VaultWithCashTest::class)
val dataSourceProps = makeTestDataSourceProperties() val dataSourceProps = makeTestDataSourceProperties()
val dataSourceAndDatabase = configureDatabase(dataSourceProps) database = configureDatabase(dataSourceProps)
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
services = object : MockServices() { services = object : MockServices() {
override val vaultService: VaultService = makeVaultService(dataSourceProps) override val vaultService: VaultService = makeVaultService(dataSourceProps)
@ -70,7 +65,7 @@ class VaultWithCashTest {
@After @After
fun tearDown() { fun tearDown() {
LogHelper.reset(VaultWithCashTest::class) LogHelper.reset(VaultWithCashTest::class)
dataSource.close() database.close()
} }
@Test @Test

View File

@ -5,8 +5,6 @@ import net.corda.core.bufferUntilSubscribed
import net.corda.core.tee import net.corda.core.tee
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
import rx.Observable import rx.Observable
@ -16,13 +14,13 @@ import java.util.*
class ObservablesTests { class ObservablesTests {
private fun isInDatabaseTransaction(): Boolean = (TransactionManager.currentOrNull() != null) private fun isInDatabaseTransaction(): Boolean = (DatabaseTransactionManager.currentOrNull() != null)
val toBeClosed = mutableListOf<Closeable>() val toBeClosed = mutableListOf<Closeable>()
fun createDatabase(): Database { fun createDatabase(): CordaPersistence {
val (closeable, database) = configureDatabase(makeTestDataSourceProperties()) val database = configureDatabase(makeTestDataSourceProperties())
toBeClosed += closeable toBeClosed += database
return database return database
} }
@ -167,7 +165,7 @@ class ObservablesTests {
observableWithDbTx.first().subscribe { undelayedEvent.set(it to isInDatabaseTransaction()) } observableWithDbTx.first().subscribe { undelayedEvent.set(it to isInDatabaseTransaction()) }
fun observeSecondEvent(event: Int, future: SettableFuture<Pair<Int, UUID?>>) { fun observeSecondEvent(event: Int, future: SettableFuture<Pair<Int, UUID?>>) {
future.set(event to if (isInDatabaseTransaction()) StrandLocalTransactionManager.transactionId else null) future.set(event to if (isInDatabaseTransaction()) DatabaseTransactionManager.transactionId else null)
} }
observableWithDbTx.skip(1).first().subscribe { observeSecondEvent(it, delayedEventFromSecondObserver) } observableWithDbTx.skip(1).first().subscribe { observeSecondEvent(it, delayedEventFromSecondObserver) }

View File

@ -17,19 +17,17 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.testing.LogHelper import net.corda.testing.LogHelper
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.irs.flows.RatesFixFlow import net.corda.irs.flows.RatesFixFlow
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.makeTestDataSourceProperties import net.corda.testing.node.makeTestDataSourceProperties
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.junit.After import org.junit.After
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.Closeable
import java.math.BigDecimal import java.math.BigDecimal
import java.util.function.Predicate import java.util.function.Predicate
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -50,8 +48,7 @@ class NodeInterestRatesTest {
val DUMMY_CASH_ISSUER = Party(X500Name("CN=Cash issuer,O=R3,OU=corda,L=London,C=GB"), DUMMY_CASH_ISSUER_KEY.public) val DUMMY_CASH_ISSUER = Party(X500Name("CN=Cash issuer,O=R3,OU=corda,L=London,C=GB"), DUMMY_CASH_ISSUER_KEY.public)
lateinit var oracle: NodeInterestRates.Oracle lateinit var oracle: NodeInterestRates.Oracle
lateinit var dataSource: Closeable lateinit var database: CordaPersistence
lateinit var database: Database
fun fixCmdFilter(elem: Any): Boolean { fun fixCmdFilter(elem: Any): Boolean {
return when (elem) { return when (elem) {
@ -64,9 +61,7 @@ class NodeInterestRatesTest {
@Before @Before
fun setUp() { fun setUp() {
val dataSourceAndDatabase = configureDatabase(makeTestDataSourceProperties()) database = configureDatabase(makeTestDataSourceProperties())
dataSource = dataSourceAndDatabase.first
database = dataSourceAndDatabase.second
database.transaction { database.transaction {
oracle = NodeInterestRates.Oracle( oracle = NodeInterestRates.Oracle(
MEGA_CORP, MEGA_CORP,
@ -78,7 +73,7 @@ class NodeInterestRatesTest {
@After @After
fun tearDown() { fun tearDown() {
dataSource.close() database.close()
} }
@Test @Test

View File

@ -22,7 +22,6 @@ import net.corda.irs.contract.InterestRateSwap
import net.corda.irs.flows.FixingFlow import net.corda.irs.flows.FixingFlow
import net.corda.jackson.JacksonSupport import net.corda.jackson.JacksonSupport
import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.utilities.transaction
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import rx.Observable import rx.Observable
import java.security.PublicKey import java.security.PublicKey

View File

@ -19,7 +19,6 @@ import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.SimpleNotaryService import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.node.utilities.transaction
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.TestClock import net.corda.testing.node.TestClock

View File

@ -17,12 +17,11 @@ import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.utilities.trace import net.corda.core.utilities.trace
import net.corda.node.services.messaging.* import net.corda.node.services.messaging.*
import net.corda.node.utilities.AffinityExecutor import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.JDBCHashSet import net.corda.node.utilities.JDBCHashSet
import net.corda.node.utilities.transaction
import net.corda.testing.node.InMemoryMessagingNetwork.InMemoryMessaging import net.corda.testing.node.InMemoryMessagingNetwork.InMemoryMessaging
import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.activemq.artemis.utils.ReusableLatch
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.jetbrains.exposed.sql.Database
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
@ -108,7 +107,7 @@ class InMemoryMessagingNetwork(
fun createNode(manuallyPumped: Boolean, fun createNode(manuallyPumped: Boolean,
executor: AffinityExecutor, executor: AffinityExecutor,
advertisedServices: List<ServiceEntry>, advertisedServices: List<ServiceEntry>,
database: Database): Pair<PeerHandle, MessagingServiceBuilder<InMemoryMessaging>> { database: CordaPersistence): Pair<PeerHandle, MessagingServiceBuilder<InMemoryMessaging>> {
check(counter >= 0) { "In memory network stopped: please recreate." } check(counter >= 0) { "In memory network stopped: please recreate." }
val builder = createNodeWithID(manuallyPumped, counter, executor, advertisedServices, database = database) as Builder val builder = createNodeWithID(manuallyPumped, counter, executor, advertisedServices, database = database) as Builder
counter++ counter++
@ -130,7 +129,7 @@ class InMemoryMessagingNetwork(
executor: AffinityExecutor, executor: AffinityExecutor,
advertisedServices: List<ServiceEntry>, advertisedServices: List<ServiceEntry>,
description: X500Name = X509Utilities.getX509Name("In memory node $id","London","demo@r3.com",null), description: X500Name = X509Utilities.getX509Name("In memory node $id","London","demo@r3.com",null),
database: Database) database: CordaPersistence)
: MessagingServiceBuilder<InMemoryMessaging> { : MessagingServiceBuilder<InMemoryMessaging> {
val peerHandle = PeerHandle(id, description) val peerHandle = PeerHandle(id, description)
peersMapping[peerHandle.description] = peerHandle // Assume that the same name - the same entity in MockNetwork. peersMapping[peerHandle.description] = peerHandle // Assume that the same name - the same entity in MockNetwork.
@ -187,7 +186,7 @@ class InMemoryMessagingNetwork(
val id: PeerHandle, val id: PeerHandle,
val serviceHandles: List<ServiceHandle>, val serviceHandles: List<ServiceHandle>,
val executor: AffinityExecutor, val executor: AffinityExecutor,
val database: Database) : MessagingServiceBuilder<InMemoryMessaging> { val database: CordaPersistence) : MessagingServiceBuilder<InMemoryMessaging> {
override fun start(): ListenableFuture<InMemoryMessaging> { override fun start(): ListenableFuture<InMemoryMessaging> {
synchronized(this@InMemoryMessagingNetwork) { synchronized(this@InMemoryMessagingNetwork) {
val node = InMemoryMessaging(manuallyPumped, id, executor, database) val node = InMemoryMessaging(manuallyPumped, id, executor, database)
@ -304,7 +303,7 @@ class InMemoryMessagingNetwork(
inner class InMemoryMessaging(private val manuallyPumped: Boolean, inner class InMemoryMessaging(private val manuallyPumped: Boolean,
private val peerHandle: PeerHandle, private val peerHandle: PeerHandle,
private val executor: AffinityExecutor, private val executor: AffinityExecutor,
private val database: Database) : SingletonSerializeAsToken(), MessagingService { private val database: CordaPersistence) : SingletonSerializeAsToken(), MessagingService {
inner class Handler(val topicSession: TopicSession, inner class Handler(val topicSession: TopicSession,
val callback: (ReceivedMessage, MessageHandlerRegistration) -> Unit) : MessageHandlerRegistration val callback: (ReceivedMessage, MessageHandlerRegistration) -> Unit) : MessageHandlerRegistration

View File

@ -17,11 +17,9 @@ import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.NodeMessagingClient import net.corda.node.services.messaging.NodeMessagingClient
import net.corda.node.services.network.InMemoryNetworkMapCache import net.corda.node.services.network.InMemoryNetworkMapCache
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.node.utilities.transaction
import net.corda.testing.freeLocalHostAndPort import net.corda.testing.freeLocalHostAndPort
import org.jetbrains.exposed.sql.Database
import java.io.Closeable
import java.security.KeyPair import java.security.KeyPair
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import kotlin.concurrent.thread import kotlin.concurrent.thread
@ -34,8 +32,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort
rpcAddress: NetworkHostAndPort = freeLocalHostAndPort(), rpcAddress: NetworkHostAndPort = freeLocalHostAndPort(),
trustRoot: X509Certificate) : AutoCloseable { trustRoot: X509Certificate) : AutoCloseable {
private val databaseWithCloseable: Pair<Closeable, Database> = configureDatabase(config.dataSourceProperties) val database: CordaPersistence = configureDatabase(config.dataSourceProperties)
val database: Database get() = databaseWithCloseable.second
val userService = RPCUserServiceImpl(config.rpcUsers) val userService = RPCUserServiceImpl(config.rpcUsers)
val monitoringService = MonitoringService(MetricRegistry()) val monitoringService = MonitoringService(MetricRegistry())
val identity: KeyPair = generateKeyPair() val identity: KeyPair = generateKeyPair()
@ -72,7 +69,7 @@ class SimpleNode(val config: NodeConfiguration, val address: NetworkHostAndPort
override fun close() { override fun close() {
network.stop() network.stop()
broker.stop() broker.stop()
databaseWithCloseable.first.close() database.close()
executor.shutdownNow() executor.shutdownNow()
} }
} }