mirror of
https://github.com/corda/corda.git
synced 2024-12-19 21:17:58 +00:00
ENT-3496 Move dumpCheckpoints
to the new InternalCordaRPCOps
interface
To prevent making `dumpCheckpoints` part of the public API a new interface, `InternalCordaRPCOps` has been created and the function has been moved there. `InternalCordaRPCOps` inherits from `CordaRPCOps`. `CordaRPCOpsImpl` now implements `InternalCordaRPCOps`. `RunShellCommand` and `StringToMethodCallParser` required additional changes due to issues handling inherited functions. This has only been raised now due to `InternalCordaRPCOps` inheriting from `CordaRPCOps`. Many classes have had references to `CordaRPCOps` changed to `InternalCordaRPCOps`.
This commit is contained in:
parent
d8395baf62
commit
31a0c077b8
@ -239,15 +239,17 @@ open class StringToMethodCallParser<in T : Any> @JvmOverloads constructor(
|
||||
/** Returns a string-to-string map of commands to a string describing available parameter types. */
|
||||
val availableCommands: Map<String, String>
|
||||
get() {
|
||||
return methodMap.entries().map { entry ->
|
||||
return methodMap.entries().mapNotNull { entry ->
|
||||
val (name, args) = entry // TODO: Kotlin 1.1
|
||||
val argStr = if (args.parameterCount == 0) "" else {
|
||||
val paramNames = methodParamNames[name]!!
|
||||
val typeNames = args.parameters.map { it.type.simpleName }
|
||||
val paramTypes = paramNames.zip(typeNames)
|
||||
paramTypes.joinToString(", ") { "${it.first}: ${it.second}" }
|
||||
val argStr: String? = if (args.parameterCount == 0) "" else {
|
||||
val paramNames = methodParamNames[name]?. let { params ->
|
||||
val typeNames = args.parameters.map { it.type.simpleName }
|
||||
val paramTypes = params.zip(typeNames)
|
||||
paramTypes.joinToString(", ") { "${it.first}: ${it.second}" }
|
||||
}
|
||||
paramNames
|
||||
}
|
||||
Pair(name, argStr)
|
||||
if(argStr == null) null else Pair(name, argStr)
|
||||
}.toMap()
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import net.corda.core.context.Actor
|
||||
import net.corda.core.context.Trace
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.PLATFORM_VERSION
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.ClientRpcSslOptions
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.serialization.SerializationCustomSerializer
|
||||
@ -310,7 +311,7 @@ class CordaRPCClient private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRpcClient(): RPCClient<CordaRPCOps> {
|
||||
private fun getRpcClient(): RPCClient<InternalCordaRPCOps> {
|
||||
return when {
|
||||
// Client->RPC broker
|
||||
haAddressPool.isEmpty() -> RPCClient(
|
||||
@ -385,7 +386,7 @@ class CordaRPCClient private constructor(
|
||||
* @throws RPCException if the server version is too low or if the server isn't reachable within a reasonable timeout.
|
||||
*/
|
||||
fun start(username: String, password: String, externalTrace: Trace?, impersonatedActor: Actor?, targetLegalIdentity: CordaX500Name?): CordaRPCConnection {
|
||||
return CordaRPCConnection(getRpcClient().start(CordaRPCOps::class.java, username, password, externalTrace, impersonatedActor, targetLegalIdentity))
|
||||
return CordaRPCConnection(getRpcClient().start(InternalCordaRPCOps::class.java, username, password, externalTrace, impersonatedActor, targetLegalIdentity))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,7 @@ package net.corda.client.rpc.internal
|
||||
import net.corda.client.rpc.*
|
||||
import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.internal.times
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.messaging.ClientRpcSslOptions
|
||||
@ -44,7 +45,7 @@ class ReconnectingCordaRPCOps private constructor(
|
||||
private val reconnectingRPCConnection: ReconnectingRPCConnection,
|
||||
private val observersPool: ExecutorService,
|
||||
private val userPool: Boolean
|
||||
) : AutoCloseable, CordaRPCOps by proxy(reconnectingRPCConnection, observersPool) {
|
||||
) : AutoCloseable, InternalCordaRPCOps by proxy(reconnectingRPCConnection, observersPool) {
|
||||
|
||||
// Constructors that mirror CordaRPCClient.
|
||||
constructor(
|
||||
@ -77,11 +78,11 @@ class ReconnectingCordaRPCOps private constructor(
|
||||
const val MAX_RETRY_ATTEMPTS_ON_AUTH_ERROR = 3
|
||||
|
||||
private val log = contextLogger()
|
||||
private fun proxy(reconnectingRPCConnection: ReconnectingRPCConnection, observersPool: ExecutorService): CordaRPCOps {
|
||||
private fun proxy(reconnectingRPCConnection: ReconnectingRPCConnection, observersPool: ExecutorService): InternalCordaRPCOps {
|
||||
return Proxy.newProxyInstance(
|
||||
this::class.java.classLoader,
|
||||
arrayOf(CordaRPCOps::class.java),
|
||||
ErrorInterceptingHandler(reconnectingRPCConnection, observersPool)) as CordaRPCOps
|
||||
arrayOf(InternalCordaRPCOps::class.java),
|
||||
ErrorInterceptingHandler(reconnectingRPCConnection, observersPool)) as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,9 +109,6 @@ interface CordaRPCOps : RPCOps {
|
||||
@RPCReturnsObservables
|
||||
fun stateMachinesFeed(): DataFeed<List<StateMachineInfo>, StateMachineUpdate>
|
||||
|
||||
/** Dump all the current flow checkpoints as JSON into a zip file in the node's directory. */
|
||||
fun dumpCheckpoints()
|
||||
|
||||
/**
|
||||
* Returns a snapshot of vault states for a given query criteria (and optional order and paging specification)
|
||||
*
|
||||
|
@ -21,6 +21,7 @@ import net.corda.core.internal.*
|
||||
import net.corda.core.internal.concurrent.doneFuture
|
||||
import net.corda.core.internal.concurrent.map
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.internal.notary.NotaryService
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.*
|
||||
@ -259,7 +260,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
|
||||
/** The implementation of the [CordaRPCOps] interface used by this node. */
|
||||
open fun makeRPCOps(cordappLoader: CordappLoader, checkpointDumper: CheckpointDumper): CordaRPCOps {
|
||||
val ops: CordaRPCOps = CordaRPCOpsImpl(
|
||||
val ops: InternalCordaRPCOps = CordaRPCOpsImpl(
|
||||
services,
|
||||
smm,
|
||||
flowStarter,
|
||||
@ -267,7 +268,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
) {
|
||||
shutdownExecutor.submit(::stop)
|
||||
}.also { it.closeOnStop() }
|
||||
val proxies = mutableListOf<(CordaRPCOps) -> CordaRPCOps>()
|
||||
val proxies = mutableListOf<(InternalCordaRPCOps) -> InternalCordaRPCOps>()
|
||||
// Mind that order is relevant here.
|
||||
proxies += ::AuthenticatedRpcOpsProxy
|
||||
if (!configuration.devMode) {
|
||||
|
@ -17,6 +17,7 @@ import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.RPC_UPLOADER
|
||||
import net.corda.core.internal.STRUCTURAL_STEP_PREFIX
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.internal.sign
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.NetworkParameters
|
||||
@ -54,7 +55,7 @@ internal class CordaRPCOpsImpl(
|
||||
private val flowStarter: FlowStarter,
|
||||
private val checkpointDumper: CheckpointDumper,
|
||||
private val shutdownNode: () -> Unit
|
||||
) : CordaRPCOps, AutoCloseable {
|
||||
) : InternalCordaRPCOps, AutoCloseable {
|
||||
|
||||
private companion object {
|
||||
private val logger = loggerFor<CordaRPCOpsImpl>()
|
||||
|
@ -2,6 +2,7 @@ package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import net.corda.client.rpc.PermissionException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.node.internal.InvocationHandlerTemplate
|
||||
import net.corda.node.services.rpc.RpcAuthContext
|
||||
@ -12,7 +13,7 @@ import java.lang.reflect.Proxy
|
||||
/**
|
||||
* Implementation of [CordaRPCOps] that checks authorisation.
|
||||
*/
|
||||
internal class AuthenticatedRpcOpsProxy(private val delegate: CordaRPCOps) : CordaRPCOps by proxy(delegate, ::rpcContext) {
|
||||
internal class AuthenticatedRpcOpsProxy(private val delegate: InternalCordaRPCOps) : InternalCordaRPCOps by proxy(delegate, ::rpcContext) {
|
||||
/**
|
||||
* Returns the RPC protocol version, which is the same the node's Platform Version. Exists since version 1 so guaranteed
|
||||
* to be present.
|
||||
@ -32,13 +33,13 @@ internal class AuthenticatedRpcOpsProxy(private val delegate: CordaRPCOps) : Cor
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private fun proxy(delegate: CordaRPCOps, context: () -> RpcAuthContext): CordaRPCOps {
|
||||
private fun proxy(delegate: InternalCordaRPCOps, context: () -> RpcAuthContext): InternalCordaRPCOps {
|
||||
val handler = PermissionsEnforcingInvocationHandler(delegate, context)
|
||||
return Proxy.newProxyInstance(delegate::class.java.classLoader, arrayOf(CordaRPCOps::class.java), handler) as CordaRPCOps
|
||||
return Proxy.newProxyInstance(delegate::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java), handler) as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
private class PermissionsEnforcingInvocationHandler(override val delegate: CordaRPCOps, private val context: () -> RpcAuthContext) : InvocationHandlerTemplate {
|
||||
private class PermissionsEnforcingInvocationHandler(override val delegate: InternalCordaRPCOps, private val context: () -> RpcAuthContext) : InvocationHandlerTemplate {
|
||||
override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?) = guard(method.name, context) { super.invoke(proxy, method, arguments) }
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,14 @@
|
||||
package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import net.corda.core.ClientRelevantError
|
||||
import net.corda.core.CordaException
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.*
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.contracts.TransactionVerificationException
|
||||
import net.corda.core.doOnError
|
||||
import net.corda.core.flows.IdentifiableException
|
||||
import net.corda.core.internal.concurrent.doOnError
|
||||
import net.corda.core.internal.concurrent.mapError
|
||||
import net.corda.core.internal.declaredField
|
||||
import net.corda.core.mapErrors
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
import net.corda.core.messaging.FlowHandleImpl
|
||||
import net.corda.core.messaging.FlowProgressHandle
|
||||
import net.corda.core.messaging.FlowProgressHandleImpl
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.internal.InvocationHandlerTemplate
|
||||
import net.corda.nodeapi.exceptions.InternalNodeException
|
||||
@ -25,7 +17,7 @@ import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy.newProxyInstance
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal class ExceptionMaskingRpcOpsProxy(private val delegate: CordaRPCOps, doLog: Boolean) : CordaRPCOps by proxy(delegate, doLog) {
|
||||
internal class ExceptionMaskingRpcOpsProxy(private val delegate: InternalCordaRPCOps, doLog: Boolean) : InternalCordaRPCOps by proxy(delegate, doLog) {
|
||||
private companion object {
|
||||
private val logger = loggerFor<ExceptionMaskingRpcOpsProxy>()
|
||||
|
||||
@ -34,13 +26,13 @@ internal class ExceptionMaskingRpcOpsProxy(private val delegate: CordaRPCOps, do
|
||||
TransactionVerificationException::class
|
||||
)
|
||||
|
||||
private fun proxy(delegate: CordaRPCOps, doLog: Boolean): CordaRPCOps {
|
||||
private fun proxy(delegate: InternalCordaRPCOps, doLog: Boolean): InternalCordaRPCOps {
|
||||
val handler = ErrorObfuscatingInvocationHandler(delegate, whitelist, doLog)
|
||||
return newProxyInstance(delegate::class.java.classLoader, arrayOf(CordaRPCOps::class.java), handler) as CordaRPCOps
|
||||
return newProxyInstance(delegate::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java), handler) as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
private class ErrorObfuscatingInvocationHandler(override val delegate: CordaRPCOps, private val whitelist: Set<KClass<*>>, private val doLog: Boolean) : InvocationHandlerTemplate {
|
||||
private class ErrorObfuscatingInvocationHandler(override val delegate: InternalCordaRPCOps, private val whitelist: Set<KClass<*>>, private val doLog: Boolean) : InvocationHandlerTemplate {
|
||||
override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any? {
|
||||
try {
|
||||
val result = super.invoke(proxy, method, arguments)
|
||||
|
@ -1,18 +1,13 @@
|
||||
package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.CordaThrowable
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.doOnError
|
||||
import net.corda.core.internal.concurrent.doOnError
|
||||
import net.corda.core.internal.concurrent.mapError
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.mapErrors
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.DataFeed
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
import net.corda.core.messaging.FlowHandleImpl
|
||||
import net.corda.core.messaging.FlowProgressHandle
|
||||
import net.corda.core.messaging.FlowProgressHandleImpl
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.internal.InvocationHandlerTemplate
|
||||
@ -20,17 +15,17 @@ import rx.Observable
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy.newProxyInstance
|
||||
|
||||
internal class ExceptionSerialisingRpcOpsProxy(private val delegate: CordaRPCOps, doLog: Boolean) : CordaRPCOps by proxy(delegate, doLog) {
|
||||
internal class ExceptionSerialisingRpcOpsProxy(private val delegate: InternalCordaRPCOps, doLog: Boolean) : InternalCordaRPCOps by proxy(delegate, doLog) {
|
||||
private companion object {
|
||||
private val logger = loggerFor<ExceptionSerialisingRpcOpsProxy>()
|
||||
|
||||
private fun proxy(delegate: CordaRPCOps, doLog: Boolean): CordaRPCOps {
|
||||
private fun proxy(delegate: InternalCordaRPCOps, doLog: Boolean): InternalCordaRPCOps {
|
||||
val handler = ErrorSerialisingInvocationHandler(delegate, doLog)
|
||||
return newProxyInstance(delegate::class.java.classLoader, arrayOf(CordaRPCOps::class.java), handler) as CordaRPCOps
|
||||
return newProxyInstance(delegate::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java), handler) as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
private class ErrorSerialisingInvocationHandler(override val delegate: CordaRPCOps, private val doLog: Boolean) : InvocationHandlerTemplate {
|
||||
private class ErrorSerialisingInvocationHandler(override val delegate: InternalCordaRPCOps, private val doLog: Boolean) : InvocationHandlerTemplate {
|
||||
override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any? {
|
||||
try {
|
||||
val result = super.invoke(proxy, method, arguments)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.node.internal.rpc.proxies
|
||||
|
||||
import net.corda.core.internal.executeWithThreadContextClassLoader
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.node.internal.InvocationHandlerTemplate
|
||||
import java.lang.reflect.Method
|
||||
@ -12,15 +13,15 @@ import java.lang.reflect.Proxy
|
||||
* without sensible fallbacks to the classloader of the current instance.
|
||||
* If clients' CorDapps use one of these libraries, this temporary adjustment can ensure that any provided classes from these libraries will be available during RPC calls.
|
||||
*/
|
||||
internal class ThreadContextAdjustingRpcOpsProxy(private val delegate: CordaRPCOps, private val classLoader: ClassLoader): CordaRPCOps by proxy(delegate, classLoader) {
|
||||
internal class ThreadContextAdjustingRpcOpsProxy(private val delegate: InternalCordaRPCOps, private val classLoader: ClassLoader): InternalCordaRPCOps by proxy(delegate, classLoader) {
|
||||
private companion object {
|
||||
private fun proxy(delegate: CordaRPCOps, classLoader: ClassLoader): CordaRPCOps {
|
||||
private fun proxy(delegate: InternalCordaRPCOps, classLoader: ClassLoader): InternalCordaRPCOps {
|
||||
val handler = ThreadContextAdjustingRpcOpsProxy.ThreadContextAdjustingInvocationHandler(delegate, classLoader)
|
||||
return Proxy.newProxyInstance(delegate::class.java.classLoader, arrayOf(CordaRPCOps::class.java), handler) as CordaRPCOps
|
||||
return Proxy.newProxyInstance(delegate::class.java.classLoader, arrayOf(InternalCordaRPCOps::class.java), handler) as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
|
||||
private class ThreadContextAdjustingInvocationHandler(override val delegate: CordaRPCOps, private val classLoader: ClassLoader) : InvocationHandlerTemplate {
|
||||
private class ThreadContextAdjustingInvocationHandler(override val delegate: InternalCordaRPCOps, private val classLoader: ClassLoader) : InvocationHandlerTemplate {
|
||||
override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any? {
|
||||
return executeWithThreadContextClassLoader(this.classLoader) { super.invoke(proxy, method, arguments) }
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
package net.corda.tools.shell
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory
|
||||
import com.google.common.io.Files
|
||||
import com.jcraft.jsch.ChannelExec
|
||||
import com.jcraft.jsch.JSch
|
||||
import com.nhaarman.mockito_kotlin.any
|
||||
import com.nhaarman.mockito_kotlin.doAnswer
|
||||
import com.nhaarman.mockito_kotlin.mock
|
||||
import net.corda.client.jackson.JacksonSupport
|
||||
import net.corda.client.rpc.RPCException
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.ClientRpcSslOptions
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.utilities.ProgressTracker
|
||||
@ -33,11 +37,13 @@ import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.util.io.Streams
|
||||
import org.crsh.text.RenderPrintWriter
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class InteractiveShellIntegrationTest {
|
||||
@ -47,6 +53,13 @@ class InteractiveShellIntegrationTest {
|
||||
|
||||
private val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
||||
|
||||
private lateinit var inputObjectMapper: ObjectMapper
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
inputObjectMapper = objectMapperWithClassLoader(InteractiveShell.getCordappsClassloader())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shell should not log in with invalid credentials`() {
|
||||
val user = User("u", "p", setOf())
|
||||
@ -277,6 +290,30 @@ class InteractiveShellIntegrationTest {
|
||||
assertThat(successful).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can run dumpCheckpoints`() {
|
||||
val user = User("u", "p", setOf(all()))
|
||||
driver(DriverParameters(notarySpecs = emptyList())) {
|
||||
val nodeFuture = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user), startInSameProcess = true)
|
||||
val node = nodeFuture.getOrThrow()
|
||||
|
||||
val conf = ShellConfiguration(commandsDirectory = Files.createTempDir().toPath(),
|
||||
user = user.username, password = user.password,
|
||||
hostAndPort = node.rpcAddress)
|
||||
InteractiveShell.startShell(conf)
|
||||
// setup and configure some mocks required by InteractiveShell.runFlowByNameFragment()
|
||||
val output = mock<RenderPrintWriter> {
|
||||
on { println(any<String>()) } doAnswer {
|
||||
val line = it.arguments[0]
|
||||
assertNotEquals("Please try 'man run' to learn what syntax is acceptable", line)
|
||||
}
|
||||
}
|
||||
// can call without causing any errors, no output to easily check
|
||||
InteractiveShell.runRPCFromString(
|
||||
listOf("dumpCheckpoints"), output, mock(), node.rpc as InternalCordaRPCOps, inputObjectMapper)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shell should start flow with unique un-qualified class name`() {
|
||||
val user = User("u", "p", setOf(all()))
|
||||
@ -372,6 +409,14 @@ class InteractiveShellIntegrationTest {
|
||||
}
|
||||
assertThat(successful).isTrue()
|
||||
}
|
||||
|
||||
private fun objectMapperWithClassLoader(classLoader: ClassLoader?): ObjectMapper {
|
||||
val objectMapper = JacksonSupport.createNonRpcMapper()
|
||||
val tf = TypeFactory.defaultInstance().withClassLoader(classLoader)
|
||||
objectMapper.typeFactory = tf
|
||||
|
||||
return objectMapper
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED")
|
||||
|
@ -3,6 +3,7 @@ package net.corda.tools.shell;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.corda.client.jackson.StringToMethodCallParser;
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps;
|
||||
import net.corda.core.messaging.CordaRPCOps;
|
||||
import org.crsh.cli.Argument;
|
||||
import org.crsh.cli.Command;
|
||||
@ -13,10 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
|
||||
@ -38,21 +36,31 @@ public class RunShellCommand extends InteractiveShellCommand {
|
||||
public Object main(InvocationContext<Map> context,
|
||||
@Usage("The command to run") @Argument(unquote = false) List<String> command) {
|
||||
logger.info("Executing command \"run {}\",", (command != null) ? String.join(" ", command) : "<no arguments>");
|
||||
StringToMethodCallParser<CordaRPCOps> parser = new StringToMethodCallParser<>(CordaRPCOps.class, objectMapper(InteractiveShell.getCordappsClassloader()));
|
||||
|
||||
if (command == null) {
|
||||
emitHelp(context, parser);
|
||||
emitHelp(context);
|
||||
return null;
|
||||
}
|
||||
|
||||
return InteractiveShell.runRPCFromString(command, out, context, ops(), objectMapper(InteractiveShell.getCordappsClassloader()));
|
||||
}
|
||||
|
||||
private void emitHelp(InvocationContext<Map> context, StringToMethodCallParser<CordaRPCOps> parser) {
|
||||
// Sends data down the pipeline about what commands are available. CRaSH will render it nicely.
|
||||
// Each element we emit is a map of column -> content.
|
||||
Set<Map.Entry<String, String>> entries = parser.getAvailableCommands().entrySet();
|
||||
List<Map.Entry<String, String>> entryList = new ArrayList<>(entries);
|
||||
private void emitHelp(InvocationContext<Map> context) {
|
||||
// to handle the lack of working inheritance in [StringToMethodCallParser] two parsers are used
|
||||
StringToMethodCallParser<CordaRPCOps> cordaRpcOpsParser =
|
||||
new StringToMethodCallParser<>(
|
||||
CordaRPCOps.class, objectMapper(InteractiveShell.getCordappsClassloader()));
|
||||
StringToMethodCallParser<InternalCordaRPCOps> internalCordaRpcOpsParser =
|
||||
new StringToMethodCallParser<>(
|
||||
InternalCordaRPCOps.class, objectMapper(InteractiveShell.getCordappsClassloader()));
|
||||
|
||||
// Sends data down the pipeline about what commands are available. CRaSH will render it nicely.
|
||||
// Each element we emit is a map of column -> content.
|
||||
Set<Map.Entry<String, String>> entries = cordaRpcOpsParser.getAvailableCommands().entrySet();
|
||||
Set<Map.Entry<String, String>> internalEntries = internalCordaRpcOpsParser.getAvailableCommands().entrySet();
|
||||
Set<Map.Entry<String, String>> entrySet = new HashSet<>(entries);
|
||||
entrySet.addAll(internalEntries);
|
||||
List<Map.Entry<String, String>> entryList = new ArrayList<>(entrySet);
|
||||
entryList.sort(comparing(Map.Entry::getKey));
|
||||
for (Map.Entry<String, String> entry : entryList) {
|
||||
// Skip these entries as they aren't really interesting for the user.
|
||||
|
@ -1,13 +1,13 @@
|
||||
package net.corda.tools.shell
|
||||
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
|
||||
import org.crsh.auth.AuthInfo
|
||||
import org.crsh.auth.AuthenticationPlugin
|
||||
import org.crsh.plugin.CRaSHPlugin
|
||||
|
||||
class CordaAuthenticationPlugin(private val rpcOps: (username: String, credential: String) -> CordaRPCOps) : CRaSHPlugin<AuthenticationPlugin<String>>(), AuthenticationPlugin<String> {
|
||||
class CordaAuthenticationPlugin(private val rpcOps: (username: String, credential: String) -> InternalCordaRPCOps) : CRaSHPlugin<AuthenticationPlugin<String>>(), AuthenticationPlugin<String> {
|
||||
|
||||
companion object {
|
||||
private val logger = loggerFor<CordaAuthenticationPlugin>()
|
||||
|
@ -1,12 +1,12 @@
|
||||
package net.corda.tools.shell
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.tools.shell.InteractiveShell.createYamlInputMapper
|
||||
import net.corda.tools.shell.utlities.ANSIProgressRenderer
|
||||
import org.crsh.auth.AuthInfo
|
||||
|
||||
class CordaSSHAuthInfo(val successful: Boolean, val rpcOps: CordaRPCOps, val ansiProgressRenderer: ANSIProgressRenderer? = null, val isSsh: Boolean = false) : AuthInfo {
|
||||
class CordaSSHAuthInfo(val successful: Boolean, val rpcOps: InternalCordaRPCOps, val ansiProgressRenderer: ANSIProgressRenderer? = null, val isSsh: Boolean = false) : AuthInfo {
|
||||
override fun isSuccessful(): Boolean = successful
|
||||
|
||||
val yamlInputMapper: ObjectMapper by lazy {
|
||||
|
@ -23,6 +23,7 @@ import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.internal.concurrent.doneFuture
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.tools.shell.utlities.ANSIProgressRenderer
|
||||
import net.corda.tools.shell.utlities.StdoutANSIProgressRenderer
|
||||
@ -73,8 +74,8 @@ import kotlin.concurrent.thread
|
||||
|
||||
object InteractiveShell {
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
private lateinit var rpcOps: (username: String, password: String) -> CordaRPCOps
|
||||
private lateinit var ops: CordaRPCOps
|
||||
private lateinit var rpcOps: (username: String, password: String) -> InternalCordaRPCOps
|
||||
private lateinit var ops: InternalCordaRPCOps
|
||||
private lateinit var rpcConn: AutoCloseable
|
||||
private var shell: Shell? = null
|
||||
private var classLoader: ClassLoader? = null
|
||||
@ -104,7 +105,7 @@ object InteractiveShell {
|
||||
classLoader = classLoader)
|
||||
val connection = client.start(username, password)
|
||||
rpcConn = connection
|
||||
connection.proxy
|
||||
connection.proxy as InternalCordaRPCOps
|
||||
}
|
||||
}
|
||||
_startShell(configuration, classLoader)
|
||||
@ -488,7 +489,7 @@ object InteractiveShell {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun runRPCFromString(input: List<String>, out: RenderPrintWriter, context: InvocationContext<out Any>, cordaRPCOps: CordaRPCOps,
|
||||
fun runRPCFromString(input: List<String>, out: RenderPrintWriter, context: InvocationContext<out Any>, cordaRPCOps: InternalCordaRPCOps,
|
||||
inputObjectMapper: ObjectMapper): Any? {
|
||||
val cmd = input.joinToString(" ").trim { it <= ' ' }
|
||||
if (cmd.startsWith("startflow", ignoreCase = true)) {
|
||||
@ -504,7 +505,7 @@ object InteractiveShell {
|
||||
var result: Any? = null
|
||||
try {
|
||||
InputStreamSerializer.invokeContext = context
|
||||
val parser = StringToMethodCallParser(CordaRPCOps::class.java, inputObjectMapper)
|
||||
val parser = StringToMethodCallParser(InternalCordaRPCOps::class.java, inputObjectMapper)
|
||||
val call = parser.parse(cordaRPCOps, cmd)
|
||||
result = call.call()
|
||||
if (result != null && result !== kotlin.Unit && result !is Void) {
|
||||
|
@ -1,20 +1,20 @@
|
||||
package net.corda.tools.shell
|
||||
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
fun makeRPCOps(getCordaRPCOps: (username: String, credential: String) -> CordaRPCOps, username: String, credential: String): CordaRPCOps {
|
||||
val cordaRPCOps: CordaRPCOps by lazy {
|
||||
fun makeRPCOps(getCordaRPCOps: (username: String, credential: String) -> InternalCordaRPCOps, username: String, credential: String): InternalCordaRPCOps {
|
||||
val cordaRPCOps: InternalCordaRPCOps by lazy {
|
||||
getCordaRPCOps(username, credential)
|
||||
}
|
||||
|
||||
return Proxy.newProxyInstance(CordaRPCOps::class.java.classLoader, arrayOf(CordaRPCOps::class.java), { _, method, args ->
|
||||
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 CordaRPCOps
|
||||
} as InternalCordaRPCOps
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.internal.messaging.InternalCordaRPCOps
|
||||
import net.corda.core.messaging.FlowProgressHandleImpl
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
@ -41,7 +41,7 @@ import kotlin.test.assertFailsWith
|
||||
|
||||
class InteractiveShellTest {
|
||||
lateinit var inputObjectMapper: ObjectMapper
|
||||
lateinit var cordaRpcOps: CordaRPCOps
|
||||
lateinit var cordaRpcOps: InternalCordaRPCOps
|
||||
lateinit var invocationContext: InvocationContext<Map<Any, Any>>
|
||||
lateinit var printWriter: RenderPrintWriter
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user