mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
Merged in clint-caplet (pull request #292)
Node server now loads plugins/cordapps from directory
This commit is contained in:
commit
4cb6d11e9f
28
build.gradle
28
build.gradle
@ -108,6 +108,7 @@ dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.2"
|
||||
compile 'com.squareup.okhttp3:okhttp:3.3.1'
|
||||
compile 'co.paralleluniverse:capsule:1.0.3'
|
||||
|
||||
// Unit testing helpers.
|
||||
testCompile 'junit:junit:4.12'
|
||||
@ -196,46 +197,49 @@ applicationDistribution.into("bin") {
|
||||
fileMode = 0755
|
||||
}
|
||||
|
||||
task createCapsule(type: FatCapsule, dependsOn: 'quasarScan') {
|
||||
task buildCordaJAR(type: FatCapsule, dependsOn: 'quasarScan') {
|
||||
applicationClass 'com.r3corda.node.MainKt'
|
||||
archiveName 'corda.jar'
|
||||
applicationSource = files(project.tasks.findByName('jar'), 'build/classes/main/CordaCaplet.class')
|
||||
|
||||
capsuleManifest {
|
||||
appClassPath = ["jolokia-agent-war-${project.ext.jolokia_version}.war"]
|
||||
systemProperties['log4j.configuration'] = 'log4j2.xml'
|
||||
javaAgents = ["quasar-core-${quasar_version}-jdk8.jar"]
|
||||
minJavaVersion = '1.8.0'
|
||||
caplets = ['CordaCaplet']
|
||||
}
|
||||
}
|
||||
|
||||
task createStandalone(dependsOn: 'createCapsule') << {
|
||||
task installTemplateNodes(dependsOn: 'buildCordaJAR') << {
|
||||
copy {
|
||||
from createCapsule.outputs.getFiles()
|
||||
from buildCordaJAR.outputs.getFiles()
|
||||
from 'config/dev/nameservernode.conf'
|
||||
into "${buildDir}/standalone/nameserver"
|
||||
into "${buildDir}/nodes/nameserver"
|
||||
rename 'nameservernode.conf', 'node.conf'
|
||||
}
|
||||
|
||||
copy {
|
||||
from createCapsule.outputs.getFiles()
|
||||
from buildCordaJAR.outputs.getFiles()
|
||||
from 'config/dev/generalnodea.conf'
|
||||
into "${buildDir}/standalone/nodea"
|
||||
into "${buildDir}/nodes/nodea"
|
||||
rename 'generalnodea.conf', 'node.conf'
|
||||
}
|
||||
|
||||
copy {
|
||||
from createCapsule.outputs.getFiles()
|
||||
from buildCordaJAR.outputs.getFiles()
|
||||
from 'config/dev/generalnodeb.conf'
|
||||
into "${buildDir}/standalone/nodeb"
|
||||
into "${buildDir}/nodes/nodeb"
|
||||
rename 'generalnodeb.conf', 'node.conf'
|
||||
}
|
||||
|
||||
delete("${buildDir}/standalone/runstandalone")
|
||||
def jarName = createCapsule.outputs.getFiles().getSingleFile().getName()
|
||||
delete("${buildDir}/nodes/runnodes")
|
||||
def jarName = buildCordaJAR.outputs.getFiles().getSingleFile().getName()
|
||||
copy {
|
||||
from "buildSrc/scripts/runstandalone"
|
||||
from "buildSrc/scripts/runnodes"
|
||||
filter { String line -> line.replace("JAR_NAME", jarName) }
|
||||
filter(org.apache.tools.ant.filters.FixCrLfFilter.class, eol: org.apache.tools.ant.filters.FixCrLfFilter.CrLf.newInstance("lf"))
|
||||
into "${buildDir}/standalone"
|
||||
into "${buildDir}/nodes"
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Creates three nodes. A network map and notary node and two regular nodes that can be extended with cordapps.
|
||||
|
||||
set -euo pipefail
|
||||
trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
|
||||
export CAPSULE_CACHE_DIR=cache
|
65
docs/source/creating-a-cordapp.rst
Normal file
65
docs/source/creating-a-cordapp.rst
Normal file
@ -0,0 +1,65 @@
|
||||
Creating a Cordapp
|
||||
==================
|
||||
|
||||
A Cordapp is an application that runs on the Corda platform using the platform APIs and plugin system. They are self
|
||||
contained in separate JARs from the node server JAR that are created and distributed.
|
||||
|
||||
App Plugins
|
||||
-----------
|
||||
|
||||
.. note:: Currently apps are only supported for JVM languages.
|
||||
|
||||
To create an app plugin you must you must extend from `CordaPluginRegistry`_. The JavaDoc contains
|
||||
specific details of the implementation, but you can extend the server in the following ways:
|
||||
|
||||
1. Required protocols: Specify which protocols will be whitelisted for use in your web APIs.
|
||||
2. Service plugins: Register your :ref:`services`.
|
||||
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.
|
||||
|
||||
Services
|
||||
--------
|
||||
|
||||
.. _services:
|
||||
|
||||
Services are classes which are constructed after the node has started. It is provided a `ServiceHubInternal`_ which
|
||||
allows a richer API than the `ServiceHub`_ exposed to contracts. It enables adding protocols, registering
|
||||
message handlers and more. The service does not run in a separate thread, so the only entry point to the service is during
|
||||
construction, where message handlers should be registered and threads started.
|
||||
|
||||
|
||||
Starting Nodes
|
||||
--------------
|
||||
|
||||
To use an app you must also have a node server. To create a node server run the gradle installTemplateNodes task.
|
||||
|
||||
This will output the node JAR to ``build/libs/corda.jar`` and several sample/standard
|
||||
node setups to ``build/nodes``. For now you can use the ``build/nodes/nodea`` configuration as a template.
|
||||
|
||||
Each node server must have a ``node.conf`` file in the same directory as the node JAR file. After first
|
||||
execution of the node server there will be many other configuration and persistence files created in this directory.
|
||||
|
||||
.. note:: Outside of development environments do not store your node directories in the build folder.
|
||||
|
||||
Installing Apps
|
||||
------------------
|
||||
|
||||
Once you have created your app JAR you can install it to a node by adding it to ``<node_dir>/plugins/``. In this
|
||||
case the ``node_dir`` is the location where your node server's JAR and configuration file is.
|
||||
|
||||
.. note:: If the directory does not exist you can create it manually.
|
||||
|
||||
Starting your Node
|
||||
------------------
|
||||
|
||||
Now you have a node server with your app installed, you can run it by navigating to ``<node_dir>`` and running
|
||||
|
||||
java -jar corda.jar
|
||||
|
||||
The plugin should automatically be registered and the configuration file used.
|
||||
|
||||
.. warning:: If your working directory is not ``<node_dir>`` your plugins and configuration will not be used.
|
||||
|
||||
.. _CordaPluginRegistry: api/com.r3corda.core.node/-corda-plugin-registry/index.html
|
||||
.. _ServiceHubInternal: api/com.r3corda.node.services.api/-service-hub-internal/index.html
|
||||
.. _ServiceHub: api/com.r3corda.node.services.api/-service-hub/index.html
|
@ -31,6 +31,7 @@ Read on to learn:
|
||||
transaction-data-types
|
||||
consensus
|
||||
messaging
|
||||
creating-a-cordapp
|
||||
running-the-demos
|
||||
node-administration
|
||||
|
||||
|
54
src/main/java/CordaCaplet.java
Normal file
54
src/main/java/CordaCaplet.java
Normal file
@ -0,0 +1,54 @@
|
||||
// Due to Capsule being in the default package, which cannot be imported, this caplet
|
||||
// must also be in the default package. When using Kotlin there are a whole host of exceptions
|
||||
// trying to construct this from Capsule, so it is written in Java.
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CordaCaplet extends Capsule {
|
||||
|
||||
protected CordaCaplet(Capsule pred) {
|
||||
super(pred);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding the Caplet classpath generation via the intended interface in Capsule.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T attribute(Map.Entry<String, T> attr) {
|
||||
// Equality is used here because Capsule never instantiates these attributes but instead reuses the ones
|
||||
// defined as public static final fields on the Capsule class, therefore referential equality is safe.
|
||||
if(ATTR_APP_CLASS_PATH == attr) {
|
||||
T cp = super.attribute(attr);
|
||||
List<Path> classpath = (List<Path>) cp;
|
||||
return (T) augmentClasspath(classpath);
|
||||
}
|
||||
return super.attribute(attr);
|
||||
}
|
||||
|
||||
// TODO: Make directory configurable via the capsule manifest.
|
||||
// TODO: Add working directory variable to capsules string replacement variables.
|
||||
private List<Path> augmentClasspath(List<Path> classpath) {
|
||||
File dir = new File("plugins");
|
||||
if(!dir.exists()) {
|
||||
dir.mkdir();
|
||||
}
|
||||
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (file.isFile() && isJAR(file)) {
|
||||
classpath.add(file.toPath().toAbsolutePath());
|
||||
}
|
||||
}
|
||||
return classpath;
|
||||
}
|
||||
|
||||
private Boolean isJAR(File file) {
|
||||
return file.getName().toLowerCase().endsWith(".jar");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user