Merge remote-tracking branch 'origin/release/os/4.9' into vkolomeyko/os-4.9-4.10-merge

# Conflicts:
#	build.gradle
This commit is contained in:
Viktor Kolomeyko 2022-02-24 16:46:48 +00:00
commit df34a59b02
16 changed files with 592 additions and 142 deletions

View File

@ -397,7 +397,6 @@ allprojects {
includeGroup 'org.crashub' includeGroup 'org.crashub'
includeGroup 'com.github.bft-smart' includeGroup 'com.github.bft-smart'
includeGroup 'com.github.detro' includeGroup 'com.github.detro'
includeGroup 'org.apache.activemq'
} }
} }
maven { maven {

View File

@ -16,5 +16,6 @@ object PlatformVersionSwitches {
const val LIMIT_KEYS_IN_SIGNATURE_CONSTRAINTS = 5 const val LIMIT_KEYS_IN_SIGNATURE_CONSTRAINTS = 5
const val BATCH_DOWNLOAD_COUNTERPARTY_BACKCHAIN = 6 const val BATCH_DOWNLOAD_COUNTERPARTY_BACKCHAIN = 6
const val ENABLE_P2P_COMPRESSION = 7 const val ENABLE_P2P_COMPRESSION = 7
const val RESTRICTED_DATABASE_OPERATIONS = 7
const val CERTIFICATE_ROTATION = 9 const val CERTIFICATE_ROTATION = 9
} }

View File

@ -5,6 +5,10 @@ apply plugin: 'net.corda.plugins.publish-utils'
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.artifactory' apply plugin: 'com.jfrog.artifactory'
dependencies {
compile rootProject
}
def internalPackagePrefixes(sourceDirs) { def internalPackagePrefixes(sourceDirs) {
def prefixes = [] def prefixes = []
// Kotlin allows packages to deviate from the directory structure, but let's assume they don't: // Kotlin allows packages to deviate from the directory structure, but let's assume they don't:
@ -36,10 +40,13 @@ task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
} }
[dokka, dokkaJavadoc].collect { [dokka, dokkaJavadoc].collect {
it.configure { it.configuration {
moduleName = 'corda' moduleName = 'corda'
processConfigurations = ['compile'] dokkaSourceDirs.collect { sourceDir ->
sourceDirs = dokkaSourceDirs sourceRoot {
path = sourceDir.path
}
}
includes = ['packages.md'] includes = ['packages.md']
jdkVersion = 8 jdkVersion = 8
externalDocumentationLink { externalDocumentationLink {
@ -52,7 +59,7 @@ task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
url = new URL("https://www.bouncycastle.org/docs/docs1.5on/") url = new URL("https://www.bouncycastle.org/docs/docs1.5on/")
} }
internalPackagePrefixes.collect { packagePrefix -> internalPackagePrefixes.collect { packagePrefix ->
packageOptions { perPackageOption {
prefix = packagePrefix prefix = packagePrefix
suppress = true suppress = true
} }

View File

@ -4,14 +4,15 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.persistence.RestrictedConnection import net.corda.nodeapi.internal.persistence.RestrictedConnection
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.StartedMockNode import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.internal.enclosedCordapp
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.junit.After import org.junit.After
import org.junit.Before
import org.junit.Test import org.junit.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -38,40 +39,63 @@ class RestrictedConnectionFlowTest {
} }
@InitiatingFlow @InitiatingFlow
class TestCloseMethodIsBlocked : FlowLogic<Unit>() { class TestClearWarningsMethodIsBlocked : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
val connection = serviceHub.jdbcSession() val connection = serviceHub.jdbcSession()
connection.close() connection.clearWarnings()
} }
} }
@Before
fun init() {
mockNetwork = MockNetwork(MockNetworkParameters())
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
}
@After @After
fun done() { fun done() {
mockNetwork.stopNodes() mockNetwork.stopNodes()
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun testIfItIsRestrictedConnection() { fun `restricted connection is returned from ServiceHub#jdbcSession`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = PLATFORM_VERSION))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
assertTrue { aliceNode.startFlow(TestIfItIsRestrictedConnection()).get() } assertTrue { aliceNode.startFlow(TestIfItIsRestrictedConnection()).get() }
mockNetwork.runNetwork() mockNetwork.runNetwork()
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun testMethodsAreBlocked() { fun `restricted methods are blocked when the target platform is the current corda version`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = PLATFORM_VERSION))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java) Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestAutoCommitMethodIsBlocked()).getOrThrow() } .isThrownBy { aliceNode.startFlow(TestAutoCommitMethodIsBlocked()).getOrThrow() }
.withMessageContaining("This method cannot be called via ServiceHub.jdbcSession.") .withMessageContaining("ServiceHub.jdbcSession.setAutoCommit is restricted and cannot be called")
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java) Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestCloseMethodIsBlocked()).getOrThrow() } .isThrownBy { aliceNode.startFlow(TestClearWarningsMethodIsBlocked()).getOrThrow() }
.withMessageContaining("This method cannot be called via ServiceHub.jdbcSession.") .withMessageContaining("ServiceHub.jdbcSession.clearWarnings is restricted and cannot be called")
mockNetwork.runNetwork()
}
@Test(timeout=300_000)
fun `restricted methods are blocked when the target platform is 7`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = 7))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestAutoCommitMethodIsBlocked()).getOrThrow() }
.withMessageContaining("ServiceHub.jdbcSession.setAutoCommit is restricted and cannot be called")
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestClearWarningsMethodIsBlocked()).getOrThrow() }
.withMessageContaining("ServiceHub.jdbcSession.clearWarnings is restricted and cannot be called")
mockNetwork.runNetwork()
}
@Test(timeout=300_000)
fun `restricted methods are not blocked when the target platform is 6`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = 6))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
aliceNode.startFlow(TestAutoCommitMethodIsBlocked()).getOrThrow()
aliceNode.startFlow(TestClearWarningsMethodIsBlocked()).getOrThrow()
mockNetwork.runNetwork() mockNetwork.runNetwork()
} }

