diff --git a/build.gradle b/build.gradle index b7dcc8227b..99e3df0645 100644 --- a/build.gradle +++ b/build.gradle @@ -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', diff --git a/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt new file mode 100644 index 0000000000..407657bfb4 --- /dev/null +++ b/client/rpc/src/integration-test/kotlin/net/corda/client/rpc/RPCMultipleInterfacesTests.kt @@ -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 + + fun intTestMethod(): Int + } + + interface StringRPCOps : RPCOps { + fun stream(size: Int): Observable + + fun stringTestMethod() : String + } + + private class IntRPCOpsImpl : IntRPCOps { + override val protocolVersion = 1000 + + override fun stream(size: Int): Observable { + 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 { + 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(server.broker.hostAndPort!!).get() + val intList = clientInt.stream(sampleSize).toList().toBlocking().single() + assertEquals(sampleSize, intList.size) + + val clientString = startRpcClient(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(server.broker.hostAndPort!!).get() + assertFalse(rpcOpsClient.attachmentExists(SecureHash.zeroHash)) + + Assertions.assertThatThrownBy { startRpcClient(server.broker.hostAndPort!!).get() } + .hasCauseInstanceOf(RPCException::class.java).hasMessageContaining("possible client/server version skew") + + server.rpcServer.close() + } + } +} diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt index 6470cc9525..5e0d3f639e 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt @@ -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) diff --git a/constants.properties b/constants.properties index 5c8fd948dd..ef48b22e4a 100644 --- a/constants.properties +++ b/constants.properties @@ -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 # ***************************************************************# diff --git a/detekt-baseline.xml b/detekt-baseline.xml index d05e9643a5..081bee46e1 100644 --- a/detekt-baseline.xml +++ b/detekt-baseline.xml @@ -872,8 +872,10 @@ 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 ) LongParameterList:RPCClient.kt$RPCClient$( rpcOpsClass: Class<I>, username: String, password: String, externalTrace: Trace? = null, impersonatedActor: Actor? = null, targetLegalIdentity: CordaX500Name? = null ) 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 ) + LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, listOps: List<I>, brokerHandle: RpcBrokerHandle, queueDrainTimeout: Duration = 5.seconds ) LongParameterList:RPCDriver.kt$RPCDriverDSL$( rpcUser: User = rpcTestUser, nodeLegalName: CordaX500Name = fakeNodeLegalName, configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, ops: I, brokerHandle: RpcBrokerHandle, queueDrainTimeout: Duration = 5.seconds ) 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 ) + 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> ) 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 ) 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) LongParameterList:SerializationEnvironment.kt$SerializationEnvironment.Companion$( serializationFactory: SerializationFactory, p2pContext: SerializationContext, rpcServerContext: SerializationContext? = null, rpcClientContext: SerializationContext? = null, storageContext: SerializationContext? = null, checkpointContext: CheckpointSerializationContext? = null, checkpointSerializer: CheckpointSerializer? = null ) @@ -2135,6 +2137,10 @@ MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$3 MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests$4 MagicNumber:RPCHighThroughputObservableTests.kt$RPCHighThroughputObservableTests.TestOpsImpl$1000 + MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.IntRPCOpsImpl$1000 + MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.MyCordaRpcOpsImpl$1000 + MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.StringRPCOpsImpl$1000 + MagicNumber:RPCMultipleInterfacesTests.kt$RPCMultipleInterfacesTests.StringRPCOpsImpl$8 MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$100 MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000 MagicNumber:RPCPerformanceTests.kt$RPCPerformanceTests$1000.0 @@ -3609,11 +3615,8 @@ MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val existingTypes = (commonPredicates[predicateID]!!.expressions[0] as InPredicate<*>).values.map { (it as LiteralExpression).literal }.toSet() MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val externalIdJoin = criteriaBuilder.equal(vaultStates.get<VaultSchemaV1.VaultStates>("stateRef"), entityRoot.get<VaultSchemaV1.StateToExternalId>("compositeKey").get<PersistentStateRef>("stateRef")) MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), entityRoot.get<PersistentStateRef>("stateRef")) - MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), vaultFungibleStates.get<PersistentStateRef>("stateRef")) - MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val joinPredicate = criteriaBuilder.equal(vaultStates.get<PersistentStateRef>("stateRef"), vaultLinearStates.get<PersistentStateRef>("stateRef")) MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val predicateConstraintData = criteriaBuilder.equal(vaultStates.get<Vault.ConstraintInfo>(VaultSchemaV1.VaultStates::constraintData.name), constraint.data()) MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val predicateConstraintType = criteriaBuilder.equal(vaultStates.get<Vault.ConstraintInfo>(VaultSchemaV1.VaultStates::constraintType.name), constraint.type()) - MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val statePartyJoin = criteriaBuilder.equal(vaultStates.get<VaultSchemaV1.VaultStates>("stateRef"), entityRoot.get<VaultSchemaV1.PersistentParty>("compositeKey").get<PersistentStateRef>("stateRef")) MaxLineLength:HibernateQueryCriteriaParser.kt$HibernateQueryCriteriaParser$val vaultStates: Root<VaultSchemaV1.VaultStates> 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 } MaxLineLength:HttpApi.kt$HttpApi.Companion$fun fromHostAndPort(hostAndPort: NetworkHostAndPort, base: String, protocol: String = "http", mapper: ObjectMapper = defaultMapper): HttpApi @@ -4513,7 +4516,6 @@ MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$return cacheFactory.buildNamed(Caffeine.newBuilder().weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()), "RpcClientProxyHandler_rpcObservable") MaxLineLength:RPCClientProxyHandler.kt$RPCClientProxyHandler$throw UnsupportedOperationException("Method $calledMethod was added in RPC protocol version $sinceVersion but the server is running $serverProtocolVersion") MaxLineLength:RPCDriver.kt$RPCDriverDSL$val artemisConfig = createRpcServerArtemisConfig(maxFileSize, maxBufferedBytesPerClient, driverDSL.driverDirectory / serverName, hostAndPort) - MaxLineLength:RPCDriver.kt$RPCDriverDSL$val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(InternalUser(rpcUser.username, rpcUser.password, rpcUser.permissions)), id = AuthServiceId("TEST_SECURITY_MANAGER")) MaxLineLength:RPCDriver.kt$RPCDriverDSL.Companion$fun createRpcServerArtemisConfig(maxFileSize: Int, maxBufferedBytesPerClient: Long, baseDirectory: Path, hostAndPort: NetworkHostAndPort): Configuration MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$private inline fun <reified T> HashMap<Class<*>, Generator<*>>.add(generator: Generator<T>) MaxLineLength:RPCDriver.kt$RandomRpcUser.Companion$val handle = RPCClient<RPCOps>(hostAndPort, null, serializationContext = AMQP_RPC_CLIENT_CONTEXT).start(rpcClass, username, password) @@ -4523,6 +4525,9 @@ MaxLineLength:RPCOpsWithContext.kt$fun makeRPCOps(getCordaRPCOps: (username: String, credential: String) -> InternalCordaRPCOps, username: String, credential: String): InternalCordaRPCOps 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 MaxLineLength:RPCSecurityManagerWithAdditionalUser.kt$RPCSecurityManagerWithAdditionalUser : RPCSecurityManager + MaxLineLength:RPCServer.kt$RPCServer + MaxLineLength:RPCServer.kt$RPCServer$( ops: RPCOps, rpcServerUsername: String, rpcServerPassword: String, serverLocator: ServerLocator, securityManager: RPCSecurityManager, nodeLegalName: CordaX500Name, rpcConfiguration: RPCServerConfiguration, cacheFactory: NamedCacheFactory ) + 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> MaxLineLength:RPCServer.kt$RPCServer$consumerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE) MaxLineLength:RPCServer.kt$RPCServer$private MaxLineLength:RPCServer.kt$RPCServer$producerSession = sessionFactory!!.createSession(rpcServerUsername, rpcServerPassword, false, true, true, false, DEFAULT_ACK_BATCH_SIZE) @@ -5432,7 +5437,7 @@ SpreadOperator:RPCDriver.kt$RandomRpcUser.Companion$(handle.proxy, *arguments.toTypedArray()) SpreadOperator:RPCOpsWithContext.kt$(cordaRPCOps, *(args ?: arrayOf())) SpreadOperator:RPCSecurityManagerTest.kt$RPCSecurityManagerTest$(request.first(), *args) - SpreadOperator:RPCServer.kt$RPCServer$(ops, *arguments.toTypedArray()) + SpreadOperator:RPCServer.kt$RPCServer$(invocationTarget.instance, *arguments.toTypedArray()) SpreadOperator:ReactiveArtemisConsumer.kt$ReactiveArtemisConsumer.Companion$(queueName, *queueNames) SpreadOperator:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ErrorInterceptingHandler$(reconnectingRPCConnection.proxy, *(args ?: emptyArray())) SpreadOperator:ServiceHub.kt$ServiceHub$(first, *remaining) @@ -5480,7 +5485,7 @@ ThrowsCount:NonValidatingNotaryFlow.kt$NonValidatingNotaryFlow$ private fun checkNotaryWhitelisted(notary: Party, attachedParameterHash: SecureHash?) ThrowsCount:PropertyDescriptor.kt$PropertyDescriptor$ fun validate() ThrowsCount:RPCApi.kt$RPCApi.ServerToClient.Companion$fun fromClientMessage(context: SerializationContext, message: ClientMessage): ServerToClient - ThrowsCount:RPCServer.kt$RPCServer$private fun invokeRpc(context: RpcAuthContext, methodName: String, arguments: List<Any?>): Try<Any> + ThrowsCount:RPCServer.kt$RPCServer$private fun invokeRpc(context: RpcAuthContext, inMethodName: String, arguments: List<Any?>): Try<Any> ThrowsCount:SchemaMigration.kt$SchemaMigration$private fun doRunMigration(run: Boolean, check: Boolean, existingCheckpoints: Boolean? = null) ThrowsCount:ServicesForResolutionImpl.kt$ServicesForResolutionImpl$// We may need to recursively chase transactions if there are notary changes. fun inner(stateRef: StateRef, forContractClassName: String?): Attachment 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 @@ -6659,6 +6664,7 @@ WildcardImport:QueryCriteriaUtils.kt$import net.corda.core.node.services.vault.LikenessOperator.* WildcardImport:RPCClientProxyHandler.kt$import net.corda.core.internal.* WildcardImport:RPCClientProxyHandler.kt$import org.apache.activemq.artemis.api.core.client.* + WildcardImport:RPCMultipleInterfacesTests.kt$import org.junit.Assert.* WildcardImport:RPCSecurityManagerImpl.kt$import org.apache.shiro.authc.* WildcardImport:RPCServer.kt$import net.corda.core.utilities.* WildcardImport:RPCServer.kt$import org.apache.activemq.artemis.api.core.client.* diff --git a/docs/source/aws-vm.rst b/docs/source/aws-vm.rst index 571620463c..742411f170 100644 --- a/docs/source/aws-vm.rst +++ b/docs/source/aws-vm.rst @@ -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 `__. diff --git a/docs/source/azure-vm.rst b/docs/source/azure-vm.rst index 0a00f46855..0624492f76 100644 --- a/docs/source/azure-vm.rst +++ b/docs/source/azure-vm.rst @@ -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 diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index ef50a9b2ac..3743301b43 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -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 diff --git a/docs/source/clientrpc.rst b/docs/source/clientrpc.rst index 7e5cf7b19b..02e00552b2 100644 --- a/docs/source/clientrpc.rst +++ b/docs/source/clientrpc.rst @@ -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 `_. diff --git a/docs/source/cordapp-build-systems.rst b/docs/source/cordapp-build-systems.rst index abec6d02bd..715c1ce604 100644 --- a/docs/source/cordapp-build-systems.rst +++ b/docs/source/cordapp-build-systems.rst @@ -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 diff --git a/docs/source/demobench.rst b/docs/source/demobench.rst index b079804f8e..36c7cdbf0d 100644 --- a/docs/source/demobench.rst +++ b/docs/source/demobench.rst @@ -126,7 +126,7 @@ current working directory of the JVM): corda/ corda.jar - corda-webserver.jar + corda-testserver.jar explorer/ node-explorer.jar cordapps/ diff --git a/docs/source/deploying-a-node.rst b/docs/source/deploying-a-node.rst index 4d9ae2fd4a..85d0fed967 100644 --- a/docs/source/deploying-a-node.rst +++ b/docs/source/deploying-a-node.rst @@ -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/`` diff --git a/docs/source/design/monitoring-management/design.md b/docs/source/design/monitoring-management/design.md index b15cf81db8..10e21a1fd6 100644 --- a/docs/source/design/monitoring-management/design.md +++ b/docs/source/design/monitoring-management/design.md @@ -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 | - diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 92e63567ba..0a4143ea28 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -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') diff --git a/docs/source/quickstart-build.rst b/docs/source/quickstart-build.rst index c4b406c353..c1c449817b 100644 --- a/docs/source/quickstart-build.rst +++ b/docs/source/quickstart-build.rst @@ -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`` diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/RPCApi.kt b/node-api/src/main/kotlin/net/corda/nodeapi/RPCApi.kt index cf6b813cf5..c4af5510eb 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/RPCApi.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/RPCApi.kt @@ -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. */ diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index d8a5c90132..a37a452c7f 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -375,7 +375,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration, signedNodeInfo, netParams, keyManagementService, - configuration.networkParameterAcceptanceSettings) + configuration.networkParameterAcceptanceSettings!!) try { startMessagingService(rpcOps, nodeInfo, myNotaryIdentity, netParams) } catch (e: Exception) { diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt index c1515430e8..c6c7ebe54d 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt @@ -81,7 +81,7 @@ interface NodeConfiguration { val cordappSignerKeyFingerprintBlacklist: List - val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings + val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings? val blacklistedAttachmentSigningKeys: List diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt index 488bda6bd1..a3dbe02f3d 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt @@ -75,7 +75,8 @@ data class NodeConfigurationImpl( override val jmxReporterType: JmxReporterType? = Defaults.jmxReporterType, override val flowOverrides: FlowOverrideConfig?, override val cordappSignerKeyFingerprintBlacklist: List = Defaults.cordappSignerKeyFingerprintBlacklist, - override val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings = Defaults.networkParameterAcceptanceSettings, + override val networkParameterAcceptanceSettings: NetworkParameterAcceptanceSettings? = + Defaults.networkParameterAcceptanceSettings, override val blacklistedAttachmentSigningKeys: List = Defaults.blacklistedAttachmentSigningKeys ) : NodeConfiguration { internal object Defaults { diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt index 882a254196..81fc40ff66 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/ConfigSections.kt @@ -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("NetworkParameterAcceptanceSettings") { + private val autoAcceptEnabled by boolean().optional().withDefaultValue(true) + private val excludedAutoAcceptableParameters by string().listOrEmpty() + override fun parseValid(configuration: Config): Valid { + return valid(NetworkParameterAcceptanceSettings(configuration[autoAcceptEnabled], + configuration[excludedAutoAcceptableParameters].toSet()) + ) + } +} + + @Suppress("DEPRECATION") internal object CertChainPolicyConfigSpec : Configuration.Specification("CertChainPolicyConfig") { private val role by string() diff --git a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt index 5c9bdf4ac1..32feeb73e0 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/schema/v1/V1NodeConfigurationSpec.kt @@ -58,6 +58,9 @@ internal object V1NodeConfigurationSpec : Configuration.Specification, 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 + /** + * 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 /** 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() + 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> = + clazz.interfaces.filter { RPCOps::class.java.isAssignableFrom(it) }.flatMap { + listOf(it) + listOfApplicableInterfacesRec(it) + } + private fun createObservableSubscriptionMap(): ObservableSubscriptionMap { val onObservableRemove = RemovalListener { 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): Try { + private fun invokeRpc(context: RpcAuthContext, inMethodName: String, arguments: List): Try { 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 } diff --git a/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt b/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt index ff40df7596..c3794701b5 100644 --- a/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt +++ b/node/src/main/kotlin/net/corda/node/services/statemachine/SingleThreadedStateMachineManager.kt @@ -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("#") } diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 9501fd8335..b12af585b6 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -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", diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index a810f598c8..2fc0b17e52 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -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') diff --git a/samples/cordapp-configuration/build.gradle b/samples/cordapp-configuration/build.gradle index 3d1843b1c1..9d466ed986 100644 --- a/samples/cordapp-configuration/build.gradle +++ b/samples/cordapp-configuration/build.gradle @@ -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 { diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index b32344b049..a5a7a40117 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -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']) diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 2844d9ebe7..f95a10716b 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -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 { diff --git a/settings.gradle b/settings.gradle index 07ee58e75a..37526a0581 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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' diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt index 10c803eea3..6d3fa042ea 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt @@ -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 diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt index fad709c789..c1caf61551 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/RPCDriver.kt @@ -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 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 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 ): CordaFuture { 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 startRpcServerWithBrokerRunning( + rpcUser: User = rpcTestUser, + nodeLegalName: CordaX500Name = fakeNodeLegalName, + configuration: RPCServerConfiguration = RPCServerConfiguration.DEFAULT, + listOps: List, + 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, diff --git a/webserver/build.gradle b/testing/testserver/build.gradle similarity index 98% rename from webserver/build.gradle rename to testing/testserver/build.gradle index 77193ad81e..5496288d78 100644 --- a/webserver/build.gradle +++ b/testing/testserver/build.gradle @@ -76,7 +76,7 @@ task integrationTest(type: Test) { } jar { - baseName 'corda-webserver-impl' + baseName 'corda-testserver-impl' } publish { diff --git a/webserver/src/integration-test/kotlin/net/corda/webserver/WebserverDriverTests.kt b/testing/testserver/src/integration-test/kotlin/net/corda/webserver/WebserverDriverTests.kt similarity index 100% rename from webserver/src/integration-test/kotlin/net/corda/webserver/WebserverDriverTests.kt rename to testing/testserver/src/integration-test/kotlin/net/corda/webserver/WebserverDriverTests.kt diff --git a/webserver/src/main/java/CordaWebserverCaplet.java b/testing/testserver/src/main/java/CordaWebserverCaplet.java similarity index 100% rename from webserver/src/main/java/CordaWebserverCaplet.java rename to testing/testserver/src/main/java/CordaWebserverCaplet.java diff --git a/webserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/WebArgsParser.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/WebServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/WebServer.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/WebServer.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/WebServerConfig.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/api/APIServer.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/api/Query.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/api/Query.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/api/Query.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/api/Query.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/converters/Converters.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/internal/APIServerImpl.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/internal/AllExceptionMapper.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/internal/NodeWebServer.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/services/WebServerPluginRegistry.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/services/WebServerPluginRegistry.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/services/WebServerPluginRegistry.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/services/WebServerPluginRegistry.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/servlets/AttachmentDownloadServlet.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/servlets/CorDappInfoServlet.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/servlets/DataUploadServlet.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ObjectMapperConfig.kt diff --git a/webserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt b/testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt similarity index 100% rename from webserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt rename to testing/testserver/src/main/kotlin/net/corda/webserver/servlets/ResponseFilter.kt diff --git a/webserver/src/main/resources/web-reference.conf b/testing/testserver/src/main/resources/web-reference.conf similarity index 100% rename from webserver/src/main/resources/web-reference.conf rename to testing/testserver/src/main/resources/web-reference.conf diff --git a/webserver/webcapsule/build.gradle b/testing/testserver/testcapsule/build.gradle similarity index 82% rename from webserver/webcapsule/build.gradle rename to testing/testserver/testcapsule/build.gradle index 746e8c1206..69dff8cfcd 100644 --- a/webserver/webcapsule/build.gradle +++ b/testing/testserver/testcapsule/build.gradle @@ -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' } diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index 1a307e1e63..a53039babd 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -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 } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServerController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServerController.kt index 6760547adc..4fd46146a3 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServerController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/web/WebServerController.kt @@ -5,7 +5,7 @@ import tornadofx.* class WebServerController : Controller() { private val jvm by inject() - 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")