mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
* Move CompositeSignaturesWithKeys into net.corda.core.crypto package.
* Rename and move CordaPluginRegistry to reflect its real purpose now. * Docs: docsite improvements * Remove discussion of webserver from 'writing a cordapp' page. * Fixup some flow docs. * Add a couple more package descriptions. * Review comments - always apply default whitelist and no longer load it via ServiceLoader * Added wording about renaming services resource file
This commit is contained in:
parent
12982b3034
commit
9a16011448
@ -1,8 +1,8 @@
|
||||
package net.corda.core.cordapp
|
||||
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import java.net.URL
|
||||
|
||||
@ -19,7 +19,7 @@ import java.net.URL
|
||||
* @property rpcFlows List of RPC initiable flows classes
|
||||
* @property schedulableFlows List of flows startable by the scheduler
|
||||
* @property servies List of RPC services
|
||||
* @property plugins List of Corda plugin registries
|
||||
* @property serializationWhitelists List of Corda plugin registries
|
||||
* @property customSchemas List of custom schemas
|
||||
* @property jarPath The path to the JAR for this CorDapp
|
||||
*/
|
||||
@ -30,7 +30,7 @@ interface Cordapp {
|
||||
val rpcFlows: List<Class<out FlowLogic<*>>>
|
||||
val schedulableFlows: List<Class<out FlowLogic<*>>>
|
||||
val services: List<Class<out SerializeAsToken>>
|
||||
val plugins: List<CordaPluginRegistry>
|
||||
val serializationWhitelists: List<SerializationWhitelist>
|
||||
val customSchemas: Set<MappedSchema>
|
||||
val jarPath: URL
|
||||
val cordappClasses: List<String>
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.composite.CompositeSignaturesWithKeys
|
||||
import net.corda.core.serialization.deserialize
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.security.*
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.core.crypto.composite
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
|
||||
/**
|
@ -2,8 +2,8 @@ package net.corda.core.internal.cordapp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
@ -14,7 +14,7 @@ data class CordappImpl(
|
||||
override val rpcFlows: List<Class<out FlowLogic<*>>>,
|
||||
override val schedulableFlows: List<Class<out FlowLogic<*>>>,
|
||||
override val services: List<Class<out SerializeAsToken>>,
|
||||
override val plugins: List<CordaPluginRegistry>,
|
||||
override val serializationWhitelists: List<SerializationWhitelist>,
|
||||
override val customSchemas: Set<MappedSchema>,
|
||||
override val jarPath: URL) : Cordapp {
|
||||
override val name: String = File(jarPath.toURI()).name.removeSuffix(".jar")
|
||||
@ -24,5 +24,5 @@ data class CordappImpl(
|
||||
*
|
||||
* TODO: Also add [SchedulableFlow] as a Cordapp class
|
||||
*/
|
||||
override val cordappClasses = ((rpcFlows + initiatedFlows + services + plugins.map { javaClass }).map { it.name } + contractClassNames)
|
||||
override val cordappClasses = ((rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass }).map { it.name } + contractClassNames)
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
package net.corda.core.node
|
||||
|
||||
import net.corda.core.serialization.SerializationCustomization
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
abstract class CordaPluginRegistry {
|
||||
/**
|
||||
* Optionally whitelist types for use in object serialization, as we lock down the types that can be serialized.
|
||||
*
|
||||
* For example, if you add a new [net.corda.core.contracts.ContractState] it needs to be whitelisted. You can do that
|
||||
* either by adding the [net.corda.core.serialization.CordaSerializable] annotation or via this method.
|
||||
**
|
||||
* @return true if you register types, otherwise you will be filtered out of the list of plugins considered in future.
|
||||
*/
|
||||
open fun customizeSerialization(custom: SerializationCustomization): Boolean = false
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package net.corda.core.serialization
|
||||
|
||||
interface SerializationCustomization {
|
||||
fun addToWhitelist(vararg types: Class<*>)
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package net.corda.core.serialization
|
||||
|
||||
/**
|
||||
* Provide a subclass of this via the [java.util.ServiceLoader] mechanism to be able to whitelist types for
|
||||
* serialisation that you cannot otherwise annotate. The name of the class must appear in a text file on the
|
||||
* classpath under the path META-INF/services/net.corda.core.serialization.SerializationWhitelist
|
||||
*/
|
||||
interface SerializationWhitelist {
|
||||
/**
|
||||
* Optionally whitelist types for use in object serialization, as we lock down the types that can be serialized.
|
||||
*
|
||||
* For example, if you add a new [net.corda.core.contracts.ContractState] it needs to be whitelisted. You can do that
|
||||
* either by adding the [net.corda.core.serialization.CordaSerializable] annotation or via this method.
|
||||
*/
|
||||
val whitelist: List<Class<*>>
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.CompositeKey.NodeAndWeight
|
||||
import net.corda.core.crypto.composite.CompositeSignaturesWithKeys
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.internal.declaredField
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.internal.cert
|
||||
import net.corda.core.utilities.toBase58String
|
||||
import net.corda.node.utilities.*
|
||||
import net.corda.testing.TestDependencyInjectionBase
|
||||
|
@ -24,6 +24,10 @@ RPC client interface to Corda, for use both by user-facing client and integratio
|
||||
|
||||
Internal, do not use. These APIs and implementations which are currently being revised and are subject to future change.
|
||||
|
||||
# Package net.corda.core
|
||||
|
||||
Exception types and some utilities for working with observables and futures.
|
||||
|
||||
# Package net.corda.core.cordapp
|
||||
|
||||
This package contains the interface to CorDapps from within a node. A CorDapp can access its own context by using
|
||||
@ -60,10 +64,6 @@ processes such as handling fixing of interest rate swaps.
|
||||
|
||||
Data classes which model different forms of identity (potentially with supporting evidence) for legal entities and services.
|
||||
|
||||
# Package net.corda.core.internal
|
||||
|
||||
Internal, do not use. These APIs and implementations which are currently being revised and are subject to future change.
|
||||
|
||||
# Package net.corda.core.messaging
|
||||
|
||||
Data types used by the Corda messaging layer to manage state of messaging and sessions between nodes.
|
||||
|
@ -65,9 +65,11 @@ Release 1.0
|
||||
* About half of the code in test-utils has been moved to a new module ``node-driver``,
|
||||
and the test scope modules are now located in a ``testing`` directory.
|
||||
|
||||
* Removed `requireSchemas` CordaPluginRegistry configuration item.
|
||||
Custom schemas are now automatically located using classpath scanning for deployed CorDapps.
|
||||
Improved support for testing custom schemas in MockNode and MockServices using explicit registration.
|
||||
* CordaPluginRegistry has been renamed to SerializationWhitelist and moved to the net.corda.core.serialization
|
||||
package. The API for whitelisting types that can't be annotated was slightly simplified. This class used to contain
|
||||
many things, but as we switched to annotations and classpath scanning over time it hollowed out until this was
|
||||
the only functionality left. You also need to rename your services resource file to the new class name.
|
||||
An associated property on ``MockNode`` was renamed from ``testPluginRegistries`` to ``testSerializationWhitelists``.
|
||||
|
||||
* Contract Upgrades: deprecated RPC authorisation / deauthorisation API calls in favour of equivalent flows in ContractUpgradeFlow.
|
||||
Implemented contract upgrade persistence using JDBC backed persistent map.
|
||||
|
@ -4,9 +4,8 @@ import net.corda.core.contracts.Amount
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultQueryBy
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.SerializationCustomization
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
@ -16,9 +15,9 @@ import net.corda.finance.flows.CashExitFlow
|
||||
import net.corda.finance.flows.CashIssueFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.testing.ALICE
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.driver.driver
|
||||
@ -142,12 +141,8 @@ data class ExampleRPCValue(val foo: String)
|
||||
@CordaSerializable
|
||||
data class ExampleRPCValue2(val bar: Int)
|
||||
|
||||
class ExampleRPCCordaPluginRegistry : CordaPluginRegistry() {
|
||||
override fun customizeSerialization(custom: SerializationCustomization): Boolean {
|
||||
// Add classes like this.
|
||||
custom.addToWhitelist(ExampleRPCValue::class.java)
|
||||
// You should return true, otherwise your plugin will be ignored for registering classes with Kryo.
|
||||
return true
|
||||
}
|
||||
class ExampleRPCSerializationWhitelist : SerializationWhitelist {
|
||||
// Add classes like this.
|
||||
override val whitelist = listOf(ExampleRPCValue::class.java)
|
||||
}
|
||||
// END 7
|
||||
|
@ -277,40 +277,9 @@ will propagate to the other side. Any other exception will not propagate.
|
||||
|
||||
Taking a step back, we mentioned that the other side has to accept the session request for there to be a communication
|
||||
channel. A node accepts a session request if it has registered the flow type (the fully-qualified class name) that is
|
||||
making the request - each session initiation includes the initiating flow type. The registration is done by a CorDapp
|
||||
which has made available the particular flow communication, using ``PluginServiceHub.registerServiceFlow``. This method
|
||||
specifies a flow factory for generating the counter-flow to any given initiating flow. If this registration doesn't exist
|
||||
then no further communication takes place and the initiating flow ends with an exception.
|
||||
|
||||
Going back to our buyer and seller flows, we need a way to initiate communication between the two. This is typically done
|
||||
with one side started manually using the ``startFlowDynamic`` RPC and this initiates the counter-flow on the other side.
|
||||
In this case it doesn't matter which flow is the initiator and which is the initiated. If we choose the seller side as
|
||||
the initiator then the buyer side would need to register their flow, perhaps with something like:
|
||||
|
||||
.. container:: codeset
|
||||
|
||||
.. sourcecode:: kotlin
|
||||
|
||||
class TwoPartyTradeFlowPlugin : CordaPluginRegistry() {
|
||||
override val servicePlugins = listOf(Function(TwoPartyTradeFlowService::Service))
|
||||
}
|
||||
|
||||
object TwoPartyTradeFlowService {
|
||||
class Service(services: PluginServiceHub) {
|
||||
init {
|
||||
services.registerServiceFlow(TwoPartyTradeFlow.Seller::class.java) {
|
||||
TwoPartyTradeFlow.Buyer(
|
||||
it,
|
||||
notary = services.networkMapCache.notaryIdentities[0].party,
|
||||
acceptablePrice = TODO(),
|
||||
typeToBuy = TODO())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This is telling the buyer node to fire up an instance of ``TwoPartyTradeFlow.Buyer`` (the code in the lambda) when
|
||||
they receive a message from the initiating seller side of the flow (``TwoPartyTradeFlow.Seller::class.java``).
|
||||
making the request - each session initiation includes the initiating flow type. The *initiated* (server) flow must name the
|
||||
*initiating* (client) flow using the ``@InitiatedBy`` annotation and passing the class name that will be starting the
|
||||
flow session as the annotation parameter.
|
||||
|
||||
.. _subflows:
|
||||
|
||||
|
@ -44,7 +44,7 @@ The ``src`` directory of the Template CorDapp, where we define our CorDapp's sou
|
||||
│ └── resources
|
||||
│ ├── META-INF
|
||||
│ │ └── services
|
||||
│ │ ├── net.corda.core.node.CordaPluginRegistry
|
||||
│ │ ├── net.corda.core.serialization.SerializationWhitelist
|
||||
│ │ └── net.corda.webserver.services.WebServerPluginRegistry
|
||||
│ ├── certificates
|
||||
│ │ ├── sslkeystore.jks
|
||||
@ -58,40 +58,4 @@ The ``src`` directory of the Template CorDapp, where we define our CorDapp's sou
|
||||
└── com
|
||||
└── template
|
||||
└── contract
|
||||
└── TemplateTests.java
|
||||
|
||||
Defining plugins
|
||||
----------------
|
||||
Your CorDapp may need to define two types of plugins:
|
||||
|
||||
* ``CordaPluginRegistry`` subclasses, which define additional serializable classes
|
||||
* ``WebServerPluginRegistry`` subclasses, which define the APIs and static web content served by your CorDapp
|
||||
|
||||
The fully-qualified class path of each ``CordaPluginRegistry`` subclass must then be added to the
|
||||
``net.corda.core.node.CordaPluginRegistry`` file in the CorDapp's ``resources/META-INF/services`` folder. Meanwhile,
|
||||
the fully-qualified class path of each ``WebServerPluginRegistry`` subclass must be added to the
|
||||
``net.corda.webserver.services.WebServerPluginRegistry`` file, again in the CorDapp's ``resources/META-INF/services``
|
||||
folder.
|
||||
|
||||
The ``CordaPluginRegistry`` class defines the following:
|
||||
|
||||
* ``customizeSerialization``, which can be overridden to provide a list of the classes to be whitelisted for object
|
||||
serialisation, over and above those tagged with the ``@CordaSerializable`` annotation. See :doc:`serialization`
|
||||
|
||||
The ``WebServerPluginRegistry`` class defines the following:
|
||||
|
||||
* ``webApis``, which can be overridden to return a list of JAX-RS annotated REST access classes. These classes will be
|
||||
constructed by the bundled web server and must have a single argument constructor taking a ``CordaRPCOps`` object.
|
||||
This will allow the API to communicate with the node process via the RPC interface. These web APIs will not be
|
||||
available if the bundled web server is not started
|
||||
|
||||
* ``staticServeDirs``, which can be overridden to map static web content to virtual paths and allow simple web demos to
|
||||
be distributed within the CorDapp jars. This static content will not be available if the bundled web server is not
|
||||
started
|
||||
|
||||
* ``customizeJSONSerialization``, which can be overridden to register custom JSON serializers if required by the REST api.
|
||||
|
||||
* The static web content itself should be placed inside the ``src/main/resources`` directory
|
||||
|
||||
To learn about how to use gradle to build your cordapp against Corda and generate an artifact please read
|
||||
:doc:`cordapp-build-systems`.
|
||||
└── TemplateTests.java
|
@ -1,5 +0,0 @@
|
||||
package net.corda.finance.contracts.isolated
|
||||
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
|
||||
class IsolatedPlugin : CordaPluginRegistry()
|
@ -1 +0,0 @@
|
||||
net.corda.finance.contracts.isolated.IsolatedPlugin
|
@ -2,7 +2,6 @@
|
||||
|
||||
package net.corda.nodeapi.internal.serialization
|
||||
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.*
|
||||
import net.corda.core.utilities.ByteSequence
|
||||
import net.corda.nodeapi.internal.serialization.amqp.AmqpHeaderV1_0
|
||||
@ -14,12 +13,6 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
val AMQP_ENABLED get() = SerializationDefaults.P2P_CONTEXT.preferredSerializationVersion == AmqpHeaderV1_0
|
||||
|
||||
class AMQPSerializationCustomization(val factory: SerializerFactory) : SerializationCustomization {
|
||||
override fun addToWhitelist(vararg types: Class<*>) {
|
||||
factory.addToWhitelist(*types)
|
||||
}
|
||||
}
|
||||
|
||||
fun SerializerFactory.addToWhitelist(vararg types: Class<*>) {
|
||||
require(types.toSet().size == types.size) {
|
||||
val duplicates = types.toMutableList()
|
||||
@ -33,12 +26,12 @@ fun SerializerFactory.addToWhitelist(vararg types: Class<*>) {
|
||||
|
||||
abstract class AbstractAMQPSerializationScheme : SerializationScheme {
|
||||
internal companion object {
|
||||
private val pluginRegistries: List<CordaPluginRegistry> by lazy {
|
||||
ServiceLoader.load(CordaPluginRegistry::class.java, this::class.java.classLoader).toList()
|
||||
private val serializationWhitelists: List<SerializationWhitelist> by lazy {
|
||||
ServiceLoader.load(SerializationWhitelist::class.java, this::class.java.classLoader).toList() + DefaultWhitelist
|
||||
}
|
||||
|
||||
fun registerCustomSerializers(factory: SerializerFactory) {
|
||||
factory.apply {
|
||||
with(factory) {
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer)
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(this))
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.X500NameSerializer)
|
||||
@ -67,8 +60,8 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme {
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(this))
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this))
|
||||
}
|
||||
val customizer = AMQPSerializationCustomization(factory)
|
||||
pluginRegistries.forEach { it.customizeSerialization(customizer) }
|
||||
for (whitelistProvider in serializationWhitelists)
|
||||
factory.addToWhitelist(*whitelistProvider.whitelist.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ class GlobalTransientClassWhiteList(val delegate: ClassWhitelist) : MutableClass
|
||||
}
|
||||
|
||||
/**
|
||||
* A whitelist that can be customised via the [net.corda.core.node.CordaPluginRegistry], since implements [MutableClassWhitelist].
|
||||
* A whitelist that can be customised via the [net.corda.core.node.SerializationWhitelist], since implements [MutableClassWhitelist].
|
||||
*/
|
||||
class TransientClassWhiteList(val delegate: ClassWhitelist) : MutableClassWhitelist, ClassWhitelist by delegate {
|
||||
val whitelist: MutableSet<String> = Collections.synchronizedSet(mutableSetOf())
|
||||
|
@ -15,7 +15,7 @@ import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.PrivacySalt
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SerializedBytes
|
||||
import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
@ -49,8 +49,8 @@ import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
object DefaultKryoCustomizer {
|
||||
private val pluginRegistries: List<CordaPluginRegistry> by lazy {
|
||||
ServiceLoader.load(CordaPluginRegistry::class.java, this.javaClass.classLoader).toList()
|
||||
private val serializationWhitelists: List<SerializationWhitelist> by lazy {
|
||||
ServiceLoader.load(SerializationWhitelist::class.java, this.javaClass.classLoader).toList() + DefaultWhitelist
|
||||
}
|
||||
|
||||
fun customize(kryo: Kryo): Kryo {
|
||||
@ -122,8 +122,17 @@ object DefaultKryoCustomizer {
|
||||
register(java.lang.invoke.SerializedLambda::class.java)
|
||||
register(ClosureSerializer.Closure::class.java, CordaClosureBlacklistSerializer)
|
||||
|
||||
val customization = KryoSerializationCustomization(this)
|
||||
pluginRegistries.forEach { it.customizeSerialization(customization) }
|
||||
for (whitelistProvider in serializationWhitelists) {
|
||||
val types = whitelistProvider.whitelist
|
||||
require(types.toSet().size == types.size) {
|
||||
val duplicates = types.toMutableList()
|
||||
types.toSet().forEach { duplicates -= it }
|
||||
"Cannot add duplicate classes to the whitelist ($duplicates)."
|
||||
}
|
||||
for (type in types) {
|
||||
((kryo.classResolver as? CordaClassResolver)?.whitelist as? MutableClassWhitelist)?.add(type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
package net.corda.nodeapi.internal.serialization
|
||||
|
||||
import com.esotericsoftware.kryo.KryoException
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.SerializationCustomization
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import org.apache.activemq.artemis.api.core.SimpleString
|
||||
import rx.Notification
|
||||
@ -12,10 +11,9 @@ import java.util.*
|
||||
/**
|
||||
* NOTE: We do not whitelist [HashMap] or [HashSet] since they are unstable under serialization.
|
||||
*/
|
||||
class DefaultWhitelist : CordaPluginRegistry() {
|
||||
override fun customizeSerialization(custom: SerializationCustomization): Boolean {
|
||||
custom.apply {
|
||||
addToWhitelist(Array<Any>(0, {}).javaClass,
|
||||
object DefaultWhitelist : SerializationWhitelist {
|
||||
override val whitelist =
|
||||
listOf(Array<Any>(0, {}).javaClass,
|
||||
Notification::class.java,
|
||||
Notification.Kind::class.java,
|
||||
ArrayList::class.java,
|
||||
@ -60,8 +58,6 @@ class DefaultWhitelist : CordaPluginRegistry() {
|
||||
java.util.LinkedHashMap::class.java,
|
||||
BitSet::class.java,
|
||||
OnErrorNotImplementedException::class.java,
|
||||
StackTraceElement::class.java)
|
||||
}
|
||||
return true
|
||||
}
|
||||
StackTraceElement::class.java
|
||||
)
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package net.corda.nodeapi.internal.serialization
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo
|
||||
import net.corda.core.serialization.SerializationCustomization
|
||||
|
||||
class KryoSerializationCustomization(val kryo: Kryo) : SerializationCustomization {
|
||||
override fun addToWhitelist(vararg types: Class<*>) {
|
||||
require(types.toSet().size == types.size) {
|
||||
val duplicates = types.toMutableList()
|
||||
types.toSet().forEach { duplicates -= it }
|
||||
"Cannot add duplicate classes to the whitelist ($duplicates)."
|
||||
}
|
||||
for (type in types) {
|
||||
((kryo.classResolver as? CordaClassResolver)?.whitelist as? MutableClassWhitelist)?.add(type)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
|
||||
net.corda.nodeapi.internal.serialization.DefaultWhitelist
|
@ -23,12 +23,12 @@ import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.ServiceHub
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.node.services.NetworkMapCache.MapChange
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -70,7 +70,6 @@ import net.corda.node.utilities.*
|
||||
import net.corda.node.utilities.AddOrRemove.ADD
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.nodeapi.internal.ServiceType
|
||||
import net.corda.nodeapi.internal.serialization.DefaultWhitelist
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||
import org.slf4j.Logger
|
||||
import rx.Observable
|
||||
@ -160,8 +159,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
CordaX500Name.build(cert.subjectX500Principal).copy(commonName = null)
|
||||
}
|
||||
|
||||
open val pluginRegistries: List<CordaPluginRegistry> by lazy {
|
||||
cordappProvider.cordapps.flatMap { it.plugins } + DefaultWhitelist()
|
||||
open val serializationWhitelists: List<SerializationWhitelist> by lazy {
|
||||
cordappProvider.cordapps.flatMap { it.serializationWhitelists }
|
||||
}
|
||||
|
||||
/** Set to non-null once [start] has been successfully called. */
|
||||
|
@ -7,12 +7,12 @@ import net.corda.core.internal.*
|
||||
import net.corda.core.internal.concurrent.thenMatch
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.*
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.transactions.bftSMaRtSerialFilter
|
||||
import net.corda.node.shell.InteractiveShell
|
||||
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
||||
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.nodeapi.internal.addShutdownHook
|
||||
import org.fusesource.jansi.Ansi
|
||||
import org.fusesource.jansi.AnsiConsole
|
||||
@ -264,12 +264,6 @@ open class NodeStartup(val args: Array<String>) {
|
||||
if (it.isNotEmpty()) Node.printBasicNodeInfo("Providing additional services", it.joinToString())
|
||||
}
|
||||
Node.printBasicNodeInfo("Loaded CorDapps", node.cordappProvider.cordapps.map { it.name }.joinToString())
|
||||
val plugins = node.pluginRegistries
|
||||
.map { it.javaClass.name }
|
||||
.filterNot { it.startsWith("net.corda.node.") || it.startsWith("net.corda.core.") || it.startsWith("net.corda.nodeapi.") }
|
||||
.map { it.substringBefore('$') }
|
||||
if (plugins.isNotEmpty())
|
||||
Node.printBasicNodeInfo("Loaded plugins", plugins.joinToString())
|
||||
}
|
||||
|
||||
open fun drawBanner(versionInfo: VersionInfo) {
|
||||
|
@ -8,12 +8,13 @@ import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.services.CordaService
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.internal.classloading.requireAnnotation
|
||||
import net.corda.nodeapi.internal.serialization.DefaultWhitelist
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.reflect.Modifier
|
||||
@ -222,10 +223,10 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
|
||||
return (scanResult.getNamesOfClassesImplementing(Contract::class.java) + scanResult.getNamesOfClassesImplementing(UpgradedContract::class.java)).distinct()
|
||||
}
|
||||
|
||||
private fun findPlugins(cordappJarPath: URL): List<CordaPluginRegistry> {
|
||||
return ServiceLoader.load(CordaPluginRegistry::class.java, URLClassLoader(arrayOf(cordappJarPath), appClassLoader)).toList().filter {
|
||||
private fun findPlugins(cordappJarPath: URL): List<SerializationWhitelist> {
|
||||
return ServiceLoader.load(SerializationWhitelist::class.java, URLClassLoader(arrayOf(cordappJarPath), appClassLoader)).toList().filter {
|
||||
cordappJarPath == it.javaClass.protectionDomain.codeSource.location
|
||||
}
|
||||
} + DefaultWhitelist // Always add the DefaultWhitelist to the whitelist for an app.
|
||||
}
|
||||
|
||||
private fun findCustomSchemas(scanResult: ScanResult): Set<MappedSchema> {
|
||||
|
@ -55,8 +55,6 @@ class CordappLoaderTest {
|
||||
assertThat(actualCordapp.rpcFlows).isEmpty()
|
||||
assertThat(actualCordapp.schedulableFlows).isEmpty()
|
||||
assertThat(actualCordapp.services).isEmpty()
|
||||
assertThat(actualCordapp.plugins).hasSize(1)
|
||||
assertThat(actualCordapp.plugins.first().javaClass.name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedPlugin")
|
||||
assertThat(actualCordapp.jarPath).isEqualTo(isolatedJAR)
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,2 @@
|
||||
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
|
||||
net.corda.irs.plugin.IRSPlugin
|
||||
net.corda.irs.plugin.IRSDemoPlugin
|
@ -1,7 +1,7 @@
|
||||
package net.corda.vega.plugin
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.finance.plugin.registerFinanceJSONMappers
|
||||
import net.corda.vega.api.PortfolioApi
|
||||
import net.corda.webserver.services.WebServerPluginRegistry
|
||||
@ -9,7 +9,7 @@ import java.util.function.Function
|
||||
|
||||
/**
|
||||
* [SimmService] is the object that makes available the flows and services for the Simm agreement / evaluation flow.
|
||||
* It is loaded via discovery - see [CordaPluginRegistry].
|
||||
* It is loaded via discovery - see [SerializationWhitelist].
|
||||
* It is also the object that enables a human usable web service for demo purpose
|
||||
* It is loaded via discovery see [WebServerPluginRegistry].
|
||||
*/
|
||||
|
@ -10,35 +10,30 @@ import com.opengamma.strata.market.curve.CurveName
|
||||
import com.opengamma.strata.market.param.CurrencyParameterSensitivities
|
||||
import com.opengamma.strata.market.param.CurrencyParameterSensitivity
|
||||
import com.opengamma.strata.market.param.TenorDateParameterMetadata
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.serialization.SerializationCustomization
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.vega.analytics.CordaMarketData
|
||||
import net.corda.vega.analytics.InitialMarginTriple
|
||||
import net.corda.webserver.services.WebServerPluginRegistry
|
||||
|
||||
/**
|
||||
* [SimmService] is the object that makes available the flows and services for the Simm agreement / evaluation flow.
|
||||
* It is loaded via discovery - see [CordaPluginRegistry].
|
||||
* It is loaded via discovery - see [SerializationWhitelist].
|
||||
* It is also the object that enables a human usable web service for demo purpose
|
||||
* It is loaded via discovery see [WebServerPluginRegistry].
|
||||
*/
|
||||
class SimmPluginRegistry : CordaPluginRegistry() {
|
||||
override fun customizeSerialization(custom: SerializationCustomization): Boolean {
|
||||
custom.apply {
|
||||
// OpenGamma classes.
|
||||
addToWhitelist(MultiCurrencyAmount::class.java,
|
||||
Ordering.natural<Comparable<Any>>().javaClass,
|
||||
CurrencyAmount::class.java,
|
||||
Currency::class.java,
|
||||
InitialMarginTriple::class.java,
|
||||
CordaMarketData::class.java,
|
||||
CurrencyParameterSensitivities::class.java,
|
||||
CurrencyParameterSensitivity::class.java,
|
||||
DoubleArray::class.java,
|
||||
CurveName::class.java,
|
||||
TenorDateParameterMetadata::class.java,
|
||||
Tenor::class.java)
|
||||
}
|
||||
return true
|
||||
}
|
||||
class SimmPluginRegistry : SerializationWhitelist {
|
||||
override val whitelist = listOf(
|
||||
MultiCurrencyAmount::class.java,
|
||||
Ordering.natural<Comparable<Any>>().javaClass,
|
||||
CurrencyAmount::class.java,
|
||||
Currency::class.java,
|
||||
InitialMarginTriple::class.java,
|
||||
CordaMarketData::class.java,
|
||||
CurrencyParameterSensitivities::class.java,
|
||||
CurrencyParameterSensitivity::class.java,
|
||||
DoubleArray::class.java,
|
||||
CurveName::class.java,
|
||||
TenorDateParameterMetadata::class.java,
|
||||
Tenor::class.java
|
||||
)
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
|
||||
net.corda.vega.plugin.SimmPluginRegistry
|
@ -0,0 +1 @@
|
||||
net.corda.vega.plugin.SimmPluginRegistry
|
@ -15,26 +15,32 @@ import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.messaging.MessageRecipients
|
||||
import net.corda.core.messaging.RPCOps
|
||||
import net.corda.core.messaging.SingleMessageRecipient
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.node.services.IdentityService
|
||||
import net.corda.core.node.services.KeyManagementService
|
||||
import net.corda.core.node.services.NetworkMapCache
|
||||
import net.corda.core.node.services.NotaryService
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.finance.utils.WorldMapLocation
|
||||
import net.corda.node.internal.AbstractNode
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.nodeapi.internal.ServiceType
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.identity.PersistentIdentityService
|
||||
import net.corda.node.services.keys.E2ETestKeyManagementService
|
||||
import net.corda.node.services.messaging.MessagingService
|
||||
import net.corda.node.services.network.InMemoryNetworkMapService
|
||||
import net.corda.node.services.network.NetworkMapService
|
||||
import net.corda.node.services.transactions.*
|
||||
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
|
||||
import net.corda.node.services.transactions.BFTSMaRt
|
||||
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
|
||||
import net.corda.node.services.transactions.ValidatingNotaryService
|
||||
import net.corda.node.utilities.AffinityExecutor
|
||||
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
|
||||
import net.corda.node.utilities.CertificateAndKeyPair
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.nodeapi.internal.ServiceType
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import org.apache.activemq.artemis.utils.ReusableLatch
|
||||
@ -231,11 +237,11 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false,
|
||||
|
||||
override fun myAddresses() = emptyList<NetworkHostAndPort>()
|
||||
|
||||
// Allow unit tests to modify the plugin list before the node start,
|
||||
// so they don't have to ServiceLoad test plugins into all unit tests.
|
||||
val testPluginRegistries by lazy { super.pluginRegistries.toMutableList() }
|
||||
override val pluginRegistries: List<CordaPluginRegistry>
|
||||
get() = testPluginRegistries
|
||||
// Allow unit tests to modify the serialization whitelist list before the node start,
|
||||
// so they don't have to ServiceLoad test whitelists into all unit tests.
|
||||
val testSerializationWhitelists by lazy { super.serializationWhitelists.toMutableList() }
|
||||
override val serializationWhitelists: List<SerializationWhitelist>
|
||||
get() = testSerializationWhitelists
|
||||
|
||||
// This does not indirect through the NodeInfo object so it can be called before the node is started.
|
||||
// It is used from the network visualiser tool.
|
||||
|
Loading…
Reference in New Issue
Block a user