View File

@ -4,14 +4,15 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.nodeapi.internal.persistence.RestrictedEntityManager import net.corda.nodeapi.internal.persistence.RestrictedEntityManager
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.StartedMockNode import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.internal.enclosedCordapp
import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions
import org.junit.After import org.junit.After
import org.junit.Before
import org.junit.Test import org.junit.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
@ -25,7 +26,7 @@ class RestrictedEntityManagerFlowTest {
@Suspendable @Suspendable
override fun call() : Boolean { override fun call() : Boolean {
var result = false var result = false
serviceHub.withEntityManager() { serviceHub.withEntityManager {
result = this is RestrictedEntityManager result = this is RestrictedEntityManager
} }
return result return result
@ -33,11 +34,11 @@ class RestrictedEntityManagerFlowTest {
} }
@InitiatingFlow @InitiatingFlow
class TestCloseMethodIsBlocked : FlowLogic<Unit>() { class TestGetMetamodelMethodIsBlocked : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
serviceHub.withEntityManager() { serviceHub.withEntityManager {
this.close() this.metamodel
} }
} }
} }
@ -46,38 +47,61 @@ class RestrictedEntityManagerFlowTest {
class TestJoinTransactionMethodIsBlocked : FlowLogic<Unit>() { class TestJoinTransactionMethodIsBlocked : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
serviceHub.withEntityManager() { serviceHub.withEntityManager {
this.joinTransaction() this.joinTransaction()
} }
} }
} }
@Before
fun init() {
mockNetwork = MockNetwork(MockNetworkParameters())
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
}
@After @After
fun done() { fun done() {
mockNetwork.stopNodes() mockNetwork.stopNodes()
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun testIfItIsRestrictedConnection() { fun `restricted connection is returned from ServiceHub#withEntityManager`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = PLATFORM_VERSION))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
assertTrue { aliceNode.startFlow(TestIfItIsRestrictedEntityManager()).get() } assertTrue { aliceNode.startFlow(TestIfItIsRestrictedEntityManager()).get() }
mockNetwork.runNetwork() mockNetwork.runNetwork()
} }
@Test(timeout=300_000) @Test(timeout=300_000)
fun testMethodsAreBlocked() { fun `restricted methods are blocked when the target platform is the current corda version`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = PLATFORM_VERSION))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java) Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestCloseMethodIsBlocked()).getOrThrow() } .isThrownBy { aliceNode.startFlow(TestGetMetamodelMethodIsBlocked()).getOrThrow() }
.withMessageContaining("This method cannot be called via ServiceHub.withEntityManager.") .withMessageContaining("ServiceHub.withEntityManager.getMetamodel is restricted and cannot be called")
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java) Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestJoinTransactionMethodIsBlocked()).getOrThrow() } .isThrownBy { aliceNode.startFlow(TestJoinTransactionMethodIsBlocked()).getOrThrow() }
.withMessageContaining("This method cannot be called via ServiceHub.withEntityManager.") .withMessageContaining("ServiceHub.withEntityManager.joinTransaction is restricted and cannot be called")
mockNetwork.runNetwork()
}
@Test(timeout=300_000)
fun `restricted methods are blocked when the target platform is 7`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = 7))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestGetMetamodelMethodIsBlocked()).getOrThrow() }
.withMessageContaining("ServiceHub.withEntityManager.getMetamodel is restricted and cannot be called")
Assertions.assertThatExceptionOfType(UnsupportedOperationException::class.java)
.isThrownBy { aliceNode.startFlow(TestJoinTransactionMethodIsBlocked()).getOrThrow() }
.withMessageContaining("ServiceHub.withEntityManager.joinTransaction is restricted and cannot be called")
mockNetwork.runNetwork()
}
@Test(timeout=300_000)
fun `restricted methods are not blocked when the target platform is 6`() {
mockNetwork = MockNetwork(MockNetworkParameters(listOf(enclosedCordapp().copy(targetPlatformVersion = 6))))
aliceNode = mockNetwork.createPartyNode(CordaX500Name("Alice", "London", "GB"))
aliceNode.startFlow(TestGetMetamodelMethodIsBlocked()).getOrThrow()
aliceNode.startFlow(TestJoinTransactionMethodIsBlocked()).getOrThrow()
mockNetwork.runNetwork() mockNetwork.runNetwork()
} }

