2016-11-25 14:29:13 +00:00
|
|
|
The Corda plugin framework
|
2016-11-22 11:57:11 +00:00
|
|
|
==========================
|
|
|
|
|
|
|
|
The intention is that Corda is a common platform, which will be extended
|
|
|
|
by numerous application extensions (CorDapps). These extensions will
|
|
|
|
package together all of the Corda contract code, state structures,
|
|
|
|
protocols/flows to create and modify state as well as RPC extensions for
|
|
|
|
node clients. Details of writing these CorDapps is given elsewhere
|
|
|
|
:doc:`creating-a-cordapp`.
|
|
|
|
|
|
|
|
To enable these plugins to register dynamically with the Corda framework
|
|
|
|
the node uses the Java ``ServiceLoader`` to locate and load the plugin
|
|
|
|
components during the ``AbstractNode.start`` call. Therefore,
|
|
|
|
to be recognised as a plugin the component must:
|
|
|
|
|
|
|
|
1. Include a default constructable class extending from
|
|
|
|
``net.corda.core.node.CordaPluginRegistry`` which overrides the relevant
|
|
|
|
registration methods.
|
|
|
|
|
|
|
|
2. Include a resource file named
|
|
|
|
``net.corda.core.node.CordaPluginRegistry`` in the ``META-INF.services``
|
|
|
|
path. This must include a line containing the fully qualified name of
|
|
|
|
the ``CordaPluginRegistry`` implementation class. Multiple plugin
|
|
|
|
registries are allowed in this file if desired.
|
|
|
|
|
|
|
|
3. The plugin component must be on the classpath. In the normal use this
|
|
|
|
means that it should be present within the plugins subfolder of the
|
|
|
|
node's workspace.
|
|
|
|
|
|
|
|
4. As a plugin the registered components are then allowed access to some
|
|
|
|
of the node internal subsystems.
|
|
|
|
|
|
|
|
5. The overridden properties on the registry class information about the different
|
|
|
|
extensions to be created, or registered at startup. In particular:
|
|
|
|
|
|
|
|
a. The ``webApis`` property is a list of JAX-RS annotated REST access
|
2017-01-25 13:45:39 +00:00
|
|
|
classes. These classes will be constructed by the bundled web server
|
2017-01-30 12:05:22 +00:00
|
|
|
and must have a single argument constructor taking a ``CordaRPCOps``
|
2017-01-25 13:45:39 +00:00
|
|
|
reference. This will allow it 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.
|
2016-11-22 11:57:11 +00:00
|
|
|
|
|
|
|
b. The ``staticServeDirs`` property maps static web content to virtual
|
|
|
|
paths and allows simple web demos to be distributed within the CorDapp
|
2017-01-25 13:45:39 +00:00
|
|
|
jars. These static serving directories will not be available if the
|
|
|
|
bundled web server is not started.
|
2016-11-22 11:57:11 +00:00
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
c. The ``servicePlugins`` property returns a list of classes which will
|
2016-11-22 11:57:11 +00:00
|
|
|
be instantiated once during the ``AbstractNode.start`` call. These
|
|
|
|
classes must provide a single argument constructor which will receive a
|
2016-11-25 13:35:05 +00:00
|
|
|
``PluginServiceHub`` reference. They must also extend the abstract class
|
|
|
|
``SingletonSerializeAsToken`` which ensures that if any reference to your
|
|
|
|
service is captured in a flow checkpoint (i.e. serialized by Kryo as
|
|
|
|
part of Quasar checkpoints, either on the stack or by reference within
|
|
|
|
your flows) it is stored as a simple token representing your service.
|
|
|
|
When checkpoints are restored, after a node restart for example,
|
|
|
|
the latest instance of the service will be substituted back in place of
|
|
|
|
the token stored in the checkpoint.
|
2016-11-22 11:57:11 +00:00
|
|
|
|
2017-04-26 09:11:10 +00:00
|
|
|
i. Firstly, they can call ``PluginServiceHub.registerServiceFlow`` and
|
2016-11-22 11:57:11 +00:00
|
|
|
register flows that will be initiated locally in response to remote flow
|
|
|
|
requests.
|
|
|
|
|
|
|
|
ii. Second, the service can hold a long lived reference to the
|
|
|
|
PluginServiceHub and to other private data, so the service can be used
|
|
|
|
to provide Oracle functionality. This Oracle functionality would
|
|
|
|
typically be exposed to other nodes by flows which are given a reference
|
|
|
|
to the service plugin when initiated (as defined by the
|
2017-04-26 09:11:10 +00:00
|
|
|
``registerServiceFlow`` call). The flow can then call into functions
|
2016-11-22 11:57:11 +00:00
|
|
|
on the plugin service singleton. Note, care should be taken to not allow
|
2016-11-25 13:35:05 +00:00
|
|
|
flows to hold references to fields which are not
|
2016-11-22 11:57:11 +00:00
|
|
|
also ``SingletonSerializeAsToken``, otherwise Quasar suspension in the
|
|
|
|
``StateMachineManager`` will fail with exceptions. An example oracle can
|
|
|
|
be seen in ``NodeInterestRates.kt`` in the irs-demo sample.
|
|
|
|
|
2017-04-26 09:11:10 +00:00
|
|
|
iii. The final use case for service plugins is that they can spawn threads, or register
|
2016-11-22 11:57:11 +00:00
|
|
|
to monitor vault updates. This allows them to provide long lived active
|
|
|
|
functions inside the node, for instance to initiate workflows when
|
|
|
|
certain conditions are met.
|
|
|
|
|
2017-05-10 10:28:25 +00:00
|
|
|
d. The ``customizeSerialization`` function allows classes to be whitelisted
|
2017-02-28 08:12:18 +00:00
|
|
|
for object serialisation, over and above those tagged with the ``@CordaSerializable``
|
|
|
|
annotation. In general the annotation should be preferred. For
|
|
|
|
instance new state types will need to be explicitly registered. This will be called at
|
|
|
|
various points on various threads and needs to be stable and thread safe. See
|
|
|
|
:doc:`serialization`.
|
2016-11-22 11:57:11 +00:00
|
|
|
|