From 6ecdf5a94645bb8e982a1560c8b64f57738142a5 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Tue, 22 Nov 2016 11:57:11 +0000 Subject: [PATCH] Document on plugin loading framework and a tiny tweak on logging. Word wrap document. Change protocol to flow. Try to improve plugin discussion based on PR comments. add comma --- docs/source/corda-plugins.rst | 98 +++++++++++++++++++++++++++++ docs/source/index.rst | 3 +- docs/source/node-administration.rst | 11 ++-- 3 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 docs/source/corda-plugins.rst diff --git a/docs/source/corda-plugins.rst b/docs/source/corda-plugins.rst new file mode 100644 index 0000000000..bddc9cce4b --- /dev/null +++ b/docs/source/corda-plugins.rst @@ -0,0 +1,98 @@ +The Corda Plugin Framework +========================== + +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 + classes. These classes will be constructed by the embedded web server + and must have a single argument constructor taking a ``ServiceHub`` + reference. This reference provides acccess to functions such as querying + for states through the ``VaultService`` interface, or access to the + ``NetworkMapCache`` to identify services on remote nodes. The framework will + provide a database transaction in scope during the lifetime of the web + call, so full access to database data is valid. Unlike + ``servicePlugins`` the ``webApis`` cannnot register new protocols, or + initiate threads. (N.B. The intent is to move the Web support into a + separate helper process using the RPC mechanism to control access.) + + b. The ``staticServeDirs`` property maps static web content to virtual + paths and allows simple web demos to be distributed within the CorDapp + jars. (N.B. The intent is to move the Web support into a separate helper + process using the RPC mechanism to control access.) + + c. The ``requiredFlows`` property is used to declare new protocols in + the plugin jar. Specifically the property must return a map with a key + naming each exposed top level flow class and a value which is a set + naming every parameter class that will be passed to the flow's + constructor. Standard ``java.lang.*`` and ``kotlin.*`` types do not need + to be included, but all other parameter types, or concrete interface + implementations need declaring. Declaring a specific flow in this map + white lists it for activation by the ``FlowLogicRefFactory``. White + listing is not strictly required for ``subFlows`` used internally, but + is required for any top level flow, or a flow which is invoked through + the scheduler. + + d. The ``servicePlugins`` property returns a list of classes which will + be instantiated once during the ``AbstractNode.start`` call. These + classes must provide a single argument constructor which will receive a + ``PluginServiceHub`` reference. These singleton instances are regarded + as trusted components and can be used for a number of purposes. + + i. Firstly, they can call ``PluginServiceHub.registerFlowInitiator`` and + 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 + ``registerFlowInitiator`` call). The flow can then call into functions + on the plugin service singleton. Note, care should be taken to not allow + flows to hold references to plugin services, or fields which are not + 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. + + iii. The final + use case for service plugins is that they can spawn threads, or register + 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. + + e. The ``registerRPCKryoTypes`` function allows custom Kryo serialisers + to be registered and whitelisted for the RPC client interface. For + instance new state types passed to flows started via RPC will need + to be explicitly registered. This will be called at various points on + various threads and needs to be stable and thread safe. + diff --git a/docs/source/index.rst b/docs/source/index.rst index 8da12fa870..6f95f71f04 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -49,6 +49,7 @@ Read on to learn: persistence node-administration corda-configuration-files + corda-plugins node-services .. toctree:: @@ -66,7 +67,7 @@ Read on to learn: tutorial-contract-clauses tutorial-test-dsl tutorial-clientrpc-api - flow-state-machines + protocol-state-machines oracles tutorial-attachments event-scheduling diff --git a/docs/source/node-administration.rst b/docs/source/node-administration.rst index 28651bc625..e950131de0 100644 --- a/docs/source/node-administration.rst +++ b/docs/source/node-administration.rst @@ -7,11 +7,14 @@ you can upload and download attachments, access a REST API and so on. Logging ------- -Logs are stored to the logs subdirectory of the node directory and are rotated from time to time. You can +In the default configuration logs are stored to the logs subdirectory of the node directory and are rotated from time to time. You can have logging printed to the console as well by passing the ``--log-to-console`` command line flag. Corda -uses the log4j2 framework to manage its logging, so you can also configure it in more detail by writing -a custom logging configuration file and passing ``-Dlog4j.configurationFile=my-config-file.xml`` on the -command line as well. +uses the SL4J logging façade which is configured with the log4j2 binding framework to manage its logging, +so you can also configure it in more detail by writing a custom log4j2 logging configuration file and passing ``-Dlog4j.configurationFile=my-config-file.xml`` +on the command line as well. The default configuration is copied during the build from ``config/dev/log4j2.xml``, or for the test sourceSet from ``config/test/log4j2.xml``. + +In corda code a logger is typically instantiated via the ``net.corda.core.utilities.loggerFor`` utility method which will create an SL4J ``Logger`` with a name based on the type parameter. +Also, available in ``net.corda.core.utilities``, are extension methods to take a lazily evaluated logging lambda for trace and debug level, which will not evaluate the lambda if the LogLevel threshold is higher. Database access ---------------