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
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -35,4 +37,16 @@ abstract class CordaPluginRegistry {
|
||||
* allow access to the protocol factory and protocol initiation entry points there.
|
||||
*/
|
||||
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.
|
||||
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
|
||||
.. _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).
|
||||
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.
|
||||
5. Registering your additional classes used in RPC.
|
||||
|
||||
Services
|
||||
--------
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.docs
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import net.corda.client.CordaRPCClient
|
||||
import net.corda.contracts.asset.Cash
|
||||
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.USD
|
||||
import net.corda.core.div
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
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
|
||||
|
||||
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.PublicKeyTree
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.PhysicalLocation
|
||||
import net.corda.core.node.ServiceEntry
|
||||
import net.corda.core.node.WorldCoordinate
|
||||
import net.corda.core.node.*
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.protocols.StateMachineRunId
|
||||
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,
|
||||
// because we can see everything we're using in one place.
|
||||
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 {
|
||||
isRegistrationRequired = true
|
||||
// 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(KryoException::class.java)
|
||||
register(StringBuffer::class.java)
|
||||
pluginRegistries.forEach { it.registerRPCKryoTypes(this) }
|
||||
}
|
||||
|
||||
// Helper method, attempt to reduce boiler plate code
|
||||
|
Loading…
Reference in New Issue
Block a user