View File

@ -8,14 +8,13 @@ import org.apache.activemq.artemis.core.protocol.core.impl.wireformat.MessagePac
import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage
import org.apache.activemq.artemis.protocol.amqp.broker.AmqpInterceptor import org.apache.activemq.artemis.protocol.amqp.broker.AmqpInterceptor
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection
import org.apache.qpid.proton.amqp.messaging.Data
class ArtemisMessageSizeChecksInterceptor(maxMessageSize: Int) : MessageSizeChecksInterceptor<Packet>(maxMessageSize), Interceptor { class ArtemisMessageSizeChecksInterceptor(maxMessageSize: Int) : MessageSizeChecksInterceptor<Packet>(maxMessageSize), Interceptor {
override fun getMessageSize(packet: Packet?): Int? { override fun getMessageSize(packet: Packet?): Long? {
return when (packet) { return when (packet) {
// This is an estimate of how much memory a Message body takes up. // This is an estimate of how much memory a Message body takes up.
// Note, it is only an estimate // Note, it is only an estimate
is MessagePacket -> (packet.message.persistentSize - packet.message.headersAndPropertiesEncodeSize - 4).toInt() is MessagePacket -> (packet.message.persistentSize - packet.message.headersAndPropertiesEncodeSize - 4)
// Skip all artemis control messages. // Skip all artemis control messages.
else -> null else -> null
} }
@ -23,7 +22,7 @@ class ArtemisMessageSizeChecksInterceptor(maxMessageSize: Int) : MessageSizeChec
} }
class AmqpMessageSizeChecksInterceptor(maxMessageSize: Int) : MessageSizeChecksInterceptor<AMQPMessage>(maxMessageSize), AmqpInterceptor { class AmqpMessageSizeChecksInterceptor(maxMessageSize: Int) : MessageSizeChecksInterceptor<AMQPMessage>(maxMessageSize), AmqpInterceptor {
override fun getMessageSize(packet: AMQPMessage?): Int? = (packet?.protonMessage?.body as? Data)?.value?.length override fun getMessageSize(packet: AMQPMessage?): Long? = packet?.wholeMessageSize
} }
/** /**
@ -46,6 +45,6 @@ sealed class MessageSizeChecksInterceptor<T : Any>(private val maxMessageSize: I
} }
// get size of the message in byte, returns null if the message is null or size don't need to be checked. // get size of the message in byte, returns null if the message is null or size don't need to be checked.
abstract fun getMessageSize(packet: T?): Int? abstract fun getMessageSize(packet: T?): Long?
} }

View File

@ -1,5 +1,6 @@
package net.corda.nodeapi.internal.persistence package net.corda.nodeapi.internal.persistence
import net.corda.core.node.ServiceHub
import java.sql.Connection import java.sql.Connection
import java.sql.Savepoint import java.sql.Savepoint
import java.util.concurrent.Executor import java.util.concurrent.Executor
@ -8,73 +9,73 @@ import java.util.concurrent.Executor
* A delegate of [Connection] which disallows some operations. * A delegate of [Connection] which disallows some operations.
*/ */
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class RestrictedConnection(private val delegate : Connection) : Connection by delegate { class RestrictedConnection(private val delegate: Connection, private val serviceHub: ServiceHub) : Connection by delegate {
override fun abort(executor: Executor?) { override fun abort(executor: Executor?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("abort", serviceHub) { delegate.abort(executor) }
} }
override fun clearWarnings() { override fun clearWarnings() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("clearWarnings", serviceHub) { delegate.clearWarnings() }
} }
override fun close() { override fun close() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("close", serviceHub) { delegate.close() }
} }
override fun commit() { override fun commit() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("commit", serviceHub) { delegate.commit() }
} }
override fun setSavepoint(): Savepoint? { override fun setSavepoint(): Savepoint? {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") return restrictDatabaseOperationFromJdbcSession("setSavepoint", serviceHub) { delegate.setSavepoint() }
} }
override fun setSavepoint(name : String?): Savepoint? { override fun setSavepoint(name: String?): Savepoint? {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") return restrictDatabaseOperationFromJdbcSession("setSavepoint", serviceHub) { delegate.setSavepoint(name) }
} }
override fun releaseSavepoint(savepoint: Savepoint?) { override fun releaseSavepoint(savepoint: Savepoint?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("releaseSavepoint", serviceHub) { delegate.releaseSavepoint(savepoint) }
} }
override fun rollback() { override fun rollback() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("rollback", serviceHub) { delegate.rollback() }
} }
override fun rollback(savepoint: Savepoint?) { override fun rollback(savepoint: Savepoint?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("rollback", serviceHub) { delegate.rollback(savepoint) }
} }
override fun setCatalog(catalog : String?) { override fun setCatalog(catalog: String?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setCatalog", serviceHub) { delegate.catalog = catalog }
} }
override fun setTransactionIsolation(level: Int) { override fun setTransactionIsolation(level: Int) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setTransactionIsolation", serviceHub) { delegate.transactionIsolation = level }
} }
override fun setTypeMap(map: MutableMap<String, Class<*>>?) { override fun setTypeMap(map: MutableMap<String, Class<*>>?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setTypeMap", serviceHub) { delegate.typeMap = map }
} }
override fun setHoldability(holdability: Int) { override fun setHoldability(holdability: Int) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setHoldability", serviceHub) { delegate.holdability = holdability }
} }
override fun setSchema(schema: String?) { override fun setSchema(schema: String?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setSchema", serviceHub) { delegate.schema = schema }
} }
override fun setNetworkTimeout(executor: Executor?, milliseconds: Int) { override fun setNetworkTimeout(executor: Executor?, milliseconds: Int) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setNetworkTimeout", serviceHub) { delegate.setNetworkTimeout(executor, milliseconds) }
} }
override fun setAutoCommit(autoCommit: Boolean) { override fun setAutoCommit(autoCommit: Boolean) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setAutoCommit", serviceHub) { delegate.autoCommit = autoCommit }
} }
override fun setReadOnly(readOnly: Boolean) { override fun setReadOnly(readOnly: Boolean) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.jdbcSession.") restrictDatabaseOperationFromJdbcSession("setReadOnly", serviceHub) { delegate.isReadOnly = readOnly }
} }
} }

