mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
Merge branch 'release/os/4.3' into vkolomeyko/4.3-merge
# Conflicts: # constants.properties
This commit is contained in:
commit
39828326a9
@ -384,7 +384,7 @@ dependencies {
|
||||
|
||||
// Set to corda compile to ensure it exists now deploy nodes no longer relies on build
|
||||
compile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
compile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
compile project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||
|
||||
// For the buildCordappDependenciesJar task
|
||||
runtime project(':client:jfx')
|
||||
@ -394,7 +394,7 @@ dependencies {
|
||||
runtime project(':confidential-identities')
|
||||
runtime project(':finance:workflows')
|
||||
runtime project(':finance:contracts')
|
||||
runtime project(':webserver')
|
||||
runtime project(':testing:testserver')
|
||||
testCompile project(':test-utils')
|
||||
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.1'
|
||||
}
|
||||
@ -481,8 +481,8 @@ bintrayConfig {
|
||||
'corda-test-utils',
|
||||
'corda-test-db',
|
||||
'corda-jackson',
|
||||
'corda-webserver-impl',
|
||||
'corda-webserver',
|
||||
'corda-testserver-impl',
|
||||
'corda-testserver',
|
||||
'corda-node-driver',
|
||||
'corda-confidential-identities',
|
||||
'corda-shell',
|
||||
|
@ -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.identity.CordaX500Name
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
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.getOrThrow
|
||||
import net.corda.nodeapi.RPCApi
|
||||
import net.corda.nodeapi.RPCApi.CLASS_METHOD_DIVIDER
|
||||
import net.corda.nodeapi.internal.DeduplicationChecker
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQException
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException
|
||||
@ -252,12 +254,13 @@ class RPCClientProxyHandler(
|
||||
throw RPCException("RPC server is not available.")
|
||||
|
||||
val replyId = InvocationId.newInstance()
|
||||
callSiteMap?.set(replyId, CallSite(method.name))
|
||||
val methodFqn = produceMethodFullyQualifiedName(method)
|
||||
callSiteMap?.set(replyId, CallSite(methodFqn))
|
||||
try {
|
||||
val serialisedArguments = (arguments?.toList() ?: emptyList()).serialize(context = serializationContextWithObservableContext)
|
||||
val request = RPCApi.ClientToServer.RpcRequest(
|
||||
clientAddress,
|
||||
method.name,
|
||||
methodFqn,
|
||||
serialisedArguments,
|
||||
replyId,
|
||||
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) {
|
||||
val artemisMessage = producerSession!!.createMessage(false)
|
||||
message.writeToClientMessage(artemisMessage)
|
||||
|
@ -3,7 +3,7 @@
|
||||
# their own projects. So don't get fancy with syntax!
|
||||
|
||||
cordaVersion=4.4-SNAPSHOT
|
||||
gradlePluginsVersion=5.0.2
|
||||
gradlePluginsVersion=5.0.3
|
||||
kotlinVersion=1.2.71
|
||||
java8MinUpdateVersion=171
|
||||
# ***************************************************************#
|
||||
|
@ -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: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$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, 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: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>
|
||||
@ -2135,6 +2137,10 @@
|
||||
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$3</ID>
|
||||
<ID>MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$4</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$1000</ID>
|
||||
<ID>MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000.0</ID>
|
||||
@ -3609,11 +3615,8 @@
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val existingTypes = (commonPredicates[predicateID]!!.expressions[0] as InPredicate<*>).values.map { (it as LiteralExpression).literal }.toSet()</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val externalIdJoin = criteriaBuilder.equal(vaultStates.get<VaultSchemaV1.VaultStates>("stateRef"), entityRoot.get<VaultSchemaV1.StateToExternalId>("compositeKey").get<PersistentStateRef>("stateRef"))</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), entityRoot.get<PersistentStateRef>("stateRef"))</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), vaultFungibleStates.get<PersistentStateRef>("stateRef"))</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), vaultLinearStates.get<PersistentStateRef>("stateRef"))</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val predicateConstraintData = criteriaBuilder.equal(vaultStates.get<Vault.ConstraintInfo>(VaultSchemaV1.VaultStates::constraintData.name), constraint.data())</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val predicateConstraintType = criteriaBuilder.equal(vaultStates.get<Vault.ConstraintInfo>(VaultSchemaV1.VaultStates::constraintType.name), constraint.type())</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val statePartyJoin = criteriaBuilder.equal(vaultStates.get<VaultSchemaV1.VaultStates>("stateRef"), entityRoot.get<VaultSchemaV1.PersistentParty>("compositeKey").get<PersistentStateRef>("stateRef"))</ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val vaultStates: Root<VaultSchemaV1.VaultStates></ID>
|
||||
<ID>MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser${ @Suppress("UNCHECKED_CAST") column as Path<Long?>? val aggregateExpression = when (columnPredicate.type) { AggregateFunctionType.SUM -> criteriaBuilder.sum(column) AggregateFunctionType.AVG -> criteriaBuilder.avg(column) AggregateFunctionType.COUNT -> criteriaBuilder.count(column) AggregateFunctionType.MAX -> criteriaBuilder.max(column) AggregateFunctionType.MIN -> criteriaBuilder.min(column) } //TODO investigate possibility to avoid producing redundant joins in SQL for multiple aggregate functions against the same table aggregateExpressions.add(aggregateExpression) // Some databases may not support aggregate expression in 'group by' clause e.g. 'group by sum(col)', // Hibernate Criteria Builder can't produce alias 'group by col_alias', and the only solution is to use a positional parameter 'group by 1' val orderByColumnPosition = aggregateExpressions.size var shiftLeft = 0 // add optional group by clauses expression.groupByColumns?.let { columns -> val groupByExpressions = columns.map { _column -> val path = root.get<Any?>(getColumnName(_column)) val columnNumberBeforeRemoval = aggregateExpressions.size if (path is SingularAttributePath) //remove the same columns from different joins to match the single column in 'group by' only (from the last join) aggregateExpressions.removeAll { elem -> if (elem is SingularAttributePath) elem.attribute.javaMember == path.attribute.javaMember else false } shiftLeft += columnNumberBeforeRemoval - aggregateExpressions.size //record how many times a duplicated column was removed (from the previous 'parseAggregateFunction' run) aggregateExpressions.add(path) path } criteriaQuery.groupBy(groupByExpressions) } // optionally order by this aggregate function expression.orderBy?.let { val orderCriteria = when (expression.orderBy!!) { // when adding column position of 'group by' shift in case columns were removed Sort.Direction.ASC -> criteriaBuilder.asc(criteriaBuilder.literal<Int>(orderByColumnPosition - shiftLeft)) Sort.Direction.DESC -> criteriaBuilder.desc(criteriaBuilder.literal<Int>(orderByColumnPosition - shiftLeft)) } criteriaQuery.orderBy(orderCriteria) } return aggregateExpression }</ID>
|
||||
<ID>MaxLineLength:HttpApi.kt$HttpApi.Companion$fun fromHostAndPort(hostAndPort: NetworkHostAndPort, base: String, protocol: String = "http", mapper: ObjectMapper = defaultMapper): HttpApi</ID>
|
||||
@ -4513,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$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 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$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>
|
||||
@ -4523,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$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: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$private</ID>
|
||||
<ID>MaxLineLength:RPCServer.kt$RPCServer$producerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE)</ID>
|
||||
@ -5432,7 +5437,7 @@
|
||||
<ID>SpreadOperator:RPCDriver.kt$RandomRpcUser.Companion$(handle.proxy, *arguments.toTypedArray())</ID>
|
||||
<ID>SpreadOperator:RPCOpsWithContext.kt$(cordaRPCOps, *(args ?: arrayOf()))</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:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ErrorInterceptingHandler$(reconnectingRPCConnection.proxy, *(args ?: emptyArray()))</ID>
|
||||
<ID>SpreadOperator:ServiceHub.kt$ServiceHub$(first, *remaining)</ID>
|
||||
@ -5480,7 +5485,7 @@
|
||||
<ID>ThrowsCount:NonValidatingNotaryFlow.kt$NonValidatingNotaryFlow$ private fun checkNotaryWhitelisted(notary: Party, attachedParameterHash: SecureHash?)</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: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: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>
|
||||
@ -6659,6 +6664,7 @@
|
||||
<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 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:RPCServer.kt$import net.corda.core.utilities.*</ID>
|
||||
<ID>WildcardImport:RPCServer.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
||||
|
@ -53,11 +53,11 @@ For example: with cordapp-example (IOU app) the following commands would be run:
|
||||
./gradlew deployNodes
|
||||
./kotlin-source/build/nodes/runnodes
|
||||
|
||||
Then start the Corda webserver
|
||||
Then start the Corda test webserver
|
||||
|
||||
.. sourcecode:: shell
|
||||
|
||||
find ~/dev/cordapp-example/kotlin-source/ -name corda-webserver.jar -execdir sh -c 'java -jar {} &' \;
|
||||
find ~/dev/cordapp-example/kotlin-source/ -name corda-testserver.jar -execdir sh -c 'java -jar {} &' \;
|
||||
|
||||
You can now interact with your running CorDapp. See the instructions `here <https://docs.corda.net/tutorial-cordapp.html#via-http>`__.
|
||||
|
||||
|
@ -103,7 +103,7 @@ Connect to one of your Corda nodes (make sure this is not the Notary node) using
|
||||
|
||||
Build the yo cordapp sample which you can find here: |os_samples_branch|/yo-cordapp and install it in the cordapp directory.
|
||||
|
||||
Now restart Corda and the Corda webserver using the following commands or restart your Corda VM from the Azure portal:
|
||||
Now restart Corda and the Corda test webserver using the following commands or restart your Corda VM from the Azure portal:
|
||||
|
||||
.. sourcecode:: shell
|
||||
|
||||
|
@ -6,6 +6,8 @@ release, see :doc:`app-upgrade-notes`.
|
||||
|
||||
Unreleased
|
||||
----------
|
||||
* Moved and renamed the testing web server to the ``testing`` subproject. Also renamed the published artifact to ``corda-testserver.jar``.
|
||||
|
||||
* Support for Java 11 (compatibility mode). Please read https://github.com/corda/corda/pull/5356.
|
||||
|
||||
* Updating FinalityFlow with functionality to indicate the appropriate StatesToRecord. This allows the initiating party to record states
|
||||
|
@ -16,7 +16,7 @@ This class allows you to connect to your node via a message queue protocol and p
|
||||
interacting with the node. You make calls on a JVM object as normal, and the marshalling back-and-forth is handled for
|
||||
you.
|
||||
|
||||
.. warning:: The built-in Corda webserver is deprecated and unsuitable for production use. If you want to interact with
|
||||
.. warning:: The built-in Corda test webserver is deprecated and unsuitable for production use. If you want to interact with
|
||||
your node via HTTP, you will need to stand up your own webserver that connects to your node using the
|
||||
`CordaRPCClient`_ class. You can find an example of how to do this using the popular Spring Boot server
|
||||
`here <https://github.com/corda/spring-webserver>`_.
|
||||
|
@ -126,8 +126,6 @@ Here is an overview of the various Corda dependencies:
|
||||
* ``corda-tools-explorer`` - The Node Explorer tool. Do not depend on
|
||||
* ``corda-tools-network-bootstrapper`` - The Network Builder tool. Useful in build scripts
|
||||
* ``corda-tools-shell-cli`` - The Shell CLI tool. Useful in build scripts
|
||||
* ``corda-webserver-impl`` - The Corda webserver fat JAR. Deprecated. Usually only used by build scripts
|
||||
* ``corda-websever`` - The Corda webserver library. Deprecated. Use a standard webserver library such as Spring instead
|
||||
|
||||
Dependencies on other CorDapps
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -308,7 +306,7 @@ Below is a sample CorDapp Gradle dependencies block. When building your own CorD
|
||||
cordaCompile "net.corda:corda-node-api:$corda_release_version"
|
||||
cordaCompile "net.corda:corda-webserver-impl:$corda_release_version"
|
||||
cordaRuntime "net.corda:corda:$corda_release_version"
|
||||
cordaRuntime "net.corda:corda-webserver:$corda_release_version"
|
||||
cordaRuntime "net.corda:corda-testserver:$corda_release_version"
|
||||
testCompile "net.corda:corda-test-utils:$corda_release_version"
|
||||
|
||||
// Corda Plugins: dependent flows and services
|
||||
|
@ -126,7 +126,7 @@ current working directory of the JVM):
|
||||
|
||||
corda/
|
||||
corda.jar
|
||||
corda-webserver.jar
|
||||
corda-testserver.jar
|
||||
explorer/
|
||||
node-explorer.jar
|
||||
cordapps/
|
||||
|
@ -9,7 +9,7 @@ Deploying a node to a server
|
||||
|
||||
Linux: Installing and running Corda as a system service
|
||||
-------------------------------------------------------
|
||||
We recommend creating system services to run a node and the optional webserver. This provides logging and service
|
||||
We recommend creating system services to run a node and the optional test webserver. This provides logging and service
|
||||
handling, and ensures the Corda service is run at boot.
|
||||
|
||||
**Prerequisites**:
|
||||
@ -123,7 +123,7 @@ handling, and ensures the Corda service is run at boot.
|
||||
* ``sudo chown root:root /etc/init/corda.conf``
|
||||
* ``sudo chmod 644 /etc/init/corda.conf``
|
||||
|
||||
.. note:: The Corda webserver provides a simple interface for interacting with your installed CorDapps in a browser.
|
||||
.. note:: The Corda test webserver provides a simple interface for interacting with your installed CorDapps in a browser.
|
||||
Running the webserver is optional.
|
||||
|
||||
10. **SystemD**: Create a ``corda-webserver.service`` file based on the example below and save it in the ``/etc/systemd/system/``
|
||||
|
@ -53,10 +53,10 @@ human readable and machine readable.
|
||||
|
||||
In addition, in-house Corda networks at R3 use the following tools:
|
||||
|
||||
* Standard [DataDog](https://docs.datadoghq.com/guides/overview/) probes are currently used to provide e-mail based
|
||||
alerting for running Corda nodes. [Telegraf](https://github.com/influxdata/telegraf) is used in conjunction with a
|
||||
* Standard [DataDog](https://docs.datadoghq.com/guides/overview/) probes are currently used to provide e-mail based
|
||||
alerting for running Corda nodes. [Telegraf](https://github.com/influxdata/telegraf) is used in conjunction with a
|
||||
[Jolokia agent](https://jolokia.org/agent.html) as a collector to parse emitted metric data and push these to DataDog.
|
||||
* Investigation is underway to evaluate [ELK](https://logz.io/learn/complete-guide-elk-stack/) as a mechanism for parsing,
|
||||
* Investigation is underway to evaluate [ELK](https://logz.io/learn/complete-guide-elk-stack/) as a mechanism for parsing,
|
||||
indexing, storing, searching, and visualising log file data.
|
||||
|
||||
## Scope
|
||||
@ -121,15 +121,15 @@ design, either directly or through an integrated enterprise-wide systems managem
|
||||
- Validate liveness and correctness of Corda nodes and deployed CorDapps, and the physical machine or VM they are hosted on.
|
||||
|
||||
* Use logging to troubleshoot operational failures (in conjunction with other supporting failure information: eg. GC logs, stack traces)
|
||||
* Use reported metrics to fine-tune and tweak operational systems parameters (including dynamic setting of logging
|
||||
* Use reported metrics to fine-tune and tweak operational systems parameters (including dynamic setting of logging
|
||||
modules and severity levels to enable detailed logging).
|
||||
|
||||
## Design Decisions
|
||||
|
||||
The following design decisions are to be confirmed:
|
||||
|
||||
1. JMX for metric eventing and SLF4J for logging
|
||||
Both above are widely adopted mechanisms that enable pluggability and seamless interoperability with other 3rd party
|
||||
1. JMX for metric eventing and SLF4J for logging
|
||||
Both above are widely adopted mechanisms that enable pluggability and seamless interoperability with other 3rd party
|
||||
enterprise-wide system management solutions.
|
||||
2. Continue or discontinue usage of Jolokia? (TBC - most likely yes, subject to read-only security lock-down)
|
||||
3. Separation of Corda Node and CorDapp log outputs (TBC)
|
||||
@ -138,54 +138,54 @@ The following design decisions are to be confirmed:
|
||||
|
||||
There are a number of activities and parts to the solution proposal:
|
||||
|
||||
1. Extend JMX metric reporting through the Corda Monitoring Service and associated jolokia conversion to REST/JSON)
|
||||
coverage (see implementation details) to include all Corda services (vault, key management, transaction storage,
|
||||
1. Extend JMX metric reporting through the Corda Monitoring Service and associated jolokia conversion to REST/JSON)
|
||||
coverage (see implementation details) to include all Corda services (vault, key management, transaction storage,
|
||||
network map, attachment storage, identity, cordapp provision) & sub-sytems components (state machine)
|
||||
|
||||
2. Review and extend Corda log4j2 coverage (see implementation details) to ensure
|
||||
|
||||
- consistent use of severities according to situation
|
||||
- consistent coverage across all modules and libraries
|
||||
- consistent output format with all relevant contextual information (node identity, user/execution identity, flow
|
||||
- consistent output format with all relevant contextual information (node identity, user/execution identity, flow
|
||||
session identity, version information)
|
||||
- separation of Corda Node and CorDapp log outputs (TBC)
|
||||
For consistent interleaving reasons, it may be desirable to continue using combined log output.
|
||||
|
||||
Publication of a *code style guide* to define when to use different severity levels.
|
||||
|
||||
3. Implement a CorDapp to perform sanity checking of flow framework, fundamental corda services (vault, identity), and
|
||||
3. Implement a CorDapp to perform sanity checking of flow framework, fundamental corda services (vault, identity), and
|
||||
dependent middleware infrastructure (message broker, database).
|
||||
|
||||
4. Revisit and enhance as necessary the [Audit service API]( https://github.com/corda/corda/pull/620 ), and provide a
|
||||
4. Revisit and enhance as necessary the [Audit service API]( https://github.com/corda/corda/pull/620 ), and provide a
|
||||
persistent backed implementation, to include:
|
||||
|
||||
- specification of Business Event Categories (eg. User authentication and authorisation, Flow-based triggering, Corda
|
||||
- specification of Business Event Categories (eg. User authentication and authorisation, Flow-based triggering, Corda
|
||||
Service invocations, Oracle invocations, Flow-based send/receive calls, RPC invocations)
|
||||
- auto-enabled with Progress Tracker as Business Event generator
|
||||
- RDBMS backed persistent store (independent of Corda database), with adequate security controls (authenticated access
|
||||
- RDBMS backed persistent store (independent of Corda database), with adequate security controls (authenticated access
|
||||
and read-only permissioning). Captured information should be consistent with standard logging, and it may be desirable
|
||||
to define auditable loggers within log4j2 to automatically redirect certain types of log events to the audit service.
|
||||
to define auditable loggers within log4j2 to automatically redirect certain types of log events to the audit service.
|
||||
|
||||
5. Ensure 3rd party middleware drivers (JDBC for database, MQ for messaging) and the JVM are correctly configured to export
|
||||
JMX metrics. Ensure the [JVM Hotspot VM command-line parameters](https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/clopts001.html)
|
||||
are tuned correctly to enable detailed troubleshooting upon failure. Many of these metrics are already automatically
|
||||
exposed to 3rd party profiling tools such as Yourkit.
|
||||
5. Ensure 3rd party middleware drivers (JDBC for database, MQ for messaging) and the JVM are correctly configured to export
|
||||
JMX metrics. Ensure the [JVM Hotspot VM command-line parameters](https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/clopts001.html)
|
||||
are tuned correctly to enable detailed troubleshooting upon failure. Many of these metrics are already automatically
|
||||
exposed to 3rd party profiling tools such as Yourkit.
|
||||
|
||||
Apache Artemis has a comprehensive [management API](https://activemq.apache.org/artemis/docs/latest/management.html)
|
||||
that allows a user to modify a server configuration, create new resources (e.g. addresses and queues), inspect these
|
||||
resources (e.g. how many messages are currently held in a queue) and interact with it (e.g. to remove messages from a
|
||||
queue), and exposes key metrics using JMX (using role-based authentication using Artemis's JAAS plug-in support to
|
||||
Apache Artemis has a comprehensive [management API](https://activemq.apache.org/artemis/docs/latest/management.html)
|
||||
that allows a user to modify a server configuration, create new resources (e.g. addresses and queues), inspect these
|
||||
resources (e.g. how many messages are currently held in a queue) and interact with it (e.g. to remove messages from a
|
||||
queue), and exposes key metrics using JMX (using role-based authentication using Artemis's JAAS plug-in support to
|
||||
ensure Artemis cannot be controlled via JMX)..
|
||||
|
||||
### Restrictions
|
||||
|
||||
As of Corda M11, Java serialisation in the Corda node has been restricted, meaning MBeans access via the JMX port will no longer work.
|
||||
|
||||
Usage of Jolokia requires bundling an associated *jolokia-agent-war* file on the classpath, and associated configuration
|
||||
to export JMX monitoring statistics and data over the Jolokia REST/JSON interface. An associated *jolokia-access.xml*
|
||||
Usage of Jolokia requires bundling an associated *jolokia-agent-war* file on the classpath, and associated configuration
|
||||
to export JMX monitoring statistics and data over the Jolokia REST/JSON interface. An associated *jolokia-access.xml*
|
||||
configuration file defines role based permissioning to HTTP operations.
|
||||
|
||||
## Complementary solutions
|
||||
## Complementary solutions
|
||||
|
||||
A number of 3rd party libraries and frameworks have been proposed which solve different parts of the end to end
|
||||
solution, albeit with most focusing on the Agent Collector (eg. collect metrics from systems then output them to some
|
||||
@ -207,7 +207,7 @@ include:
|
||||
|
||||
Most of the above solutions are not within the scope of this design proposal, but should be capable of ingesting the outputs (logging and metrics) defined by this design.
|
||||
|
||||
## Technical design
|
||||
## Technical design
|
||||
|
||||
In general, the requirements outlined in this design are cross-cutting concerns which affect the Corda codebase holistically, both for logging and capture/export of JMX metrics.
|
||||
|
||||
@ -238,7 +238,7 @@ In general, the requirements outlined in this design are cross-cutting concerns
|
||||
|
||||
#### Health Checker
|
||||
|
||||
The Health checker is a CorDapp which verifies the health and liveliness of the Corda node it is deployed and running within by performing the following activities:
|
||||
The Health checker is a CorDapp which verifies the health and liveliness of the Corda node it is deployed and running within by performing the following activities:
|
||||
|
||||
1. Corda network and middleware infrastructure connectivity checking:
|
||||
|
||||
@ -263,7 +263,7 @@ The Health checker is a CorDapp which verifies the health and liveliness of the
|
||||
4. RPC triggering
|
||||
Autotriggering of above flow using RPC to exercise the following:
|
||||
|
||||
- messaging subsystem verification (RPC queuing)
|
||||
- messaging subsystem verification (RPC queuing)
|
||||
- authenticaton and permissions checking (against underlying configuration)
|
||||
|
||||
|
||||
@ -272,12 +272,12 @@ The Health checker may be deployed as part of a Corda distribution and automatic
|
||||
Please note that the Health checker application is not responsible for determining the healthiness of a Corda Network. This is the responsibility of the network operator, and may include verification checks such as:
|
||||
|
||||
- correct functioning of Network Map Service (registration, discovery)
|
||||
- correct functioning of configured Notary
|
||||
- correct functioning of configured Notary
|
||||
- remote messaging sub-sytem (including bridge creation)
|
||||
|
||||
#### Metrics augmentation within Corda Subsystems and Components
|
||||
|
||||
*Codahale* provides the following types of reportable metrics:
|
||||
*Codahale* provides the following types of reportable metrics:
|
||||
|
||||
- Gauge: is an instantaneous measurement of a value.
|
||||
- Counter: is a gauge for a numeric value (specifically of type `AtomicLong`) which can be incremented or decremented.
|
||||
@ -288,7 +288,7 @@ Please note that the Health checker application is not responsible for determini
|
||||
|
||||
See Appendix B for summary of current JMX Metrics exported by the Corda codebase.
|
||||
|
||||
The following table identifies additional metrics to report for a Corda node:
|
||||
The following table identifies additional metrics to report for a Corda node:
|
||||
|
||||
| Component / Subsystem | Proposed Metric(s) |
|
||||
| ---------------------------------------- | ---------------------------------------- |
|
||||
@ -333,7 +333,7 @@ A *logging style guide* will be published to answer questions such as what sever
|
||||
|
||||
- A connection to a remote peer is unexpectedly terminated.
|
||||
- A database connection timed out but was successfully re-established.
|
||||
- A message was sent to a peer.
|
||||
- A message was sent to a peer.
|
||||
|
||||
It is also important that we capture the correct amount of contextual information to enable rapid identification and resolution of issues using log file output. Specifically, within Corda we should include the following information in logged messages:
|
||||
|
||||
@ -342,7 +342,7 @@ It is also important that we capture the correct amount of contextual informatio
|
||||
- Flow id (runId, also referred to as `StateMachineRunId`), if logging within a flow
|
||||
- Other contextual Flow information (eg. counterparty), if logging within a flow
|
||||
- `FlowStackSnapshot` information for catastrophic flow failures.
|
||||
Note: this information is not currently supposed to be used in production (???).
|
||||
Note: this information is not currently supposed to be used in production (???).
|
||||
- Session id information for RPC calls
|
||||
- CorDapp name, if logging from within a CorDapp
|
||||
|
||||
@ -406,10 +406,6 @@ The following metrics are exposed directly by a Corda Node at run-time:
|
||||
| Module | Metric | Desccription |
|
||||
| ------------------------ | ---------------------------- | ---------------------------------------- |
|
||||
| Attachment Service | Attachments | Counts number of attachments persisted in database. |
|
||||
| Verification Service | VerificationsInFlight | Gauge of number of in flight verifications handled by the out of process verification service. |
|
||||
| Verification Service | Verification.Duration | Timer |
|
||||
| Verification Service | Verification.Success | Count |
|
||||
| Verification Service | Verification.Failure | Count |
|
||||
| RAFT Uniqueness Provider | RaftCluster.ThisServerStatus | Gauge |
|
||||
| RAFT Uniqueness Provider | RaftCluster.MembersCount | Count |
|
||||
| RAFT Uniqueness Provider | RaftCluster.Members | Gauge, containing a list of members (by server address) |
|
||||
@ -417,7 +413,6 @@ The following metrics are exposed directly by a Corda Node at run-time:
|
||||
| State Machine Manager | Flows.CheckpointingRate | Meter |
|
||||
| State Machine Manager | Flows.Started | Count |
|
||||
| State Machine Manager | Flows.Finished | Count |
|
||||
| Flow State Machine | FlowDuration | Timer |
|
||||
|
||||
Additionally, JMX metrics are also generated within the Corda *node-driver* performance testing utilities. Specifically, the `startPublishingFixedRateInjector` defines and exposes `QueueSize` and `WorkDuration` metrics.
|
||||
|
||||
@ -536,4 +531,3 @@ The following table summarised the types of metrics associated with Message Queu
|
||||
| messageCountDelta | *overall* number of messages added/removed from the queue *since the last message counter update*. Positive value indicated more messages were added, negative vice versa. |
|
||||
| lastAddTimestamp | timestamp of the last time a message was added to the queue |
|
||||
| updateTimestamp | timestamp of the last message counter update |
|
||||
|
||||
|
@ -40,7 +40,7 @@ dependencies {
|
||||
compile project(':core')
|
||||
compile project(':client:jfx')
|
||||
compile project(':node-driver')
|
||||
compile project(':webserver')
|
||||
compile project(':testing:testserver')
|
||||
|
||||
testCompile project(':test-utils')
|
||||
|
||||
@ -51,7 +51,7 @@ dependencies {
|
||||
}
|
||||
|
||||
cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||
|
||||
// CorDapps: dependent flows and services
|
||||
compile project(':finance:contracts')
|
||||
|
@ -55,7 +55,7 @@ Since the CorDapp models a car dealership network, a state must be created to re
|
||||
|
||||
It's important to specify what classes are required in each state, contract, and flow. This process must be repeated with each file as it is created.
|
||||
|
||||
5. Update ``@BelongsToContract(TemplateContract:class)`` to specify ``CarContract::class``.
|
||||
5. Update ``@BelongsToContract(TemplateContract::class)`` to specify ``CarContract::class``.
|
||||
|
||||
6. Add the following fields to the state:
|
||||
* ``owningBank`` of type ``Party``
|
||||
|
@ -75,6 +75,8 @@ object RPCApi {
|
||||
|
||||
const val DEDUPLICATION_SEQUENCE_NUMBER_FIELD_NAME = "deduplication-sequence-number"
|
||||
|
||||
const val CLASS_METHOD_DIVIDER = "#"
|
||||
|
||||
val RPC_CLIENT_BINDING_REMOVAL_FILTER_EXPRESSION =
|
||||
"${ManagementHelper.HDR_NOTIFICATION_TYPE} = '${CoreNotificationType.BINDING_REMOVED.name}' AND " +
|
||||
"${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.
|
||||
*
|
||||
* @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 serialisedArguments Serialised arguments to pass to the method, if any.
|
||||
*/
|
||||
|
@ -375,7 +375,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
signedNodeInfo,
|
||||
netParams,
|
||||
keyManagementService,
|
||||
configuration.networkParameterAcceptanceSettings)
|
||||
configuration.networkParameterAcceptanceSettings!!)
|
||||
try {
|
||||
startMessagingService(rpcOps, nodeInfo, myNotaryIdentity, netParams)
|
||||
} catch (e: Exception) {
|
||||
|
@ -81,7 +81,7 @@ interface NodeConfiguration {
|
||||
|
||||
val cordappSignerKeyFingerprintBlacklist: List<String>
|
||||
|
||||
val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings
|
||||
val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings?
|
||||
|
||||
val blacklistedAttachmentSigningKeys: List<String>
|
||||
|
||||
|
@ -75,7 +75,8 @@ data class NodeConfigurationImpl(
|
||||
override val jmxReporterType: JmxReporterType? = Defaults.jmxReporterType,
|
||||
override val flowOverrides: FlowOverrideConfig?,
|
||||
override val cordappSignerKeyFingerprintBlacklist: List<String> = Defaults.cordappSignerKeyFingerprintBlacklist,
|
||||
override val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings = Defaults.networkParameterAcceptanceSettings,
|
||||
override val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings? =
|
||||
Defaults.networkParameterAcceptanceSettings,
|
||||
override val blacklistedAttachmentSigningKeys: List<String> = Defaults.blacklistedAttachmentSigningKeys
|
||||
) : NodeConfiguration {
|
||||
internal object Defaults {
|
||||
|
@ -21,6 +21,7 @@ import net.corda.node.services.config.DevModeOptions
|
||||
import net.corda.node.services.config.FlowOverride
|
||||
import net.corda.node.services.config.FlowOverrideConfig
|
||||
import net.corda.node.services.config.FlowTimeoutConfiguration
|
||||
import net.corda.node.services.config.NetworkParameterAcceptanceSettings
|
||||
import net.corda.node.services.config.NetworkServicesConfig
|
||||
import net.corda.node.services.config.NodeH2Settings
|
||||
import net.corda.node.services.config.NodeRpcSettings
|
||||
@ -143,6 +144,18 @@ internal object NetworkServicesConfigSpec : Configuration.Specification<NetworkS
|
||||
}
|
||||
}
|
||||
|
||||
internal object NetworkParameterAcceptanceSettingsSpec :
|
||||
Configuration.Specification<NetworkParameterAcceptanceSettings>("NetworkParameterAcceptanceSettings") {
|
||||
private val autoAcceptEnabled by boolean().optional().withDefaultValue(true)
|
||||
private val excludedAutoAcceptableParameters by string().listOrEmpty()
|
||||
override fun parseValid(configuration: Config): Valid<NetworkParameterAcceptanceSettings> {
|
||||
return valid(NetworkParameterAcceptanceSettings(configuration[autoAcceptEnabled],
|
||||
configuration[excludedAutoAcceptableParameters].toSet())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
internal object CertChainPolicyConfigSpec : Configuration.Specification<CertChainPolicyConfig>("CertChainPolicyConfig") {
|
||||
private val role by string()
|
||||
|
@ -58,6 +58,9 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
|
||||
private val cordappDirectories by string().mapValid(::toPath).list().optional()
|
||||
private val cordappSignerKeyFingerprintBlacklist by string().list().optional().withDefaultValue(Defaults.cordappSignerKeyFingerprintBlacklist)
|
||||
private val blacklistedAttachmentSigningKeys by string().list().optional().withDefaultValue(Defaults.blacklistedAttachmentSigningKeys)
|
||||
private val networkParameterAcceptanceSettings by nested(NetworkParameterAcceptanceSettingsSpec)
|
||||
.optional()
|
||||
.withDefaultValue(Defaults.networkParameterAcceptanceSettings)
|
||||
@Suppress("unused")
|
||||
private val custom by nestedObject().optional()
|
||||
@Suppress("unused")
|
||||
@ -117,7 +120,8 @@ internal object V1NodeConfigurationSpec : Configuration.Specification<NodeConfig
|
||||
jarDirs = configuration[jarDirs],
|
||||
cordappDirectories = cordappDirectories.map { baseDirectoryPath.resolve(it) },
|
||||
cordappSignerKeyFingerprintBlacklist = configuration[cordappSignerKeyFingerprintBlacklist],
|
||||
blacklistedAttachmentSigningKeys = configuration[blacklistedAttachmentSigningKeys]
|
||||
blacklistedAttachmentSigningKeys = configuration[blacklistedAttachmentSigningKeys],
|
||||
networkParameterAcceptanceSettings = configuration[networkParameterAcceptanceSettings]
|
||||
))
|
||||
} catch (e: Exception) {
|
||||
return when (e) {
|
||||
|
@ -14,6 +14,7 @@ import net.corda.core.context.Trace.InvocationId
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.LifeCycle
|
||||
import net.corda.core.internal.NamedCacheFactory
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.serialization.SerializationContext
|
||||
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.services.logging.pushToLoggingContext
|
||||
import net.corda.nodeapi.RPCApi
|
||||
import net.corda.nodeapi.RPCApi.CLASS_METHOD_DIVIDER
|
||||
import net.corda.nodeapi.externalTrace
|
||||
import net.corda.nodeapi.impersonatedActor
|
||||
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
|
||||
* corresponding function in [ops]. During serialisation of the reply (and later observations) the server subscribes to
|
||||
* The [RPCServer] implements the complement of [net.corda.client.rpc.internal.RPCClient]. When an RPC request arrives it dispatches to the
|
||||
* 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
|
||||
* 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(
|
||||
private val ops: RPCOps,
|
||||
private val opsList: List<RPCOps>,
|
||||
private val rpcServerUsername: String,
|
||||
private val rpcServerPassword: String,
|
||||
private val serverLocator: ServerLocator,
|
||||
@ -86,6 +91,8 @@ class RPCServer(
|
||||
) {
|
||||
private companion object {
|
||||
private val log = contextLogger()
|
||||
|
||||
private data class InvocationTarget(val method: Method, val instance: RPCOps)
|
||||
}
|
||||
|
||||
private enum class State {
|
||||
@ -102,8 +109,13 @@ class RPCServer(
|
||||
private data class MessageAndContext(val message: RPCApi.ServerToClient.RpcReply, val context: ObservableContext)
|
||||
|
||||
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. */
|
||||
private val observableMap = createObservableSubscriptionMap()
|
||||
/** A mapping from client addresses to IDs of associated Observables */
|
||||
@ -130,16 +142,47 @@ class RPCServer(
|
||||
private val deduplicationChecker = DeduplicationChecker(rpcConfiguration.deduplicationCacheExpiry, cacheFactory = cacheFactory)
|
||||
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 {
|
||||
val groupedMethods = ops.javaClass.declaredMethods.groupBy { it.name }
|
||||
groupedMethods.forEach { name, methods ->
|
||||
if (methods.size > 1) {
|
||||
throw IllegalArgumentException("Encountered more than one method called $name on ${ops.javaClass.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 ->
|
||||
if (methods.size > 1) {
|
||||
throw IllegalArgumentException("Encountered more than one method called $name on ${interfaceClass.name}")
|
||||
}
|
||||
}
|
||||
val interimMap = groupedMethods.mapValues { InvocationTarget(it.value.single(), ops) }
|
||||
mutableMethodTable.putAll(interimMap)
|
||||
}
|
||||
}
|
||||
methodTable = groupedMethods.mapValues { it.value.single() }
|
||||
|
||||
// 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 {
|
||||
val onObservableRemove = RemovalListener<InvocationId, ObservableSubscription> { key, value, cause ->
|
||||
log.debug { "Unsubscribing from Observable with id $key because of $cause" }
|
||||
@ -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 {
|
||||
try {
|
||||
CURRENT_RPC_CONTEXT.set(context)
|
||||
log.trace { "Calling $methodName" }
|
||||
val method = methodTable[methodName] ?:
|
||||
throw RPCException("Received RPC for unknown method $methodName - possible client/server version skew?")
|
||||
method.invoke(ops, *arguments.toTypedArray())
|
||||
log.trace { "Calling $inMethodName" }
|
||||
val invocationTarget = methodTable[inMethodName] ?:
|
||||
throw RPCException("Received RPC for unknown method $inMethodName - possible client/server version skew?")
|
||||
invocationTarget.method.invoke(invocationTarget.instance, *arguments.toTypedArray())
|
||||
} catch (e: InvocationTargetException) {
|
||||
throw e.cause ?: RPCException("Caught InvocationTargetException without cause")
|
||||
} 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
|
||||
} finally {
|
||||
CURRENT_RPC_CONTEXT.remove()
|
||||
@ -393,7 +436,7 @@ class RPCServer(
|
||||
* we receive a notification that the client queue bindings were added.
|
||||
*/
|
||||
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) {
|
||||
null -> BufferOrNone.Buffer(ArrayList()).apply {
|
||||
container.add(MessageAndContext(message, context))
|
||||
@ -403,7 +446,7 @@ class RPCServer(
|
||||
}
|
||||
is BufferOrNone.None -> value
|
||||
}
|
||||
})
|
||||
}
|
||||
return clientBuffer is BufferOrNone.Buffer
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package net.corda.node.services.statemachine
|
||||
import co.paralleluniverse.fibers.Fiber
|
||||
import co.paralleluniverse.fibers.FiberExecutorScheduler
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import co.paralleluniverse.fibers.instrument.SuspendableHelper
|
||||
import co.paralleluniverse.fibers.instrument.JavaAgent
|
||||
import co.paralleluniverse.strands.channels.Channels
|
||||
import com.codahale.metrics.Gauge
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
@ -307,7 +307,7 @@ class SingleThreadedStateMachineManager(
|
||||
}
|
||||
|
||||
private fun checkQuasarJavaAgentPresence() {
|
||||
check(SuspendableHelper.isJavaAgentActive()) {
|
||||
check(JavaAgent.isActive()) {
|
||||
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
|
||||
#See https://docs.corda.net/head/testing.html#running-tests-in-intellij - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ dependencies {
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||
|
||||
cordapp project(':samples:attachment-demo:contracts')
|
||||
cordapp project(':samples:attachment-demo:workflows')
|
||||
@ -64,7 +64,7 @@ dependencies {
|
||||
|
||||
testCompile "org.assertj:assertj-core:$assertj_version"
|
||||
|
||||
integrationTestCompile project(':webserver')
|
||||
integrationTestCompile project(':testing:testserver')
|
||||
}
|
||||
|
||||
task integrationTest(type: Test, dependsOn: []) {
|
||||
@ -73,7 +73,7 @@ task integrationTest(type: Test, dependsOn: []) {
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':webserver:webcapsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) {
|
||||
ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow",
|
||||
"InvokeRpc.partiesFromName",
|
||||
|
@ -19,11 +19,11 @@ dependencies {
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':client:jfx')
|
||||
cordaCompile project(':client:rpc')
|
||||
cordaCompile (project(':webserver')) {
|
||||
cordaCompile(project(':testing:testserver')) {
|
||||
exclude group: "org.apache.logging.log4j"
|
||||
}
|
||||
cordaCompile (project(':node-driver')) {
|
||||
@ -43,7 +43,7 @@ dependencies {
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':webserver:webcapsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) {
|
||||
nodeDefaults {
|
||||
cordapp project(':finance:workflows')
|
||||
|
@ -16,7 +16,7 @@ dependencies {
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':webserver:webcapsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) {
|
||||
directory file("$buildDir/nodes")
|
||||
nodeDefaults {
|
||||
|
@ -31,7 +31,7 @@ dependencies {
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':webserver:webcapsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
|
||||
task deployNodes(dependsOn: ['deployNodesSingle', 'deployNodesRaft', 'deployNodesBFT', 'deployNodesCustom'])
|
||||
|
||||
|
@ -41,9 +41,9 @@ dependencies {
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaRuntime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaRuntime project(path: ":testing:testserver:testcapsule:", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile (project(':webserver')) {
|
||||
cordaCompile(project(':testing:testserver')) {
|
||||
exclude group: "org.apache.logging.log4j"
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ jar {
|
||||
}
|
||||
|
||||
def nodeTask = tasks.getByPath(':node:capsule:assemble')
|
||||
def webTask = tasks.getByPath(':webserver:webcapsule:assemble')
|
||||
def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble')
|
||||
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) {
|
||||
directory file("$buildDir/nodes")
|
||||
nodeDefaults {
|
||||
|
@ -25,8 +25,8 @@ include 'client:jfx'
|
||||
include 'client:mock'
|
||||
include 'client:rpc'
|
||||
include 'docker'
|
||||
include 'webserver'
|
||||
include 'webserver:webcapsule'
|
||||
include 'testing:testserver'
|
||||
include 'testing:testserver:testcapsule:'
|
||||
include 'experimental'
|
||||
include 'experimental:avalanche'
|
||||
include 'experimental:blobwriter'
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.testing.node.internal
|
||||
|
||||
import co.paralleluniverse.fibers.instrument.JavaAgent
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigFactory
|
||||
@ -54,7 +55,6 @@ import okhttp3.Request
|
||||
import rx.Subscription
|
||||
import rx.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.net.ConnectException
|
||||
import java.net.URL
|
||||
import java.nio.file.Path
|
||||
@ -708,7 +708,7 @@ class DriverDSLImpl(
|
||||
val effectiveP2PAddress = config.corda.messagingServerAddress ?: config.corda.p2pAddress
|
||||
return executorService.fork {
|
||||
log.info("Starting in-process Node ${config.corda.myLegalName.organisation}")
|
||||
if (!(ManagementFactory.getRuntimeMXBean().inputArguments.any { it.contains("quasar") })) {
|
||||
if (!JavaAgent.isActive()) {
|
||||
throw IllegalStateException("No quasar agent: -javaagent:lib/quasar.jar and working directory project root might fix")
|
||||
}
|
||||
// Write node.conf
|
||||
|
@ -303,15 +303,6 @@ data class RPCDriverDSL(
|
||||
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(
|
||||
serverName: String = "driver-rpc-server-${random63BitValue()}",
|
||||
rpcUser: User = rpcTestUser,
|
||||
@ -321,9 +312,29 @@ data class RPCDriverDSL(
|
||||
configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT,
|
||||
customPort: NetworkHostAndPort? = null,
|
||||
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> {
|
||||
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,
|
||||
brokerHandle: RpcBrokerHandle,
|
||||
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 {
|
||||
val locator = ActiveMQClient.createServerLocatorWithoutHA(brokerHandle.clientTransportConfiguration).apply {
|
||||
minLargeMessageSize = MAX_MESSAGE_SIZE
|
||||
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(
|
||||
ops,
|
||||
listOps,
|
||||
rpcUser.username,
|
||||
rpcUser.password,
|
||||
locator,
|
||||
|
@ -76,7 +76,7 @@ task integrationTest(type: Test) {
|
||||
}
|
||||
|
||||
jar {
|
||||
baseName 'corda-webserver-impl'
|
||||
baseName 'corda-testserver-impl'
|
||||
}
|
||||
|
||||
publish {
|
@ -26,12 +26,12 @@ capsule {
|
||||
|
||||
task buildWebserverJar(type: FatCapsule, dependsOn: project(':node').tasks.jar) {
|
||||
applicationClass 'net.corda.webserver.WebServer'
|
||||
archiveName "corda-webserver-${corda_release_version}.jar"
|
||||
archiveName "corda-testserver-${corda_release_version}.jar"
|
||||
applicationSource = files(
|
||||
project(':webserver').configurations.runtimeClasspath,
|
||||
project(':webserver').tasks.jar,
|
||||
project(':webserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet.class',
|
||||
project(':webserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet$1.class',
|
||||
project(':testing:testserver').configurations.runtimeClasspath,
|
||||
project(':testing:testserver').tasks.jar,
|
||||
project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet.class',
|
||||
project(':testing:testserver').sourceSets.main.java.outputDir.toString() + '/CordaWebserverCaplet$1.class',
|
||||
project(':node').buildDir.toString() + '/resources/main/reference.conf',
|
||||
"$rootDir/config/dev/log4j2.xml",
|
||||
project(':node:capsule').projectDir.toString() + '/NOTICE' // Copy CDDL notice
|
||||
@ -66,5 +66,5 @@ artifacts {
|
||||
|
||||
publish {
|
||||
disableDefaultJar = true
|
||||
name 'corda-webserver'
|
||||
name 'corda-testserver'
|
||||
}
|
@ -31,7 +31,7 @@ apply plugin: 'kotlin'
|
||||
apply plugin: 'application'
|
||||
|
||||
evaluationDependsOn(':tools:explorer:capsule')
|
||||
evaluationDependsOn(':webserver:webcapsule')
|
||||
evaluationDependsOn(':testing:testserver:testcapsule:')
|
||||
|
||||
mainClassName = 'net.corda.demobench.DemoBench'
|
||||
applicationDefaultJvmArgs = [
|
||||
@ -85,7 +85,7 @@ dependencies {
|
||||
compile ':purejavacomm-0.0.18'
|
||||
|
||||
testCompile project(':test-utils')
|
||||
testCompile project(':webserver')
|
||||
testCompile project(':testing:testserver')
|
||||
|
||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junit_platform_version}"
|
||||
@ -139,8 +139,8 @@ distributions {
|
||||
into 'corda'
|
||||
fileMode = 0444
|
||||
}
|
||||
from(project(':webserver:webcapsule').tasks.buildWebserverJar) {
|
||||
rename 'corda-webserver-(.*)', 'corda-webserver.jar'
|
||||
from(project(':testing:testserver:testcapsule:').tasks.buildWebserverJar) {
|
||||
rename 'corda-testserver-(.*)', 'corda-testserver.jar'
|
||||
into 'corda'
|
||||
fileMode = 0444
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import tornadofx.*
|
||||
|
||||
class WebServerController : Controller() {
|
||||
private val jvm by inject<JVMConfig>()
|
||||
private val webserverPath = jvm.applicationDir.resolve("corda").resolve("corda-webserver.jar")
|
||||
private val webserverPath = jvm.applicationDir.resolve("corda").resolve("corda-testserver.jar")
|
||||
|
||||
init {
|
||||
log.info("Web Server JAR: $webserverPath")
|
||||
|
Loading…
Reference in New Issue
Block a user