* 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:
Rick Parker 2017-09-29 15:45:19 +01:00 committed by Mike Hearn
parent 12982b3034
commit 9a16011448
31 changed files with 114 additions and 232 deletions

View File

@ -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>

View File

@ -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.*

View File

@ -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
/**

View File

@ -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)
}

View File

@ -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
}

View File

@ -1,6 +0,0 @@
package net.corda.core.serialization
interface SerializationCustomization {
fun addToWhitelist(vararg types: Class<*>)
}

View File

@ -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<*>>
}

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -1,5 +0,0 @@
package net.corda.finance.contracts.isolated
import net.corda.core.node.CordaPluginRegistry
class IsolatedPlugin : CordaPluginRegistry()

View File

@ -1 +0,0 @@
net.corda.finance.contracts.isolated.IsolatedPlugin

View File

@ -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())
}
}

View File

@ -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())

View File

@ -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)
}
}
}
}

View File

@ -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
)
}

View File

@ -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)
}
}
}

View File

@ -1,2 +0,0 @@
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
net.corda.nodeapi.internal.serialization.DefaultWhitelist

View File

@ -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. */

View File

@ -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) {

View File

@ -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> {

View File

@ -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)
}

View File

@ -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

View File

@ -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].
*/

View File

@ -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
)
}

View File

@ -1,2 +0,0 @@
# Register a ServiceLoader service extending from net.corda.core.node.CordaPluginRegistry
net.corda.vega.plugin.SimmPluginRegistry

View File

@ -0,0 +1 @@
net.corda.vega.plugin.SimmPluginRegistry

View File

@ -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.