View File

@ -0,0 +1,31 @@
package net.corda.nodeapi.internal.persistence
import net.corda.core.internal.PlatformVersionSwitches.RESTRICTED_DATABASE_OPERATIONS
import net.corda.core.internal.warnOnce
import net.corda.core.node.ServiceHub
import org.slf4j.LoggerFactory
private val log = LoggerFactory.getLogger("RestrictedDatabaseOperations")
internal inline fun <T> restrictDatabaseOperationFromJdbcSession(method: String, serviceHub: ServiceHub, operation: () -> T): T {
return restrictDatabaseOperation("ServiceHub.jdbcSession.$method", serviceHub, operation)
}
internal inline fun <T> restrictDatabaseOperationFromEntityManager(method: String, serviceHub: ServiceHub, operation: () -> T): T {
return restrictDatabaseOperation("ServiceHub.withEntityManager.$method", serviceHub, operation)
}
internal inline fun <T> restrictDatabaseOperation(method: String, serviceHub: ServiceHub, operation: () -> T): T {
return if (serviceHub.getAppContext().cordapp.targetPlatformVersion >= RESTRICTED_DATABASE_OPERATIONS) {
throw UnsupportedOperationException("$method is restricted and cannot be called")
} else {
log.warnOnce(
"$method should not be called, as manipulating database transactions and connections breaks the Corda flow state machine in " +
"ways that only become evident in failure scenarios. Purely for API backwards compatibility reasons, the prior " +
"behaviour is continued for target platform versions less than $RESTRICTED_DATABASE_OPERATIONS. You should evolve " +
"the CorDapp away from using these problematic APIs as soon as possible. For target platform version of " +
"$RESTRICTED_DATABASE_OPERATIONS or above, an exception will be thrown instead."
)
operation()
}
}

View File

