mirror of
https://github.com/corda/corda.git
synced 2024-12-21 05:53:23 +00:00
RPC Kryo plugin functionality.
This commit is contained in:
parent
f90c5a702a
commit
6abb5750bf
@ -1,5 +1,7 @@
|
|||||||
package net.corda.core.node
|
package net.corda.core.node
|
||||||
|
|
||||||
|
import com.esotericsoftware.kryo.Kryo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement this interface on a class advertised in a META-INF/services/net.corda.core.node.CordaPluginRegistry file
|
* Implement this interface on a class advertised in a META-INF/services/net.corda.core.node.CordaPluginRegistry file
|
||||||
* to extend a Corda node with additional application services.
|
* to extend a Corda node with additional application services.
|
||||||
@ -35,4 +37,16 @@ abstract class CordaPluginRegistry {
|
|||||||
* allow access to the protocol factory and protocol initiation entry points there.
|
* allow access to the protocol factory and protocol initiation entry points there.
|
||||||
*/
|
*/
|
||||||
open val servicePlugins: List<Class<*>> = emptyList()
|
open val servicePlugins: List<Class<*>> = emptyList()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally register types with [Kryo] for use over RPC, as we lock down the types that can be serialised in this
|
||||||
|
* particular use case.
|
||||||
|
* For example, if you add an RPC interface that carries some contract states back and forth, you need to register
|
||||||
|
* those classes here using the [register] method on Kryo.
|
||||||
|
*
|
||||||
|
* TODO: Kryo and likely the requirement to register classes here will go away when we replace the serialization implementation.
|
||||||
|
*
|
||||||
|
* @return true if you register types, otherwise you will be filtered out of the list of plugins considered in future.
|
||||||
|
*/
|
||||||
|
open fun registerRPCKryoTypes(kryo: Kryo): Boolean = false
|
||||||
}
|
}
|
||||||
|
@ -80,5 +80,17 @@ Wire protocol
|
|||||||
The client RPC wire protocol is not currently documented. To use it you must use the client library provided.
|
The client RPC wire protocol is not currently documented. To use it you must use the client library provided.
|
||||||
This is likely to change in a future release.
|
This is likely to change in a future release.
|
||||||
|
|
||||||
|
Registering Classes With RPC Kryo
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
In the present implementation of the node we use Kryo to generate the *on the wire* representation of contracts states
|
||||||
|
or any other classes that form part of the RPC arguments or response. To avoid the RPC interface being wide open to all
|
||||||
|
classes on the classpath, Cordapps will currently have to register any classes or custom serialisers they require with Kryo
|
||||||
|
if they are not one of those registered by default in ``RPCKryo`` via the plugin architecture. See :doc:`creating-a-cordapp`.
|
||||||
|
This will require some familiarity with Kryo. An example is shown in :doc:`tutorial-clientrpc-api`.
|
||||||
|
|
||||||
|
.. warning:: We will be replacing the use of Kryo in RPC with a stable message format and this will mean that this plugin
|
||||||
|
customisation point will either go away completely or change.
|
||||||
|
|
||||||
.. _CordaRPCClient: api/net.corda.client/-corda-r-p-c-client/index.html
|
.. _CordaRPCClient: api/net.corda.client/-corda-r-p-c-client/index.html
|
||||||
.. _CordaRPCOps: api/net.corda.node.services.messaging/-corda-r-p-c-ops/index.html
|
.. _CordaRPCOps: api/net.corda.node.services.messaging/-corda-r-p-c-ops/index.html
|
||||||
|
@ -16,6 +16,7 @@ specific details of the implementation, but you can extend the server in the fol
|
|||||||
2. Service plugins: Register your services (see below).
|
2. Service plugins: Register your services (see below).
|
||||||
3. Web APIs: You may register your own endpoints under /api/ of the built-in web server.
|
3. Web APIs: You may register your own endpoints under /api/ of the built-in web server.
|
||||||
4. Static web endpoints: You may register your own static serving directories for serving web content.
|
4. Static web endpoints: You may register your own static serving directories for serving web content.
|
||||||
|
5. Registering your additional classes used in RPC.
|
||||||
|
|
||||||
Services
|
Services
|
||||||
--------
|
--------
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.docs
|
package net.corda.docs
|
||||||
|
|
||||||
|
import com.esotericsoftware.kryo.Kryo
|
||||||
import net.corda.client.CordaRPCClient
|
import net.corda.client.CordaRPCClient
|
||||||
import net.corda.contracts.asset.Cash
|
import net.corda.contracts.asset.Cash
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
@ -7,6 +8,7 @@ import net.corda.core.contracts.Issued
|
|||||||
import net.corda.core.contracts.PartyAndReference
|
import net.corda.core.contracts.PartyAndReference
|
||||||
import net.corda.core.contracts.USD
|
import net.corda.core.contracts.USD
|
||||||
import net.corda.core.div
|
import net.corda.core.div
|
||||||
|
import net.corda.core.node.CordaPluginRegistry
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.serialization.OpaqueBytes
|
import net.corda.core.serialization.OpaqueBytes
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
@ -135,4 +137,17 @@ fun generateTransactions(proxy: CordaRPCOps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// END 6
|
// END 6
|
||||||
|
|
||||||
|
// START 7
|
||||||
|
data class ExampleRPCValue(val foo: String)
|
||||||
|
|
||||||
|
class ExampleRPCCordaPluginRegistry : CordaPluginRegistry() {
|
||||||
|
override fun registerRPCKryoTypes(kryo: Kryo): Boolean {
|
||||||
|
// Add classes like this.
|
||||||
|
kryo.register(ExampleRPCValue::class.java)
|
||||||
|
// You should return true, otherwise your plugin will be ignored for registering classes with Kryo.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// END 7
|
||||||
|
@ -79,3 +79,19 @@ Now let's try to visualise the transaction graph. We will use a graph drawing li
|
|||||||
:end-before: END 5
|
:end-before: END 5
|
||||||
|
|
||||||
If we run the client with ``Visualise`` we should see a simple random graph being drawn as new transactions are being created.
|
If we run the client with ``Visualise`` we should see a simple random graph being drawn as new transactions are being created.
|
||||||
|
|
||||||
|
Registering classes from your Cordapp with RPC Kryo
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
As described in :doc:`clientrpc`, you currently have to register any additional classes you add that are needed in RPC
|
||||||
|
requests or responses with the `Kryo` instance RPC uses. Here's an example of how you do this for an example class.
|
||||||
|
|
||||||
|
.. literalinclude:: example-code/src/main/kotlin/net/corda/docs/ClientRpcTutorial.kt
|
||||||
|
:language: kotlin
|
||||||
|
:start-after: START 7
|
||||||
|
:end-before: END 7
|
||||||
|
|
||||||
|
See more on plugins in :doc:`creating-a-cordapp`.
|
||||||
|
|
||||||
|
.. warning:: We will be replacing the use of Kryo in RPC with a stable message format and this will mean that this plugin
|
||||||
|
customisation point will either go away completely or change.
|
@ -20,10 +20,7 @@ import net.corda.core.crypto.DigitalSignature
|
|||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
import net.corda.core.crypto.PublicKeyTree
|
import net.corda.core.crypto.PublicKeyTree
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.*
|
||||||
import net.corda.core.node.PhysicalLocation
|
|
||||||
import net.corda.core.node.ServiceEntry
|
|
||||||
import net.corda.core.node.WorldCoordinate
|
|
||||||
import net.corda.core.node.services.*
|
import net.corda.core.node.services.*
|
||||||
import net.corda.core.protocols.StateMachineRunId
|
import net.corda.core.protocols.StateMachineRunId
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
@ -117,6 +114,14 @@ class PermissionException(msg: String) : RuntimeException(msg)
|
|||||||
// This is annoying to write out, but will make it easier to formalise the wire protocol when the time comes,
|
// This is annoying to write out, but will make it easier to formalise the wire protocol when the time comes,
|
||||||
// because we can see everything we're using in one place.
|
// because we can see everything we're using in one place.
|
||||||
private class RPCKryo(observableSerializer: Serializer<Observable<Any>>? = null) : Kryo() {
|
private class RPCKryo(observableSerializer: Serializer<Observable<Any>>? = null) : Kryo() {
|
||||||
|
companion object {
|
||||||
|
private val pluginRegistries: List<CordaPluginRegistry> by lazy {
|
||||||
|
val unusedKryo = Kryo()
|
||||||
|
// Sorting required to give a stable ordering, as Kryo allocates integer tokens for each registered class.
|
||||||
|
ServiceLoader.load(CordaPluginRegistry::class.java).toList().filter { it.registerRPCKryoTypes(unusedKryo) }.sortedBy { it.javaClass.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
isRegistrationRequired = true
|
isRegistrationRequired = true
|
||||||
// Allow construction of objects using a JVM backdoor that skips invoking the constructors, if there is no
|
// Allow construction of objects using a JVM backdoor that skips invoking the constructors, if there is no
|
||||||
@ -215,6 +220,7 @@ private class RPCKryo(observableSerializer: Serializer<Observable<Any>>? = null)
|
|||||||
register(ProtocolHandle::class.java)
|
register(ProtocolHandle::class.java)
|
||||||
register(KryoException::class.java)
|
register(KryoException::class.java)
|
||||||
register(StringBuffer::class.java)
|
register(StringBuffer::class.java)
|
||||||
|
pluginRegistries.forEach { it.registerRPCKryoTypes(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method, attempt to reduce boiler plate code
|
// Helper method, attempt to reduce boiler plate code
|
||||||
|
Loading…
Reference in New Issue
Block a user