Revert: Extensions to Corda Behave for CTS.

This commit is contained in:
josecoll 2018-05-02 15:51:45 +01:00
parent 8f47fe8c68
commit c27003b471
2 changed files with 248 additions and 0 deletions

View File

@ -0,0 +1,85 @@
/*
* R3 Proprietary and Confidential
*
* Copyright (c) 2018 R3 Limited. All rights reserved.
*
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
*
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
group 'net.corda.behave.tools'
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
configurations {
smokeTestCompile.extendsFrom testCompile
smokeTestRuntime.extendsFrom testRuntime
}
sourceSets {
rpcProxy {
kotlin {
srcDir "src/main/kotlin"
}
resources {
srcDir "config/dev"
}
}
smokeTest {
kotlin {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/smoke-test/kotlin')
}
}
}
dependencies {
compile project(':test-utils')
compile "net.corda.plugins:cordform-common:$gradle_plugins_version"
// Integration test helpers
testCompile "org.assertj:assertj-core:$assertj_version"
testCompile "junit:junit:$junit_version"
compile project(':finance')
compileOnly project(':node-api')
compile project(':core')
compile project(':client:rpc')
// includes jetty/jersey dependencies used by RPCProxyServer
compile project(':webserver')
// Jetty http server
rpcProxyCompile "org.eclipse.jetty:jetty-servlet:$jetty_version"
rpcProxyCompile "org.eclipse.jetty:jetty-webapp:$jetty_version"
rpcProxyCompile "javax.servlet:javax.servlet-api:3.1.0"
// Jersey for JAX-RS implementation for use in Jetty
rpcProxyCompile "org.glassfish.jersey.core:jersey-server:$jersey_version"
rpcProxyCompile "org.glassfish.jersey.containers:jersey-container-servlet-core:$jersey_version"
rpcProxyCompile "org.glassfish.jersey.containers:jersey-container-jetty-http:$jersey_version"
}
task smokeTest(type: Test) {
testClassesDirs = sourceSets.smokeTest.output.classesDirs
classpath = sourceSets.smokeTest.runtimeClasspath
}
task rpcProxyJar(type: Jar) {
baseName "corda-rpcProxy"
from {
configurations.rpcProxyRuntime.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
exclude("META-INF/*.DSA")
exclude("META-INF/*.RSA")
exclude("META-INF/*.SF")
manifest {
attributes 'Main-Class': 'net.corda.behave.service.proxy.RPCProxyServerKt'
}
}

View File

@ -0,0 +1,163 @@
package net.corda.behave.service.proxy
import net.corda.behave.service.proxy.RPCProxyWebService.Companion.RPC_PROXY_PATH
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCClientConfiguration
import net.corda.client.rpc.internal.KryoClientSerializationScheme
import net.corda.core.contracts.ContractState
import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.internal.effectiveSerializationEnv
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import java.io.InputStream
import javax.servlet.http.HttpServletRequest
import javax.ws.rs.Consumes
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.core.Context
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
import javax.ws.rs.core.Response.status
@Path(RPC_PROXY_PATH)
class RPCProxyWebService(targetHostAndPort: NetworkHostAndPort) {
// see "NetworkInterface" port allocation definitions
private val targetPort = targetHostAndPort.port - 1000
init {
try {
effectiveSerializationEnv
} catch (e: IllegalStateException) {
try {
KryoClientSerializationScheme.initialiseSerialization()
} catch (e: IllegalStateException) {
// Race e.g. two of these constructed in parallel, ignore.
}
}
}
companion object {
private val log = contextLogger()
const val DEFAULT_PASSWORD = "S0meS3cretW0rd"
const val RPC_PROXY_PATH = "rpc"
}
@GET
@Path("my-ip")
fun myIp(@Context request: HttpServletRequest): Response {
return createResponse("HELLO! My ip is ${request.remoteHost}:${request.remotePort}")
}
@GET
@Path("node-info")
fun nodeInfo(@Context request: HttpServletRequest): Response {
log.info("nodeInfo")
return use {
it.nodeInfo()
}
}
@GET
@Path("registered-flows")
fun registeredFlows(@Context request: HttpServletRequest): Response {
log.info("registeredFlows")
return use {
it.registeredFlows()
}
}
@GET
@Path("notary-identities")
fun notaryIdentities(@Context request: HttpServletRequest): Response {
log.info("networkMapSnapshot")
return use {
it.notaryIdentities()
}
}
@GET
@Path("network-map-snapshot")
fun networkMapSnapshot(@Context request: HttpServletRequest): Response {
log.info("networkMapSnapshot")
return use {
it.networkMapSnapshot()
}
}
@POST
@Path("parties-from-name")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
fun partiesFromName(input: InputStream): Response {
log.info("partiesFromName")
val queryName = input.readBytes().deserialize<String>()
return use {
it.partiesFromName(queryName, false)
}
}
@POST
@Path("vault-query")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
fun vaultQuery(input: InputStream): Response {
log.info("vaultQuery")
val contractStateType = input.readBytes().deserialize<String>()
val clazz = Class.forName(contractStateType) as Class<ContractState>
return use {
log.info("Calling vaultQuery with: $clazz")
it.vaultQuery(clazz)
}
}
@POST
@Path("start-flow")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
fun startFlow(input: InputStream): Response {
log.info("startFlow")
return use { rpcClient ->
val argsList = input.readBytes().deserialize<List<Any>>()
for (i in argsList.indices) {
log.info("$i: ${argsList[i]}")
}
val flowClass = Class.forName(argsList[0] as String) as Class<FlowLogic<*>>
val flowArgs = argsList.drop(1).toTypedArray()
log.info("Calling flow: $flowClass with arguments: ${flowArgs.asList()}")
rpcClient.startFlowDynamic(flowClass, *flowArgs).returnValue.getOrThrow()
}
}
private fun <T> use(action: (CordaRPCOps) -> T): Response {
val targetHost = NetworkHostAndPort("localhost", targetPort)
val config = object : CordaRPCClientConfiguration {
override val connectionMaxRetryInterval = 10.seconds
}
log.info("Establishing RPC connection to ${targetHost.host} on port ${targetHost.port} ...")
return try {
CordaRPCClient(targetHost, config).use("corda", DEFAULT_PASSWORD) {
log.info("RPC connection to ${targetHost.host}:${targetHost.port} established")
val client = it.proxy
val result = action(client)
log.info("CordaRPCOps result: $result")
return createResponse(result)
}
} catch (e: Exception) {
log.warn("RPC Proxy request failed: ", e)
e.printStackTrace()
status(Response.Status.INTERNAL_SERVER_ERROR).encoding(e.message)
}.build()
}
private fun createResponse(payload: Any?): Response {
return if (payload != null) {
Response.ok(payload.serialize().bytes)
} else {
status(Response.Status.NOT_FOUND)
}.build()
}
}