@ -1,5 +1,6 @@
package net.corda.nodeapi.internal.persistence package net.corda.nodeapi.internal.persistence
import net.corda.core.node.ServiceHub
import javax.persistence.EntityManager import javax.persistence.EntityManager
import javax.persistence.EntityTransaction import javax.persistence.EntityTransaction
import javax.persistence.LockModeType import javax.persistence.LockModeType
@ -8,56 +9,59 @@ import javax.persistence.metamodel.Metamodel
/** /**
* A delegate of [EntityManager] which disallows some operations. * A delegate of [EntityManager] which disallows some operations.
*/ */
class RestrictedEntityManager(private val delegate: EntityManager) : EntityManager by delegate { class RestrictedEntityManager(private val delegate: EntityManager, private val serviceHub: ServiceHub) : EntityManager by delegate {
override fun getTransaction(): EntityTransaction { override fun getTransaction(): EntityTransaction {
return RestrictedEntityTransaction(delegate.transaction) return RestrictedEntityTransaction(delegate.transaction, serviceHub)
} }
override fun close() { override fun close() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("close", serviceHub) { delegate.close() }
} }
override fun <T : Any?> unwrap(cls: Class<T>?): T { override fun <T : Any?> unwrap(cls: Class<T>?): T {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") return restrictDatabaseOperationFromEntityManager("unwrap", serviceHub) { delegate.unwrap(cls) }
} }
override fun getDelegate(): Any { override fun getDelegate(): Any {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") return restrictDatabaseOperationFromEntityManager("getDelegate", serviceHub) { delegate.delegate }
} }
override fun getMetamodel(): Metamodel? { override fun getMetamodel(): Metamodel? {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") return restrictDatabaseOperationFromEntityManager("getMetamodel", serviceHub) { delegate.metamodel }
} }
override fun joinTransaction() { override fun joinTransaction() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("joinTransaction", serviceHub) { delegate.joinTransaction() }
} }
override fun lock(entity: Any?, lockMode: LockModeType?) { override fun lock(entity: Any?, lockMode: LockModeType?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("lock", serviceHub) { delegate.lock(entity, lockMode) }
} }
override fun lock(entity: Any?, lockMode: LockModeType?, properties: MutableMap<String, Any>?) { override fun lock(entity: Any?, lockMode: LockModeType?, properties: MutableMap<String, Any>?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("lock", serviceHub) { delegate.lock(entity, lockMode, properties) }
} }
override fun setProperty(propertyName: String?, value: Any?) { override fun setProperty(propertyName: String?, value: Any?) {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("lock", serviceHub) { delegate.setProperty(propertyName, value) }
} }
} }
class RestrictedEntityTransaction(private val delegate: EntityTransaction) : EntityTransaction by delegate { class RestrictedEntityTransaction(
private val delegate: EntityTransaction,
private val serviceHub: ServiceHub
) : EntityTransaction by delegate {
override fun rollback() { override fun rollback() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("EntityTransaction.rollback", serviceHub) { delegate.rollback() }
} }
override fun commit() { override fun commit() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("EntityTransaction.commit", serviceHub) { delegate.commit() }
} }
override fun begin() { override fun begin() {
throw UnsupportedOperationException("This method cannot be called via ServiceHub.withEntityManager.") restrictDatabaseOperationFromEntityManager("EntityTransaction.begin", serviceHub) { delegate.begin() }
} }
} }

View File

