From 97cd2fcd3ab58acd2a46fb23489f5b175748aebf Mon Sep 17 00:00:00 2001 From: Anthony Keenan Date: Tue, 11 Sep 2018 13:36:38 +0100 Subject: [PATCH 1/4] Publish cliutils (#3927) --- build.gradle | 3 ++- tools/cliutils/build.gradle | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a1ae6ac906..ed6188c746 100644 --- a/build.gradle +++ b/build.gradle @@ -350,7 +350,8 @@ bintrayConfig { 'corda-serialization-deterministic', 'corda-tools-blob-inspector', 'corda-tools-explorer', - 'corda-tools-network-bootstrapper' + 'corda-tools-network-bootstrapper', + 'corda-tools-cliutils' ] license { name = 'Apache-2.0' diff --git a/tools/cliutils/build.gradle b/tools/cliutils/build.gradle index 501b11cf58..a73bd68cb7 100644 --- a/tools/cliutils/build.gradle +++ b/tools/cliutils/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'java' apply plugin: 'kotlin' +apply plugin: 'net.corda.plugins.publish-utils' description 'CLI Utilities' @@ -15,3 +16,12 @@ dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" } + +jar { + baseName = "cliutils" +} + +publish { + name 'corda-tools-cliutils' +} + From ce5cdc03f37bd21bdf20606c6d33e04c18b26776 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Tue, 11 Sep 2018 13:44:22 +0100 Subject: [PATCH 2/4] Use standard Automatic-Module-Name for DemoBench. (#3913) --- tools/demobench/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index d62249294a..2dbc5c941a 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -88,8 +88,7 @@ jar { manifest { attributes( 'Main-Class': mainClassName, - 'Class-Path': configurations.runtime.collect { it.getName() }.join(' '), - 'Automatic-Module-Name': 'net.corda.tools.demobench' + 'Class-Path': configurations.runtimeClasspath.collect { it.name }.join(' '), ) } } From 49adf553974f2e79f5e7089566e4a7462de26225 Mon Sep 17 00:00:00 2001 From: Viktor Kolomeyko Date: Tue, 11 Sep 2018 16:32:17 +0100 Subject: [PATCH 3/4] ENT-2489: Additional optional parameter to specify target for RPC invocation. (#3915) This is a split-out change from an enterprise feature, but since we do have: `RPCApi.RPC_TARGET_LEGAL_IDENTITY` header constant even in OS, it would make sense to extend RPC client API to populate this. --- .../net/corda/client/rpc/CordaRPCClient.kt | 36 ++++++++++++++++++- .../corda/client/rpc/internal/RPCClient.kt | 7 ++-- .../rpc/internal/RPCClientProxyHandler.kt | 9 +++-- docs/source/changelog.rst | 2 ++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt index 56724a4de8..116e6baf84 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/CordaRPCClient.kt @@ -4,6 +4,7 @@ import net.corda.client.rpc.internal.RPCClient import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme import net.corda.core.context.Actor import net.corda.core.context.Trace +import net.corda.core.identity.CordaX500Name import net.corda.core.messaging.CordaRPCOps import net.corda.core.serialization.internal.effectiveSerializationEnv import net.corda.core.utilities.NetworkHostAndPort @@ -329,6 +330,21 @@ class CordaRPCClient private constructor( return start(username, password, null, null) } + /** + * Logs in to the target server and returns an active connection. The returned connection is a [java.io.Closeable] + * and can be used with a try-with-resources statement. If you don't use that, you should use the + * [RPCConnection.notifyServerAndClose] or [RPCConnection.forceClose] methods to dispose of the connection object + * when done. + * + * @param username The username to authenticate with. + * @param password The password to authenticate with. + * @param targetLegalIdentity in case of multi-identity RPC endpoint specific legal identity to which the calls must be addressed. + * @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, targetLegalIdentity: CordaX500Name): CordaRPCConnection { + return start(username, password, null, null, targetLegalIdentity) + } + /** * Logs in to the target server and returns an active connection. The returned connection is a [java.io.Closeable] * and can be used with a try-with-resources statement. If you don't use that, you should use the @@ -338,10 +354,28 @@ class CordaRPCClient private constructor( * @param username The username to authenticate with. * @param password The password to authenticate with. * @param externalTrace external [Trace] for correlation. + * @param impersonatedActor the actor on behalf of which all the invocations will be made. * @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?): CordaRPCConnection { - return CordaRPCConnection(getRpcClient().start(CordaRPCOps::class.java, username, password, externalTrace, impersonatedActor)) + return start(username, password, externalTrace, impersonatedActor, null) + } + + /** + * Logs in to the target server and returns an active connection. The returned connection is a [java.io.Closeable] + * and can be used with a try-with-resources statement. If you don't use that, you should use the + * [RPCConnection.notifyServerAndClose] or [RPCConnection.forceClose] methods to dispose of the connection object + * when done. + * + * @param username The username to authenticate with. + * @param password The password to authenticate with. + * @param externalTrace external [Trace] for correlation. + * @param impersonatedActor the actor on behalf of which all the invocations will be made. + * @param targetLegalIdentity in case of multi-identity RPC endpoint specific legal identity to which the calls must be addressed. + * @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)) } /** diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt index f34da0a84a..a29c481d47 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClient.kt @@ -6,6 +6,7 @@ import net.corda.client.rpc.RPCException import net.corda.core.context.Actor import net.corda.core.context.Trace import net.corda.core.crypto.random63BitValue +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.logElapsedTime import net.corda.core.internal.uncheckedCast import net.corda.core.messaging.ClientRpcSslOptions @@ -65,7 +66,8 @@ class RPCClient( username: String, password: String, externalTrace: Trace? = null, - impersonatedActor: Actor? = null + impersonatedActor: Actor? = null, + targetLegalIdentity: CordaX500Name? = null ): RPCConnection { return log.logElapsedTime("Startup") { val clientAddress = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.$username.${random63BitValue()}") @@ -85,7 +87,8 @@ class RPCClient( isUseGlobalPools = nodeSerializationEnv != null } val sessionId = Trace.SessionId.newInstance() - val proxyHandler = RPCClientProxyHandler(rpcConfiguration, username, password, serverLocator, clientAddress, rpcOpsClass, serializationContext, sessionId, externalTrace, impersonatedActor) + val proxyHandler = RPCClientProxyHandler(rpcConfiguration, username, password, serverLocator, clientAddress, + rpcOpsClass, serializationContext, sessionId, externalTrace, impersonatedActor, targetLegalIdentity) try { proxyHandler.start() val ops: I = uncheckedCast(Proxy.newProxyInstance(rpcOpsClass.classLoader, arrayOf(rpcOpsClass), proxyHandler)) 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 c45c4671b7..f7438b02f4 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 @@ -14,6 +14,7 @@ import net.corda.client.rpc.internal.serialization.amqp.RpcClientObservableDeSer import net.corda.core.context.Actor 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.RPCOps import net.corda.core.serialization.SerializationContext @@ -64,7 +65,7 @@ import kotlin.reflect.jvm.javaMethod * automatically signal the server. This is done using a cache that holds weak references to the [UnicastSubject]s. * The cleanup happens in batches using a dedicated reaper, scheduled on [reaperExecutor]. * - * The client will attempt to failover in case the server become unreachable. Depending on the [ServerLocataor] instance + * The client will attempt to failover in case the server become unreachable. Depending on the [ServerLocator] instance * passed in the constructor, failover is either handle at Artemis level or client level. If only one transport * was used to create the [ServerLocator], failover is handled by Artemis (retrying based on [CordaRPCClientConfiguration]. * If a list of transport configurations was used, failover is handled locally. Artemis is able to do it, however the @@ -80,7 +81,8 @@ class RPCClientProxyHandler( serializationContext: SerializationContext, private val sessionId: Trace.SessionId, private val externalTrace: Trace?, - private val impersonatedActor: Actor? + private val impersonatedActor: Actor?, + private val targetLegalIdentity: CordaX500Name? ) : InvocationHandler { private enum class State { @@ -274,6 +276,9 @@ class RPCClientProxyHandler( private fun sendMessage(message: RPCApi.ClientToServer) { val artemisMessage = producerSession!!.createMessage(false) message.writeToClientMessage(artemisMessage) + targetLegalIdentity?.let { + artemisMessage.putStringProperty(RPCApi.RPC_TARGET_LEGAL_IDENTITY, it.toString()) + } sendExecutor!!.submit { artemisMessage.putLongProperty(RPCApi.DEDUPLICATION_SEQUENCE_NUMBER_FIELD_NAME, deduplicationSequenceNumber.getAndIncrement()) log.debug { "-> RPC -> $message" } diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index b0440cf00f..f1705f57a4 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -7,6 +7,8 @@ release, see :doc:`upgrade-notes`. Unreleased ---------- +* New overload for ``CordaRPCClient.start()`` method allowing to specify target legal identity to use for RPC call. + * Case insensitive vault queries can be specified via a boolean on applicable SQL criteria builder operators. By default queries will be case sensitive. * Getter added to ``CordaRPCOps`` for the node's network parameters. From f5768348eecd3aaff8b94d8b46a4e9e445af2a56 Mon Sep 17 00:00:00 2001 From: Konstantinos Chalkias Date: Tue, 11 Sep 2018 17:39:19 +0100 Subject: [PATCH 4/4] More descriptive message on "latest" supported Java version. (#3929) Also a TODO to reconsider the auto-resume registration functionality. --- node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 3ccb4792c3..6da2c527e9 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -68,13 +68,15 @@ open class NodeStartup: CordaCliWrapper("corda", "Runs a Corda Node") { override fun runProgram(): Int { val startTime = System.currentTimeMillis() if (!canNormalizeEmptyPath()) { - println("You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest version.") + println("You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest supported version.") println("Corda will now exit...") return ExitCodes.FAILURE } val registrationMode = checkRegistrationMode() + // TODO: Reconsider if automatic re-registration should be applied when something failed during initial registration. + // There might be cases where the node user should investigate what went wrong before registering again. if (registrationMode && !cmdLineOptions.isRegistration) { println("Node was started before with `--initial-registration`, but the registration was not completed.\nResuming registration.") // Pretend that the node was started with `--initial-registration` to help prevent user error.