mirror of
https://github.com/corda/corda.git
synced 2025-04-29 07:20:13 +00:00
CORDA-3232: Support of multiple interfaces for RPC calls (#5495)
* CORDA-3232: Make backward compatible RPC client changes Such that it will be able to talk to new and old server versions. * CORDA-3232: Make backward compatible RPC server changes Such that it will be able to talk to new and old client versions. * CORDA-3232: Trick Detekt * CORDA-3232: Integration test for multi-interface communication. * CORDA-3232: Add legacy mode test. * CORDA-3232: Making Detekt happier * CORDA-3232: Fix Detekt baseline after merge with `4.3` branch * CORDA-3232: Incrementing Platform version As discussed with @lockathan * CORDA-3232: Fix legacy test post platform version increment * CORDA-3232: Use recursive logic to establish complete population of method names * Revert "CORDA-3232: Incrementing Platform version" This reverts commit d75f48aa * CORDA-3232: Remove logic that conditions on PLATFORM_VERSION * CORDA-3232: Making Detekt happier * CORDA-3232: Few more changes after conversation with @mnesbit * CORDA-3232: Make a strict match to `CordaRPCOps` on client side Or else will fail: net.corda.tools.shell.InteractiveShellIntegrationTest.dumpCheckpoints creates zip with json file for suspended flow Flagging that `InternalCordaRPCOps.dumpCheckpoints` cannot be called. * CORDA-3232: Address PR comments by @rick-r3 * CORDA-3232: Address further review input from @rick-r3 * Change the way how methods stored in the map; * Extend test to make sure that `CordaRPCOps` can indeed be mixed with other RPC interfaces.
This commit is contained in:
parent
298d8ba69c
commit
51330c2e44
@ -0,0 +1,91 @@
|
|||||||
|
package net.corda.client.rpc
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import net.corda.client.rpc.RPCMultipleInterfacesTests.StringRPCOpsImpl.testPhrase
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
|
import net.corda.core.messaging.RPCOps
|
||||||
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.node.internal.rpcDriver
|
||||||
|
import net.corda.testing.node.internal.startRpcClient
|
||||||
|
import org.assertj.core.api.Assertions
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import rx.Observable
|
||||||
|
|
||||||
|
class RPCMultipleInterfacesTests {
|
||||||
|
@Rule
|
||||||
|
@JvmField
|
||||||
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val sampleSize = 30
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IntRPCOps : RPCOps {
|
||||||
|
fun stream(size: Int): Observable<Int>
|
||||||
|
|
||||||
|
fun intTestMethod(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StringRPCOps : RPCOps {
|
||||||
|
fun stream(size: Int): Observable<String>
|
||||||
|
|
||||||
|
fun stringTestMethod() : String
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IntRPCOpsImpl : IntRPCOps {
|
||||||
|
override val protocolVersion = 1000
|
||||||
|
|
||||||
|
override fun stream(size: Int): Observable<Int> {
|
||||||
|
return Observable.range(0, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intTestMethod(): Int = protocolVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
private object StringRPCOpsImpl : StringRPCOps {
|
||||||
|
|
||||||
|
const val testPhrase = "I work with Strings."
|
||||||
|
|
||||||
|
override val protocolVersion = 1000
|
||||||
|
|
||||||
|
override fun stream(size: Int): Observable<String> {
|
||||||
|
return Observable.range(0, size).map { it.toString(8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stringTestMethod(): String = testPhrase
|
||||||
|
}
|
||||||
|
|
||||||
|
private object MyCordaRpcOpsImpl : CordaRPCOps by mock() {
|
||||||
|
override val protocolVersion = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImaginaryFriend : RPCOps
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `can talk multiple interfaces`() {
|
||||||
|
rpcDriver {
|
||||||
|
val server = startRpcServer(listOps = listOf(IntRPCOpsImpl(), StringRPCOpsImpl, MyCordaRpcOpsImpl)).get()
|
||||||
|
|
||||||
|
val clientInt = startRpcClient<IntRPCOps>(server.broker.hostAndPort!!).get()
|
||||||
|
val intList = clientInt.stream(sampleSize).toList().toBlocking().single()
|
||||||
|
assertEquals(sampleSize, intList.size)
|
||||||
|
|
||||||
|
val clientString = startRpcClient<StringRPCOps>(server.broker.hostAndPort!!).get()
|
||||||
|
val stringList = clientString.stream(sampleSize).toList().toBlocking().single()
|
||||||
|
assertEquals(sampleSize, stringList.size)
|
||||||
|
assertTrue(stringList.toString(), stringList.all { it.matches("[0-7]*".toRegex()) })
|
||||||
|
assertEquals(testPhrase, clientString.stringTestMethod())
|
||||||
|
|
||||||
|
val rpcOpsClient = startRpcClient<CordaRPCOps>(server.broker.hostAndPort!!).get()
|
||||||
|
assertFalse(rpcOpsClient.attachmentExists(SecureHash.zeroHash))
|
||||||
|
|
||||||
|
Assertions.assertThatThrownBy { startRpcClient<ImaginaryFriend>(server.broker.hostAndPort!!).get() }
|
||||||
|
.hasCauseInstanceOf(RPCException::class.java).hasMessageContaining("possible client/server version skew")
|
||||||
|
|
||||||
|
server.rpcServer.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ import net.corda.core.context.Trace
|
|||||||
import net.corda.core.context.Trace.InvocationId
|
import net.corda.core.context.Trace.InvocationId
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
@ -25,6 +26,7 @@ import net.corda.core.utilities.contextLogger
|
|||||||
import net.corda.core.utilities.debug
|
import net.corda.core.utilities.debug
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.nodeapi.RPCApi
|
import net.corda.nodeapi.RPCApi
|
||||||
|
import net.corda.nodeapi.RPCApi.CLASS_METHOD_DIVIDER
|
||||||
import net.corda.nodeapi.internal.DeduplicationChecker
|
import net.corda.nodeapi.internal.DeduplicationChecker
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQException
|
import org.apache.activemq.artemis.api.core.ActiveMQException
|
||||||
import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException
|
import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException
|
||||||
@ -252,12 +254,13 @@ class RPCClientProxyHandler(
|
|||||||
throw RPCException("RPC server is not available.")
|
throw RPCException("RPC server is not available.")
|
||||||
|
|
||||||
val replyId = InvocationId.newInstance()
|
val replyId = InvocationId.newInstance()
|
||||||
callSiteMap?.set(replyId, CallSite(method.name))
|
val methodFqn = produceMethodFullyQualifiedName(method)
|
||||||
|
callSiteMap?.set(replyId, CallSite(methodFqn))
|
||||||
try {
|
try {
|
||||||
val serialisedArguments = (arguments?.toList() ?: emptyList()).serialize(context = serializationContextWithObservableContext)
|
val serialisedArguments = (arguments?.toList() ?: emptyList()).serialize(context = serializationContextWithObservableContext)
|
||||||
val request = RPCApi.ClientToServer.RpcRequest(
|
val request = RPCApi.ClientToServer.RpcRequest(
|
||||||
clientAddress,
|
clientAddress,
|
||||||
method.name,
|
methodFqn,
|
||||||
serialisedArguments,
|
serialisedArguments,
|
||||||
replyId,
|
replyId,
|
||||||
sessionId,
|
sessionId,
|
||||||
@ -282,6 +285,15 @@ class RPCClientProxyHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun produceMethodFullyQualifiedName(method: Method) : String {
|
||||||
|
// For CordaRPCOps send method only - for backwards compatibility
|
||||||
|
return if (CordaRPCOps::class.java == rpcOpsClass) {
|
||||||
|
method.name
|
||||||
|
} else {
|
||||||
|
rpcOpsClass.name + CLASS_METHOD_DIVIDER + method.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun sendMessage(message: RPCApi.ClientToServer) {
|
private fun sendMessage(message: RPCApi.ClientToServer) {
|
||||||
val artemisMessage = producerSession!!.createMessage(false)
|
val artemisMessage = producerSession!!.createMessage(false)
|
||||||
message.writeToClientMessage(artemisMessage)
|
message.writeToClientMessage(artemisMessage)
|
||||||
|
@ -872,8 +872,10 @@
|
|||||||
<ID>LongParameterList:QueryCriteria.kt$QueryCriteria.VaultQueryCriteria$( status: Vault.StateStatus = this.status, contractStateTypes: Set<Class<out ContractState>>? = this.contractStateTypes, stateRefs: List<StateRef>? = this.stateRefs, notary: List<AbstractParty>? = this.notary, softLockingCondition: SoftLockingCondition? = this.softLockingCondition, timeCondition: TimeCondition? = this.timeCondition )</ID>
|
<ID>LongParameterList:QueryCriteria.kt$QueryCriteria.VaultQueryCriteria$( status: Vault.StateStatus = this.status, contractStateTypes: Set<Class<out ContractState>>? = this.contractStateTypes, stateRefs: List<StateRef>? = this.stateRefs, notary: List<AbstractParty>? = this.notary, softLockingCondition: SoftLockingCondition? = this.softLockingCondition, timeCondition: TimeCondition? = this.timeCondition )</ID>
|
||||||
<ID>LongParameterList:RPCClient.kt$RPCClient$( rpcOpsClass: Class<I>, username: String, password: String, externalTrace: Trace? = null, impersonatedActor: Actor? = null, targetLegalIdentity: CordaX500Name? = null )</ID>
|
<ID>LongParameterList:RPCClient.kt$RPCClient$( rpcOpsClass: Class<I>, username: String, password: String, externalTrace: Trace? = null, impersonatedActor: Actor? = null, targetLegalIdentity: CordaX500Name? = null )</ID>
|
||||||
<ID>LongParameterList:RPCDriver.kt$( isDebug: Boolean = false, driverDirectory: Path = Paths.get("build") / "rpc-driver" / getTimestampAsDirectoryName(), portAllocation: PortAllocation = globalPortAllocation, debugPortAllocation: PortAllocation = globalDebugPortAllocation, systemProperties: Map<String, String> = emptyMap(), useTestClock: Boolean = false, startNodesInProcess: Boolean = false, waitForNodesToFinish: Boolean = false, extraCordappPackagesToScan: List<String> = emptyList(), notarySpecs: List<NotarySpec> = emptyList(), externalTrace: Trace? = null, @Suppress("DEPRECATION") jmxPolicy: JmxPolicy = JmxPolicy(), networkParameters: NetworkParameters = testNetworkParameters(), notaryCustomOverrides: Map<String, Any?> = emptyMap(), inMemoryDB: Boolean = true, cordappsForAllNodes: Collection<TestCordappInternal>? = null, dsl: RPCDriverDSL.() -> A )</ID>
|
<ID>LongParameterList:RPCDriver.kt$( isDebug: Boolean = false, driverDirectory: Path = Paths.get("build") / "rpc-driver" / getTimestampAsDirectoryName(), portAllocation: PortAllocation = globalPortAllocation, debugPortAllocation: PortAllocation = globalDebugPortAllocation, systemProperties: Map<String, String> = emptyMap(), useTestClock: Boolean = false, startNodesInProcess: Boolean = false, waitForNodesToFinish: Boolean = false, extraCordappPackagesToScan: List<String> = emptyList(), notarySpecs: List<NotarySpec> = emptyList(), externalTrace: Trace? = null, @Suppress("DEPRECATION") jmxPolicy: JmxPolicy = JmxPolicy(), networkParameters: NetworkParameters = testNetworkParameters(), notaryCustomOverrides: Map<String, Any?> = emptyMap(), inMemoryDB: Boolean = true, cordappsForAllNodes: Collection<TestCordappInternal>? = null, dsl: RPCDriverDSL.() -> A )</ID>
|
||||||
|
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, listOps: List<I>, brokerHandle: RpcBrokerHandle, queueDrainTimeout: Duration = 5.seconds )</ID>
|
||||||
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, ops: I, brokerHandle: RpcBrokerHandle, queueDrainTimeout: Duration = 5.seconds )</ID>
|
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, ops: I, brokerHandle: RpcBrokerHandle, queueDrainTimeout: Duration = 5.seconds )</ID>
|
||||||
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = MAX_MESSAGE_SIZE, maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, ops: I, queueDrainTimeout: Duration = 5.seconds )</ID>
|
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = MAX_MESSAGE_SIZE, maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, ops: I, queueDrainTimeout: Duration = 5.seconds )</ID>
|
||||||
|
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( serverName: String = "driver-rpc-server-${random63BitValue()}", rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = MAX_MESSAGE_SIZE, maxBufferedBytesPerClient: Long = 5L * MAX_MESSAGE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, customPort: NetworkHostAndPort? = null, listOps: List<I> )</ID>
|
||||||
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( serverName: String = "driver-rpc-server-${random63BitValue()}", rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = MAX_MESSAGE_SIZE, maxBufferedBytesPerClient: Long = 5L * MAX_MESSAGE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, customPort: NetworkHostAndPort? = null, ops: I )</ID>
|
<ID>LongParameterList:RPCDriver.kt$RPCDriverDSL$( serverName: String = "driver-rpc-server-${random63BitValue()}", rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, maxFileSize: Int = MAX_MESSAGE_SIZE, maxBufferedBytesPerClient: Long = 5L * MAX_MESSAGE_SIZE, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, customPort: NetworkHostAndPort? = null, ops: I )</ID>
|
||||||
<ID>LongParameterList:RpcBrokerConfiguration.kt$RpcBrokerConfiguration$(name: String, send: Boolean = false, consume: Boolean = false, createDurableQueue: Boolean = false, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false)</ID>
|
<ID>LongParameterList:RpcBrokerConfiguration.kt$RpcBrokerConfiguration$(name: String, send: Boolean = false, consume: Boolean = false, createDurableQueue: Boolean = false, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false)</ID>
|
||||||
<ID>LongParameterList:SerializationEnvironment.kt$SerializationEnvironment.Companion$( serializationFactory: SerializationFactory, p2pContext: SerializationContext, rpcServerContext: SerializationContext? = null, rpcClientContext: SerializationContext? = null, storageContext: SerializationContext? = null, checkpointContext: CheckpointSerializationContext? = null, checkpointSerializer: CheckpointSerializer? = null )</ID>
|
<ID>LongParameterList:SerializationEnvironment.kt$SerializationEnvironment.Companion$( serializationFactory: SerializationFactory, p2pContext: SerializationContext, rpcServerContext: SerializationContext? = null, rpcClientContext: SerializationContext? = null, storageContext: SerializationContext? = null, checkpointContext: CheckpointSerializationContext? = null, checkpointSerializer: CheckpointSerializer? = null )</ID>
|
||||||
@ -2135,6 +2137,10 @@
|
|||||||
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$3</ID>
|
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$3</ID>
|
||||||
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$4</ID>
|
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$4</ID>
|
||||||
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests.TestOpsImpl$1000</ID>
|
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests.TestOpsImpl$1000</ID>
|
||||||
|
<ID>MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.IntRPCOpsImpl$1000</ID>
|
||||||
|
<ID>MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.MyCordaRpcOpsImpl$1000</ID>
|
||||||
|
<ID>MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.StringRPCOpsImpl$1000</ID>
|
||||||
|
<ID>MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.StringRPCOpsImpl$8</ID>
|
||||||
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$100</ID>
|
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$100</ID>
|
||||||
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000</ID>
|
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000</ID>
|
||||||
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000.0</ID>
|
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000.0</ID>
|
||||||
@ -4510,7 +4516,6 @@
|
|||||||
<ID>MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$return cacheFactory.buildNamed(Caffeine.newBuilder().weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()), "RpcClientProxyHandler_rpcObservable")</ID>
|
<ID>MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$return cacheFactory.buildNamed(Caffeine.newBuilder().weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()), "RpcClientProxyHandler_rpcObservable")</ID>
|
||||||
<ID>MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$throw UnsupportedOperationException("Method $calledMethod was added in RPC protocol version $sinceVersion but the server is running $serverProtocolVersion")</ID>
|
<ID>MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$throw UnsupportedOperationException("Method $calledMethod was added in RPC protocol version $sinceVersion but the server is running $serverProtocolVersion")</ID>
|
||||||
<ID>MaxLineLength:RPCDriver.kt$RPCDriverDSL$val artemisConfig = createRpcServerArtemisConfig(maxFileSize, maxBufferedBytesPerClient, driverDSL.driverDirectory / serverName, hostAndPort)</ID>
|
<ID>MaxLineLength:RPCDriver.kt$RPCDriverDSL$val artemisConfig = createRpcServerArtemisConfig(maxFileSize, maxBufferedBytesPerClient, driverDSL.driverDirectory / serverName, hostAndPort)</ID>
|
||||||
<ID>MaxLineLength:RPCDriver.kt$RPCDriverDSL$val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username, rpcUser.password, rpcUser.permissions)), id = AuthServiceId("TEST_SECURITY_MANAGER"))</ID>
|
|
||||||
<ID>MaxLineLength:RPCDriver.kt$RPCDriverDSL.Companion$fun createRpcServerArtemisConfig(maxFileSize: Int, maxBufferedBytesPerClient: Long, baseDirectory: Path, hostAndPort: NetworkHostAndPort): Configuration</ID>
|
<ID>MaxLineLength:RPCDriver.kt$RPCDriverDSL.Companion$fun createRpcServerArtemisConfig(maxFileSize: Int, maxBufferedBytesPerClient: Long, baseDirectory: Path, hostAndPort: NetworkHostAndPort): Configuration</ID>
|
||||||
<ID>MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$private inline fun <reified T> HashMap<Class<*>, Generator<*>>.add(generator: Generator<T>)</ID>
|
<ID>MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$private inline fun <reified T> HashMap<Class<*>, Generator<*>>.add(generator: Generator<T>)</ID>
|
||||||
<ID>MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$val handle = RPCClient<RPCOps>(hostAndPort, null, serializationContext = AMQP_RPC_CLIENT_CONTEXT).start(rpcClass, username, password)</ID>
|
<ID>MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$val handle = RPCClient<RPCOps>(hostAndPort, null, serializationContext = AMQP_RPC_CLIENT_CONTEXT).start(rpcClass, username, password)</ID>
|
||||||
@ -4520,6 +4525,9 @@
|
|||||||
<ID>MaxLineLength:RPCOpsWithContext.kt$fun makeRPCOps(getCordaRPCOps: (username: String, credential: String) -> InternalCordaRPCOps, username: String, credential: String): InternalCordaRPCOps</ID>
|
<ID>MaxLineLength:RPCOpsWithContext.kt$fun makeRPCOps(getCordaRPCOps: (username: String, credential: String) -> InternalCordaRPCOps, username: String, credential: String): InternalCordaRPCOps</ID>
|
||||||
<ID>MaxLineLength:RPCOpsWithContext.kt$return Proxy.newProxyInstance(InternalCordaRPCOps::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java)) { _, method, args -> try { method.invoke(cordaRPCOps, *(args ?: arrayOf())) } catch (e: InvocationTargetException) { // Unpack exception. throw e.targetException } } as InternalCordaRPCOps</ID>
|
<ID>MaxLineLength:RPCOpsWithContext.kt$return Proxy.newProxyInstance(InternalCordaRPCOps::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java)) { _, method, args -> try { method.invoke(cordaRPCOps, *(args ?: arrayOf())) } catch (e: InvocationTargetException) { // Unpack exception. throw e.targetException } } as InternalCordaRPCOps</ID>
|
||||||
<ID>MaxLineLength:RPCSecurityManagerWithAdditionalUser.kt$RPCSecurityManagerWithAdditionalUser : RPCSecurityManager</ID>
|
<ID>MaxLineLength:RPCSecurityManagerWithAdditionalUser.kt$RPCSecurityManagerWithAdditionalUser : RPCSecurityManager</ID>
|
||||||
|
<ID>MaxLineLength:RPCServer.kt$RPCServer</ID>
|
||||||
|
<ID>MaxLineLength:RPCServer.kt$RPCServer$( ops: RPCOps, rpcServerUsername: String, rpcServerPassword: String, serverLocator: ServerLocator, securityManager: RPCSecurityManager, nodeLegalName: CordaX500Name, rpcConfiguration: RPCServerConfiguration, cacheFactory: NamedCacheFactory )</ID>
|
||||||
|
<ID>MaxLineLength:RPCServer.kt$RPCServer$/** * The method name -> InvocationTarget used for servicing the actual call. * NB: The key in this map can either be: * - FQN of the method including interface name for all the interfaces except `CordaRPCOps`; * - For `CordaRPCOps` interface this will be just plain method name. This is done to maintain wire compatibility with previous versions. */ private val methodTable: Map<String, InvocationTarget></ID>
|
||||||
<ID>MaxLineLength:RPCServer.kt$RPCServer$consumerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)</ID>
|
<ID>MaxLineLength:RPCServer.kt$RPCServer$consumerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)</ID>
|
||||||
<ID>MaxLineLength:RPCServer.kt$RPCServer$private</ID>
|
<ID>MaxLineLength:RPCServer.kt$RPCServer$private</ID>
|
||||||
<ID>MaxLineLength:RPCServer.kt$RPCServer$producerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)</ID>
|
<ID>MaxLineLength:RPCServer.kt$RPCServer$producerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)</ID>
|
||||||
@ -5429,7 +5437,7 @@
|
|||||||
<ID>SpreadOperator:RPCDriver.kt$RandomRpcUser.Companion$(handle.proxy, *arguments.toTypedArray())</ID>
|
<ID>SpreadOperator:RPCDriver.kt$RandomRpcUser.Companion$(handle.proxy, *arguments.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:RPCOpsWithContext.kt$(cordaRPCOps, *(args ?: arrayOf()))</ID>
|
<ID>SpreadOperator:RPCOpsWithContext.kt$(cordaRPCOps, *(args ?: arrayOf()))</ID>
|
||||||
<ID>SpreadOperator:RPCSecurityManagerTest.kt$RPCSecurityManagerTest$(request.first(), *args)</ID>
|
<ID>SpreadOperator:RPCSecurityManagerTest.kt$RPCSecurityManagerTest$(request.first(), *args)</ID>
|
||||||
<ID>SpreadOperator:RPCServer.kt$RPCServer$(ops, *arguments.toTypedArray())</ID>
|
<ID>SpreadOperator:RPCServer.kt$RPCServer$(invocationTarget.instance, *arguments.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:ReactiveArtemisConsumer.kt$ReactiveArtemisConsumer.Companion$(queueName, *queueNames)</ID>
|
<ID>SpreadOperator:ReactiveArtemisConsumer.kt$ReactiveArtemisConsumer.Companion$(queueName, *queueNames)</ID>
|
||||||
<ID>SpreadOperator:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ErrorInterceptingHandler$(reconnectingRPCConnection.proxy, *(args ?: emptyArray()))</ID>
|
<ID>SpreadOperator:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ErrorInterceptingHandler$(reconnectingRPCConnection.proxy, *(args ?: emptyArray()))</ID>
|
||||||
<ID>SpreadOperator:ServiceHub.kt$ServiceHub$(first, *remaining)</ID>
|
<ID>SpreadOperator:ServiceHub.kt$ServiceHub$(first, *remaining)</ID>
|
||||||
@ -5477,7 +5485,7 @@
|
|||||||
<ID>ThrowsCount:NonValidatingNotaryFlow.kt$NonValidatingNotaryFlow$ private fun checkNotaryWhitelisted(notary: Party, attachedParameterHash: SecureHash?)</ID>
|
<ID>ThrowsCount:NonValidatingNotaryFlow.kt$NonValidatingNotaryFlow$ private fun checkNotaryWhitelisted(notary: Party, attachedParameterHash: SecureHash?)</ID>
|
||||||
<ID>ThrowsCount:PropertyDescriptor.kt$PropertyDescriptor$ fun validate()</ID>
|
<ID>ThrowsCount:PropertyDescriptor.kt$PropertyDescriptor$ fun validate()</ID>
|
||||||
<ID>ThrowsCount:RPCApi.kt$RPCApi.ServerToClient.Companion$fun fromClientMessage(context: SerializationContext, message: ClientMessage): ServerToClient</ID>
|
<ID>ThrowsCount:RPCApi.kt$RPCApi.ServerToClient.Companion$fun fromClientMessage(context: SerializationContext, message: ClientMessage): ServerToClient</ID>
|
||||||
<ID>ThrowsCount:RPCServer.kt$RPCServer$private fun invokeRpc(context: RpcAuthContext, methodName: String, arguments: List<Any?>): Try<Any></ID>
|
<ID>ThrowsCount:RPCServer.kt$RPCServer$private fun invokeRpc(context: RpcAuthContext, inMethodName: String, arguments: List<Any?>): Try<Any></ID>
|
||||||
<ID>ThrowsCount:SchemaMigration.kt$SchemaMigration$private fun doRunMigration(run: Boolean, check: Boolean, existingCheckpoints: Boolean? = null)</ID>
|
<ID>ThrowsCount:SchemaMigration.kt$SchemaMigration$private fun doRunMigration(run: Boolean, check: Boolean, existingCheckpoints: Boolean? = null)</ID>
|
||||||
<ID>ThrowsCount:ServicesForResolutionImpl.kt$ServicesForResolutionImpl$// We may need to recursively chase transactions if there are notary changes. fun inner(stateRef: StateRef, forContractClassName: String?): Attachment</ID>
|
<ID>ThrowsCount:ServicesForResolutionImpl.kt$ServicesForResolutionImpl$// We may need to recursively chase transactions if there are notary changes. fun inner(stateRef: StateRef, forContractClassName: String?): Attachment</ID>
|
||||||
<ID>ThrowsCount:SignedNodeInfo.kt$SignedNodeInfo$// TODO Add root cert param (or TrustAnchor) to make sure all the identities belong to the same root fun verified(): NodeInfo</ID>
|
<ID>ThrowsCount:SignedNodeInfo.kt$SignedNodeInfo$// TODO Add root cert param (or TrustAnchor) to make sure all the identities belong to the same root fun verified(): NodeInfo</ID>
|
||||||
@ -6656,6 +6664,7 @@
|
|||||||
<ID>WildcardImport:QueryCriteriaUtils.kt$import net.corda.core.node.services.vault.LikenessOperator.*</ID>
|
<ID>WildcardImport:QueryCriteriaUtils.kt$import net.corda.core.node.services.vault.LikenessOperator.*</ID>
|
||||||
<ID>WildcardImport:RPCClientProxyHandler.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:RPCClientProxyHandler.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:RPCClientProxyHandler.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
<ID>WildcardImport:RPCClientProxyHandler.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
||||||
|
<ID>WildcardImport:RPCMultipleInterfacesTests.kt$import org.junit.Assert.*</ID>
|
||||||
<ID>WildcardImport:RPCSecurityManagerImpl.kt$import org.apache.shiro.authc.*</ID>
|
<ID>WildcardImport:RPCSecurityManagerImpl.kt$import org.apache.shiro.authc.*</ID>
|
||||||
<ID>WildcardImport:RPCServer.kt$import net.corda.core.utilities.*</ID>
|
<ID>WildcardImport:RPCServer.kt$import net.corda.core.utilities.*</ID>
|
||||||
<ID>WildcardImport:RPCServer.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
<ID>WildcardImport:RPCServer.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
||||||
|
@ -75,6 +75,8 @@ object RPCApi {
|
|||||||
|
|
||||||
const val DEDUPLICATION_SEQUENCE_NUMBER_FIELD_NAME = "deduplication-sequence-number"
|
const val DEDUPLICATION_SEQUENCE_NUMBER_FIELD_NAME = "deduplication-sequence-number"
|
||||||
|
|
||||||
|
const val CLASS_METHOD_DIVIDER = "#"
|
||||||
|
|
||||||
val RPC_CLIENT_BINDING_REMOVAL_FILTER_EXPRESSION =
|
val RPC_CLIENT_BINDING_REMOVAL_FILTER_EXPRESSION =
|
||||||
"${ManagementHelper.HDR_NOTIFICATION_TYPE} = '${CoreNotificationType.BINDING_REMOVED.name}' AND " +
|
"${ManagementHelper.HDR_NOTIFICATION_TYPE} = '${CoreNotificationType.BINDING_REMOVED.name}' AND " +
|
||||||
"${ManagementHelper.HDR_ROUTING_NAME} LIKE '$RPC_CLIENT_QUEUE_NAME_PREFIX.%'"
|
"${ManagementHelper.HDR_ROUTING_NAME} LIKE '$RPC_CLIENT_QUEUE_NAME_PREFIX.%'"
|
||||||
@ -103,7 +105,7 @@ object RPCApi {
|
|||||||
* Request to a server to trigger the specified method with the provided arguments.
|
* Request to a server to trigger the specified method with the provided arguments.
|
||||||
*
|
*
|
||||||
* @param clientAddress return address to contact the client at.
|
* @param clientAddress return address to contact the client at.
|
||||||
* @param id a unique ID for the request, which the server will use to identify its response with.
|
* @param replyId a unique ID for the request, which the server will use to identify its response with.
|
||||||
* @param methodName name of the method (procedure) to be called.
|
* @param methodName name of the method (procedure) to be called.
|
||||||
* @param serialisedArguments Serialised arguments to pass to the method, if any.
|
* @param serialisedArguments Serialised arguments to pass to the method, if any.
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +14,7 @@ import net.corda.core.context.Trace.InvocationId
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.LifeCycle
|
import net.corda.core.internal.LifeCycle
|
||||||
import net.corda.core.internal.NamedCacheFactory
|
import net.corda.core.internal.NamedCacheFactory
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.RPCOps
|
import net.corda.core.messaging.RPCOps
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
import net.corda.core.serialization.SerializationDefaults
|
||||||
@ -25,6 +26,7 @@ import net.corda.node.internal.security.RPCSecurityManager
|
|||||||
import net.corda.node.serialization.amqp.RpcServerObservableSerializer
|
import net.corda.node.serialization.amqp.RpcServerObservableSerializer
|
||||||
import net.corda.node.services.logging.pushToLoggingContext
|
import net.corda.node.services.logging.pushToLoggingContext
|
||||||
import net.corda.nodeapi.RPCApi
|
import net.corda.nodeapi.RPCApi
|
||||||
|
import net.corda.nodeapi.RPCApi.CLASS_METHOD_DIVIDER
|
||||||
import net.corda.nodeapi.externalTrace
|
import net.corda.nodeapi.externalTrace
|
||||||
import net.corda.nodeapi.impersonatedActor
|
import net.corda.nodeapi.impersonatedActor
|
||||||
import net.corda.nodeapi.internal.DeduplicationChecker
|
import net.corda.nodeapi.internal.DeduplicationChecker
|
||||||
@ -67,15 +69,18 @@ data class RPCServerConfiguration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [RPCServer] implements the complement of [RPCClient]. When an RPC request arrives it dispatches to the
|
* The [RPCServer] implements the complement of [net.corda.client.rpc.internal.RPCClient]. When an RPC request arrives it dispatches to the
|
||||||
* corresponding function in [ops]. During serialisation of the reply (and later observations) the server subscribes to
|
* corresponding function in [opsList]. During serialisation of the reply (and later observations) the server subscribes to
|
||||||
* each Observable it encounters and captures the client address to associate with these Observables. Later it uses this
|
* each Observable it encounters and captures the client address to associate with these Observables. Later it uses this
|
||||||
* address to forward observations arriving on the Observables.
|
* address to forward observations arriving on the Observables.
|
||||||
*
|
*
|
||||||
* The way this is done is similar to that in [RPCClient], we use Kryo and add a context to stores the subscription map.
|
* The way this is done is similar to that in [net.corda.client.rpc.internal.RPCClient], we use AMQP and add a context to stores the subscription map.
|
||||||
|
*
|
||||||
|
* NB: The order of elements in [opsList] matters in case of legacy RPC clients who do not specify class name of the RPC Ops they are after.
|
||||||
|
* For Legacy RPC clients who supply method name alone, the calls are being targeted at first element in [opsList].
|
||||||
*/
|
*/
|
||||||
class RPCServer(
|
class RPCServer(
|
||||||
private val ops: RPCOps,
|
private val opsList: List<RPCOps>,
|
||||||
private val rpcServerUsername: String,
|
private val rpcServerUsername: String,
|
||||||
private val rpcServerPassword: String,
|
private val rpcServerPassword: String,
|
||||||
private val serverLocator: ServerLocator,
|
private val serverLocator: ServerLocator,
|
||||||
@ -86,6 +91,8 @@ class RPCServer(
|
|||||||
) {
|
) {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val log = contextLogger()
|
private val log = contextLogger()
|
||||||
|
|
||||||
|
private data class InvocationTarget(val method: Method, val instance: RPCOps)
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class State {
|
private enum class State {
|
||||||
@ -102,8 +109,13 @@ class RPCServer(
|
|||||||
private data class MessageAndContext(val message: RPCApi.ServerToClient.RpcReply, val context: ObservableContext)
|
private data class MessageAndContext(val message: RPCApi.ServerToClient.RpcReply, val context: ObservableContext)
|
||||||
|
|
||||||
private val lifeCycle = LifeCycle(State.UNSTARTED)
|
private val lifeCycle = LifeCycle(State.UNSTARTED)
|
||||||
/** The methodname->Method map to use for dispatching. */
|
/**
|
||||||
private val methodTable: Map<String, Method>
|
* The method name -> InvocationTarget used for servicing the actual call.
|
||||||
|
* NB: The key in this map can either be:
|
||||||
|
* - FQN of the method including interface name for all the interfaces except `CordaRPCOps`;
|
||||||
|
* - For `CordaRPCOps` interface this will be just plain method name. This is done to maintain wire compatibility with previous versions.
|
||||||
|
*/
|
||||||
|
private val methodTable: Map<String, InvocationTarget>
|
||||||
/** The observable subscription mapping. */
|
/** The observable subscription mapping. */
|
||||||
private val observableMap = createObservableSubscriptionMap()
|
private val observableMap = createObservableSubscriptionMap()
|
||||||
/** A mapping from client addresses to IDs of associated Observables */
|
/** A mapping from client addresses to IDs of associated Observables */
|
||||||
@ -130,14 +142,45 @@ class RPCServer(
|
|||||||
private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry, cacheFactory = cacheFactory)
|
private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry, cacheFactory = cacheFactory)
|
||||||
private var deduplicationIdentity: String? = null
|
private var deduplicationIdentity: String? = null
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
ops: RPCOps,
|
||||||
|
rpcServerUsername: String,
|
||||||
|
rpcServerPassword: String,
|
||||||
|
serverLocator: ServerLocator,
|
||||||
|
securityManager: RPCSecurityManager,
|
||||||
|
nodeLegalName: CordaX500Name,
|
||||||
|
rpcConfiguration: RPCServerConfiguration,
|
||||||
|
cacheFactory: NamedCacheFactory
|
||||||
|
) : this(listOf(ops), rpcServerUsername, rpcServerPassword, serverLocator, securityManager, nodeLegalName, rpcConfiguration, cacheFactory)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val groupedMethods = ops.javaClass.declaredMethods.groupBy { it.name }
|
val mutableMethodTable = mutableMapOf<String, InvocationTarget>()
|
||||||
|
opsList.forEach { ops ->
|
||||||
|
listOfApplicableInterfacesRec(ops.javaClass).toSet().forEach { interfaceClass ->
|
||||||
|
val groupedMethods = with(interfaceClass) {
|
||||||
|
if(interfaceClass == CordaRPCOps::class.java) {
|
||||||
|
methods.groupBy { it.name }
|
||||||
|
} else {
|
||||||
|
methods.groupBy { interfaceClass.name + CLASS_METHOD_DIVIDER + it.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
groupedMethods.forEach { name, methods ->
|
groupedMethods.forEach { name, methods ->
|
||||||
if (methods.size > 1) {
|
if (methods.size > 1) {
|
||||||
throw IllegalArgumentException("Encountered more than one method called $name on ${ops.javaClass.name}")
|
throw IllegalArgumentException("Encountered more than one method called $name on ${interfaceClass.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
methodTable = groupedMethods.mapValues { it.value.single() }
|
val interimMap = groupedMethods.mapValues { InvocationTarget(it.value.single(), ops) }
|
||||||
|
mutableMethodTable.putAll(interimMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Going forward it is should be treated as immutable construct.
|
||||||
|
methodTable = mutableMethodTable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listOfApplicableInterfacesRec(clazz: Class<*>): List<Class<*>> =
|
||||||
|
clazz.interfaces.filter { RPCOps::class.java.isAssignableFrom(it) }.flatMap {
|
||||||
|
listOf(it) + listOfApplicableInterfacesRec(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createObservableSubscriptionMap(): ObservableSubscriptionMap {
|
private fun createObservableSubscriptionMap(): ObservableSubscriptionMap {
|
||||||
@ -349,18 +392,18 @@ class RPCServer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun invokeRpc(context: RpcAuthContext, methodName: String, arguments: List<Any?>): Try<Any> {
|
private fun invokeRpc(context: RpcAuthContext, inMethodName: String, arguments: List<Any?>): Try<Any> {
|
||||||
return Try.on {
|
return Try.on {
|
||||||
try {
|
try {
|
||||||
CURRENT_RPC_CONTEXT.set(context)
|
CURRENT_RPC_CONTEXT.set(context)
|
||||||
log.trace { "Calling $methodName" }
|
log.trace { "Calling $inMethodName" }
|
||||||
val method = methodTable[methodName] ?:
|
val invocationTarget = methodTable[inMethodName] ?:
|
||||||
throw RPCException("Received RPC for unknown method $methodName - possible client/server version skew?")
|
throw RPCException("Received RPC for unknown method $inMethodName - possible client/server version skew?")
|
||||||
method.invoke(ops, *arguments.toTypedArray())
|
invocationTarget.method.invoke(invocationTarget.instance, *arguments.toTypedArray())
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
throw e.cause ?: RPCException("Caught InvocationTargetException without cause")
|
throw e.cause ?: RPCException("Caught InvocationTargetException without cause")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.warn("Caught exception attempting to invoke RPC $methodName", e)
|
log.warn("Caught exception attempting to invoke RPC $inMethodName", e)
|
||||||
throw e
|
throw e
|
||||||
} finally {
|
} finally {
|
||||||
CURRENT_RPC_CONTEXT.remove()
|
CURRENT_RPC_CONTEXT.remove()
|
||||||
@ -393,7 +436,7 @@ class RPCServer(
|
|||||||
* we receive a notification that the client queue bindings were added.
|
* we receive a notification that the client queue bindings were added.
|
||||||
*/
|
*/
|
||||||
private fun bufferIfQueueNotBound(clientAddress: SimpleString, message: RPCApi.ServerToClient.RpcReply, context: ObservableContext): Boolean {
|
private fun bufferIfQueueNotBound(clientAddress: SimpleString, message: RPCApi.ServerToClient.RpcReply, context: ObservableContext): Boolean {
|
||||||
val clientBuffer = responseMessageBuffer.compute(clientAddress, { _, value ->
|
val clientBuffer = responseMessageBuffer.compute(clientAddress) { _, value ->
|
||||||
when (value) {
|
when (value) {
|
||||||
null -> BufferOrNone.Buffer(ArrayList()).apply {
|
null -> BufferOrNone.Buffer(ArrayList()).apply {
|
||||||
container.add(MessageAndContext(message, context))
|
container.add(MessageAndContext(message, context))
|
||||||
@ -403,7 +446,7 @@ class RPCServer(
|
|||||||
}
|
}
|
||||||
is BufferOrNone.None -> value
|
is BufferOrNone.None -> value
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
return clientBuffer is BufferOrNone.Buffer
|
return clientBuffer is BufferOrNone.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,15 +303,6 @@ data class RPCDriverDSL(
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a Netty RPC server.
|
|
||||||
*
|
|
||||||
* @param serverName The name of the server, to be used for the folder created for Artemis files.
|
|
||||||
* @param rpcUser The single user who can access the server through RPC, and their permissions.
|
|
||||||
* @param nodeLegalName The legal name of the node to check against to authenticate a super user.
|
|
||||||
* @param configuration The RPC server configuration.
|
|
||||||
* @param ops The server-side implementation of the RPC interface.
|
|
||||||
*/
|
|
||||||
fun <I : RPCOps> startRpcServer(
|
fun <I : RPCOps> startRpcServer(
|
||||||
serverName: String = "driver-rpc-server-${random63BitValue()}",
|
serverName: String = "driver-rpc-server-${random63BitValue()}",
|
||||||
rpcUser: User = rpcTestUser,
|
rpcUser: User = rpcTestUser,
|
||||||
@ -321,9 +312,29 @@ data class RPCDriverDSL(
|
|||||||
configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT,
|
configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT,
|
||||||
customPort: NetworkHostAndPort? = null,
|
customPort: NetworkHostAndPort? = null,
|
||||||
ops: I
|
ops: I
|
||||||
|
) = startRpcServer(serverName, rpcUser, nodeLegalName, maxFileSize, maxBufferedBytesPerClient, configuration, customPort, listOf(ops))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a Netty RPC server.
|
||||||
|
*
|
||||||
|
* @param serverName The name of the server, to be used for the folder created for Artemis files.
|
||||||
|
* @param rpcUser The single user who can access the server through RPC, and their permissions.
|
||||||
|
* @param nodeLegalName The legal name of the node to check against to authenticate a super user.
|
||||||
|
* @param configuration The RPC server configuration.
|
||||||
|
* @param listOps The server-side implementation of the RPC interfaces.
|
||||||
|
*/
|
||||||
|
fun <I : RPCOps> startRpcServer(
|
||||||
|
serverName: String = "driver-rpc-server-${random63BitValue()}",
|
||||||
|
rpcUser: User = rpcTestUser,
|
||||||
|
nodeLegalName: CordaX500Name = fakeNodeLegalName,
|
||||||
|
maxFileSize: Int = MAX_MESSAGE_SIZE,
|
||||||
|
maxBufferedBytesPerClient: Long = 5L * MAX_MESSAGE_SIZE,
|
||||||
|
configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT,
|
||||||
|
customPort: NetworkHostAndPort? = null,
|
||||||
|
listOps: List<I>
|
||||||
): CordaFuture<RpcServerHandle> {
|
): CordaFuture<RpcServerHandle> {
|
||||||
return startRpcBroker(serverName, rpcUser, maxFileSize, maxBufferedBytesPerClient, customPort).map { broker ->
|
return startRpcBroker(serverName, rpcUser, maxFileSize, maxBufferedBytesPerClient, customPort).map { broker ->
|
||||||
startRpcServerWithBrokerRunning(rpcUser, nodeLegalName, configuration, ops, broker)
|
startRpcServerWithBrokerRunning(rpcUser, nodeLegalName, configuration, listOps, broker)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,14 +488,24 @@ data class RPCDriverDSL(
|
|||||||
ops: I,
|
ops: I,
|
||||||
brokerHandle: RpcBrokerHandle,
|
brokerHandle: RpcBrokerHandle,
|
||||||
queueDrainTimeout: Duration = 5.seconds
|
queueDrainTimeout: Duration = 5.seconds
|
||||||
|
) = startRpcServerWithBrokerRunning(rpcUser, nodeLegalName, configuration, listOf(ops), brokerHandle, queueDrainTimeout)
|
||||||
|
|
||||||
|
private fun <I : RPCOps> startRpcServerWithBrokerRunning(
|
||||||
|
rpcUser: User = rpcTestUser,
|
||||||
|
nodeLegalName: CordaX500Name = fakeNodeLegalName,
|
||||||
|
configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT,
|
||||||
|
listOps: List<I>,
|
||||||
|
brokerHandle: RpcBrokerHandle,
|
||||||
|
queueDrainTimeout: Duration = 5.seconds
|
||||||
): RpcServerHandle {
|
): RpcServerHandle {
|
||||||
val locator = ActiveMQClient.createServerLocatorWithoutHA(brokerHandle.clientTransportConfiguration).apply {
|
val locator = ActiveMQClient.createServerLocatorWithoutHA(brokerHandle.clientTransportConfiguration).apply {
|
||||||
minLargeMessageSize = MAX_MESSAGE_SIZE
|
minLargeMessageSize = MAX_MESSAGE_SIZE
|
||||||
isUseGlobalPools = false
|
isUseGlobalPools = false
|
||||||
}
|
}
|
||||||
val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username, rpcUser.password, rpcUser.permissions)), id = AuthServiceId("TEST_SECURITY_MANAGER"))
|
val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username,
|
||||||
|
rpcUser.password, rpcUser.permissions)), id = AuthServiceId("TEST_SECURITY_MANAGER"))
|
||||||
val rpcServer = RPCServer(
|
val rpcServer = RPCServer(
|
||||||
ops,
|
listOps,
|
||||||
rpcUser.username,
|
rpcUser.username,
|
||||||
rpcUser.password,
|
rpcUser.password,
|
||||||
locator,
|
locator,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user