@ -1,104 +1,337 @@
package net.corda.nodeapi.internal.persistence package net.corda.nodeapi.internal.persistence
import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.cordapp.Cordapp
import net.corda.core.cordapp.CordappContext
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.node.ServiceHub
import org.junit.Test import org.junit.Test
import java.sql.Connection import java.sql.Connection
import java.sql.Savepoint import java.sql.Savepoint
class RestrictedConnectionTest { class RestrictedConnectionTest {
private val connection : Connection = mock() private val connection: Connection = mock()
private val savePoint : Savepoint = mock() private val savePoint: Savepoint = mock()
private val restrictedConnection : RestrictedConnection = RestrictedConnection(connection) private val cordapp = mock<Cordapp>()
private val cordappContext = CordappContext.create(cordapp, null, javaClass.classLoader, mock())
private val serviceHub = mock<ServiceHub>().apply {
whenever(getAppContext()).thenReturn(cordappContext)
}
private val restrictedConnection: RestrictedConnection = RestrictedConnection(connection, serviceHub)
companion object { companion object {
private const val TEST_STRING : String = "test" private const val TEST_STRING: String = "test"
private const val TEST_INT : Int = 1 private const val TEST_INT: Int = 1
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testAbort() { fun `abort with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.abort { println("I'm just an executor for this test...") } restrictedConnection.abort { println("I'm just an executor for this test...") }
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testClearWarnings() { fun `clearWarnings with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.clearWarnings() restrictedConnection.clearWarnings()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testClose() { fun `close with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.close() restrictedConnection.close()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testCommit() { fun `commit with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.commit() restrictedConnection.commit()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetSavepoint() { fun `setSavepoint with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.setSavepoint() restrictedConnection.setSavepoint()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetSavepointWithName() { fun `setSavepoint with name with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.setSavepoint(TEST_STRING) restrictedConnection.setSavepoint(TEST_STRING)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testReleaseSavepoint() { fun `releaseSavepoint with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.releaseSavepoint(savePoint) restrictedConnection.releaseSavepoint(savePoint)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testRollback() { fun `rollback with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.rollback() restrictedConnection.rollback()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testRollbackWithSavepoint() { fun `rollbackWithSavepoint with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.rollback(savePoint) restrictedConnection.rollback(savePoint)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetCatalog() { fun `setCatalog with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.catalog = TEST_STRING restrictedConnection.catalog = TEST_STRING
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetTransactionIsolation() { fun `setTransactionIsolation with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.transactionIsolation = TEST_INT restrictedConnection.transactionIsolation = TEST_INT
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetTypeMap() { fun `setTypeMap with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
val map: MutableMap<String, Class<*>> = mutableMapOf() val map: MutableMap<String, Class<*>> = mutableMapOf()
restrictedConnection.typeMap = map restrictedConnection.typeMap = map
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetHoldability() { fun `setHoldability with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.holdability = TEST_INT restrictedConnection.holdability = TEST_INT
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetSchema() { fun `setSchema with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.schema = TEST_STRING restrictedConnection.schema = TEST_STRING
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetNetworkTimeout() { fun `setNetworkTimeout with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT) restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetAutoCommit() { fun `setAutoCommit with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.autoCommit = true restrictedConnection.autoCommit = true
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetReadOnly() { fun `setReadOnly with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedConnection.isReadOnly = true
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `abort with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.abort { println("I'm just an executor for this test...") }
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `clearWarnings with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.clearWarnings()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `close with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.close()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `commit with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.commit()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setSavepoint with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.setSavepoint()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setSavepoint with name with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.setSavepoint(TEST_STRING)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `releaseSavepoint with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.releaseSavepoint(savePoint)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `rollback with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.rollback()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `rollbackWithSavepoint with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.rollback(savePoint)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setCatalog with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.catalog = TEST_STRING
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setTransactionIsolation with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.transactionIsolation = TEST_INT
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setTypeMap with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
val map: MutableMap<String, Class<*>> = mutableMapOf()
restrictedConnection.typeMap = map
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setHoldability with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.holdability = TEST_INT
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setSchema with target platform version of current 7 unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.schema = TEST_STRING
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setNetworkTimeout with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setAutoCommit with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.autoCommit = true
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setReadOnly with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedConnection.isReadOnly = true
}
@Test(timeout = 300_000)
fun `abort with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.abort { println("I'm just an executor for this test...") }
}
@Test(timeout = 300_000)
fun `clearWarnings with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.clearWarnings()
}
@Test(timeout = 300_000)
fun `close with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.close()
}
@Test(timeout = 300_000)
fun `commit with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.commit()
}
@Test(timeout = 300_000)
fun `setSavepoint with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.setSavepoint()
}
@Test(timeout = 300_000)
fun `setSavepoint with name with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.setSavepoint(TEST_STRING)
}
@Test(timeout = 300_000)
fun `releaseSavepoint with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.releaseSavepoint(savePoint)
}
@Test(timeout = 300_000)
fun `rollback with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.rollback()
}
@Test(timeout = 300_000)
fun `rollbackWithSavepoint with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.rollback(savePoint)
}
@Test(timeout = 300_000)
fun `setCatalog with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.catalog = TEST_STRING
}
@Test(timeout = 300_000)
fun `setTransactionIsolation with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.transactionIsolation = TEST_INT
}
@Test(timeout = 300_000)
fun `setTypeMap with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
val map: MutableMap<String, Class<*>> = mutableMapOf()
restrictedConnection.typeMap = map
}
@Test(timeout = 300_000)
fun `setHoldability with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.holdability = TEST_INT
}
@Test(timeout = 300_000)
fun `setSchema with target platform version of current 6 unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.schema = TEST_STRING
}
@Test(timeout = 300_000)
fun `setNetworkTimeout with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.setNetworkTimeout({ println("I'm just an executor for this test...") }, TEST_INT)
}
@Test(timeout = 300_000)
fun `setAutoCommit with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.autoCommit = true
}
@Test(timeout = 300_000)
fun `setReadOnly with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedConnection.isReadOnly = true restrictedConnection.isReadOnly = true
} }
} }

View File

@ -3,6 +3,10 @@ package net.corda.nodeapi.internal.persistence
import com.nhaarman.mockito_kotlin.doReturn import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.whenever import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.cordapp.Cordapp
import net.corda.core.cordapp.CordappContext
import net.corda.core.internal.PLATFORM_VERSION
import net.corda.core.node.ServiceHub
import org.junit.Test import org.junit.Test
import javax.persistence.EntityManager import javax.persistence.EntityManager
import javax.persistence.EntityTransaction import javax.persistence.EntityTransaction
@ -12,47 +16,160 @@ import kotlin.test.assertTrue
class RestrictedEntityManagerTest { class RestrictedEntityManagerTest {
private val entitymanager = mock<EntityManager>() private val entitymanager = mock<EntityManager>()
private val transaction = mock<EntityTransaction>() private val transaction = mock<EntityTransaction>()
private val restrictedEntityManager = RestrictedEntityManager(entitymanager) private val cordapp = mock<Cordapp>()
private val cordappContext = CordappContext.create(cordapp, null, javaClass.classLoader, mock())
private val serviceHub = mock<ServiceHub>().apply {
whenever(getAppContext()).thenReturn(cordappContext)
}
private val restrictedEntityManager = RestrictedEntityManager(entitymanager, serviceHub)
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testClose() { fun `close with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.close() restrictedEntityManager.close()
} }
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun testClear() { fun `clear with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.clear() restrictedEntityManager.clear()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testGetMetaModel() { fun `getMetaModel with target platform version of current corda version throws unsupported exception`() {
restrictedEntityManager.getMetamodel() whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.metamodel
} }
@Test(timeout = 300_000) @Test(timeout = 300_000)
fun testGetTransaction() { fun `getTransaction with target platform version of current corda version executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
whenever(entitymanager.transaction).doReturn(transaction) whenever(entitymanager.transaction).doReturn(transaction)
assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction) assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testJoinTransaction() { fun `joinTransaction with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.joinTransaction() restrictedEntityManager.joinTransaction()
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testLockWithTwoParameters() { fun `lock with two parameters with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC) restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testLockWithThreeParameters() { fun `lock with three parameters with target platform version of current corda version throws unsupported exception`() {
val map: MutableMap<String,Any> = mutableMapOf() whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC,map) val map: MutableMap<String, Any> = mutableMapOf()
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC, map)
} }
@Test(expected = UnsupportedOperationException::class, timeout=300_000) @Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun testSetProperty() { fun `setProperty with target platform version of current corda version throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(PLATFORM_VERSION)
restrictedEntityManager.setProperty("number", 12)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `close with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.close()
}
@Test(timeout = 300_000)
fun `clear with target platform version of 7 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.clear()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `getMetaModel with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.metamodel
}
@Test(timeout = 300_000)
fun `getTransaction with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
whenever(entitymanager.transaction).doReturn(transaction)
assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `joinTransaction with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.joinTransaction()
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `lock with two parameters with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `lock with three parameters with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
val map: MutableMap<String, Any> = mutableMapOf()
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC, map)
}
@Test(expected = UnsupportedOperationException::class, timeout = 300_000)
fun `setProperty with target platform version of 7 throws unsupported exception`() {
whenever(cordapp.targetPlatformVersion).thenReturn(7)
restrictedEntityManager.setProperty("number", 12)
}
@Test(timeout = 300_000)
fun `close with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.close()
}
@Test(timeout = 300_000)
fun `clear with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.clear()
}
@Test(timeout = 300_000)
fun `getMetaModel with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.metamodel
}
@Test(timeout = 300_000)
fun `getTransaction with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
whenever(entitymanager.transaction).doReturn(transaction)
assertTrue(restrictedEntityManager.transaction is RestrictedEntityTransaction)
}
@Test(timeout = 300_000)
fun `joinTransaction with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.joinTransaction()
}
@Test(timeout = 300_000)
fun `lock with two parameters with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC)
}
@Test(timeout = 300_000)
fun `lock with three parameters with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
val map: MutableMap<String, Any> = mutableMapOf()
restrictedEntityManager.lock(Object(), LockModeType.OPTIMISTIC, map)
}
@Test(timeout = 300_000)
fun `setProperty with target platform version of 6 executes successfully`() {
whenever(cordapp.targetPlatformVersion).thenReturn(6)
restrictedEntityManager.setProperty("number", 12) restrictedEntityManager.setProperty("number", 12)
} }
} }

View File

@ -291,9 +291,11 @@ class ProtonWrapperTests {
@Test(timeout=300_000) @Test(timeout=300_000)
fun `Send a message larger then maxMessageSize from AMQP to Artemis inbox`() { fun `Send a message larger then maxMessageSize from AMQP to Artemis inbox`() {
val maxMessageSize = 100_000 val maxUserPayloadSize = 100_000
val (server, artemisClient) = createArtemisServerAndClient(maxMessageSize) val maxMessageSizeWithHeaders = maxUserPayloadSize + 512 // Adding a small "shim" to account for headers
val amqpClient = createClient(maxMessageSize) // and other non-payload bits of data
val (server, artemisClient) = createArtemisServerAndClient(maxMessageSizeWithHeaders)
val amqpClient = createClient(maxMessageSizeWithHeaders)
val clientConnected = amqpClient.onConnection.toFuture() val clientConnected = amqpClient.onConnection.toFuture()
amqpClient.start() amqpClient.start()
assertEquals(true, clientConnected.get().connected) assertEquals(true, clientConnected.get().connected)
@ -308,7 +310,7 @@ class ProtonWrapperTests {
testProperty["TestProp"] = "1" testProperty["TestProp"] = "1"
// Send normal message. // Send normal message.
val testData = ByteArray(maxMessageSize) val testData = ByteArray(maxUserPayloadSize)
val message = amqpClient.createMessage(testData, sendAddress, CHARLIE_NAME.toString(), testProperty) val message = amqpClient.createMessage(testData, sendAddress, CHARLIE_NAME.toString(), testProperty)
amqpClient.write(message) amqpClient.write(message)
assertEquals(MessageStatus.Acknowledged, message.onComplete.get()) assertEquals(MessageStatus.Acknowledged, message.onComplete.get())
@ -317,7 +319,7 @@ class ProtonWrapperTests {
assertArrayEquals(testData, ByteArray(received.bodySize).apply { received.bodyBuffer.readBytes(this) }) assertArrayEquals(testData, ByteArray(received.bodySize).apply { received.bodyBuffer.readBytes(this) })
// Send message larger than max message size. // Send message larger than max message size.
val largeData = ByteArray(maxMessageSize + 1) val largeData = ByteArray(maxMessageSizeWithHeaders + 1)
// Create message will fail. // Create message will fail.
assertThatThrownBy { assertThatThrownBy {
amqpClient.createMessage(largeData, sendAddress, CHARLIE_NAME.toString(), testProperty) amqpClient.createMessage(largeData, sendAddress, CHARLIE_NAME.toString(), testProperty)

View File

@ -455,7 +455,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
} }
} }
fun clearNetworkMapCache() { open fun clearNetworkMapCache() {
Node.printBasicNodeInfo("Clearing network map cache entries") Node.printBasicNodeInfo("Clearing network map cache entries")
log.info("Starting clearing of network map cache entries...") log.info("Starting clearing of network map cache entries...")
startDatabase() startDatabase()
@ -1157,7 +1157,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
/** /**
* Exposes the database connection as a [RestrictedConnection] to the users. * Exposes the database connection as a [RestrictedConnection] to the users.
*/ */
override fun jdbcSession(): Connection = RestrictedConnection(database.createSession()) override fun jdbcSession(): Connection = RestrictedConnection(database.createSession(), services)
@Suppress("TooGenericExceptionCaught") @Suppress("TooGenericExceptionCaught")
override fun <T : Any?> withEntityManager(block: EntityManager.() -> T): T { override fun <T : Any?> withEntityManager(block: EntityManager.() -> T): T {
@ -1167,7 +1167,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
withSavePoint { savepoint -> withSavePoint { savepoint ->
// Restrict what entity manager they can use inside the block // Restrict what entity manager they can use inside the block
try { try {
block(RestrictedEntityManager(manager)).also { block(RestrictedEntityManager(manager, services)).also {
if (!manager.transaction.rollbackOnly) { if (!manager.transaction.rollbackOnly) {
manager.flush() manager.flush()
} else { } else {

View File

@ -564,6 +564,11 @@ open class Node(configuration: NodeConfiguration,
return super.generateAndSaveNodeInfo() return super.generateAndSaveNodeInfo()
} }
override fun clearNetworkMapCache() {
initialiseSerialization()
super.clearNetworkMapCache()
}
override fun runDatabaseMigrationScripts( override fun runDatabaseMigrationScripts(
updateCoreSchemas: Boolean, updateCoreSchemas: Boolean,
updateAppSchemas: Boolean, updateAppSchemas: Boolean,

View File

@ -455,7 +455,10 @@ open class PersistentNetworkMapCache(cacheFactory: NamedCacheFactory,
database.transaction { database.transaction {
val result = getAllNodeInfos(session) val result = getAllNodeInfos(session)
logger.debug { "Number of node infos to be cleared: ${result.size}" } logger.debug { "Number of node infos to be cleared: ${result.size}" }
for (nodeInfo in result) session.remove(nodeInfo) for (nodeInfo in result) {
session.remove(nodeInfo)
archiveNamedIdentity(session, nodeInfo.toNodeInfo())
}
} }
} }

View File

@ -271,7 +271,7 @@ class NodeVaultService(
// This will cause a failure as we can't deserialize such states in the context of the `appClassloader`. // This will cause a failure as we can't deserialize such states in the context of the `appClassloader`.
// For now we ignore these states. // For now we ignore these states.
// In the future we will use the AttachmentsClassloader to correctly deserialize and asses the relevancy. // In the future we will use the AttachmentsClassloader to correctly deserialize and asses the relevancy.
log.debug { "Could not deserialize state $idx from transaction $txId. Cause: $e" } log.warn("Could not deserialize state $idx from transaction $txId. Cause: $e")
null null
} }
}.toMap() }.toMap()