Renamed "plugins" dir to "cordapps" (#1644)

* Renamed plugins dir to cordapps dir while maintaining backwards compatibility with the plugins dir.
Bumped gradle plugins to 2.0.4
This commit is contained in:
Clinton 2017-10-13 15:01:24 +01:00 committed by GitHub
parent 635ad9ac92
commit 2680361696
31 changed files with 176 additions and 161 deletions

View File

@ -74,9 +74,9 @@ public class StandaloneCordaRPCJavaClientTest {
} }
private void copyFinanceCordapp() { private void copyFinanceCordapp() {
Path pluginsDir = (factory.baseDirectory(notaryConfig).resolve("plugins")); Path cordappsDir = (factory.baseDirectory(notaryConfig).resolve("cordapps"));
try { try {
Files.createDirectories(pluginsDir); Files.createDirectories(cordappsDir);
} catch (IOException ex) { } catch (IOException ex) {
fail("Failed to create directories"); fail("Failed to create directories");
} }
@ -84,7 +84,7 @@ public class StandaloneCordaRPCJavaClientTest {
paths.forEach(file -> { paths.forEach(file -> {
if (file.toString().contains("corda-finance")) { if (file.toString().contains("corda-finance")) {
try { try {
Files.copy(file, pluginsDir.resolve(file.getFileName())); Files.copy(file, cordappsDir.resolve(file.getFileName()));
} catch (IOException ex) { } catch (IOException ex) {
fail("Failed to copy finance jar"); fail("Failed to copy finance jar");
} }

View File

@ -89,12 +89,12 @@ class StandaloneCordaRPClientTest {
} }
private fun copyFinanceCordapp() { private fun copyFinanceCordapp() {
val pluginsDir = (factory.baseDirectory(notaryConfig) / "plugins").createDirectories() val cordappsDir = (factory.baseDirectory(notaryConfig) / "cordapps").createDirectories()
// Find the finance jar file for the smoke tests of this module // Find the finance jar file for the smoke tests of this module
val financeJar = Paths.get("build", "resources", "smokeTest").list { val financeJar = Paths.get("build", "resources", "smokeTest").list {
it.filter { "corda-finance" in it.toString() }.toList().single() it.filter { "corda-finance" in it.toString() }.toList().single()
} }
financeJar.copyToDirectory(pluginsDir) financeJar.copyToDirectory(cordappsDir)
} }
@Test @Test

View File

@ -1,4 +1,4 @@
gradlePluginsVersion=2.0.3 gradlePluginsVersion=2.0.4
kotlinVersion=1.1.50 kotlinVersion=1.1.50
guavaVersion=21.0 guavaVersion=21.0
bouncycastleVersion=1.57 bouncycastleVersion=1.57

View File

@ -97,7 +97,7 @@ Loading the Yo! CordDapp on your Corda nodes lets you send simple Yo! messages t
* **Loading the Yo! CorDapp onto your nodes** * **Loading the Yo! CorDapp onto your nodes**
The nodes you will use to send and receive Yo messages require the Yo! CorDapp jar file to be saved to their plugins directory. The nodes you will use to send and receive Yo messages require the Yo! CorDapp jar file to be saved to their cordapps directory.
Connect to one of your Corda nodes (make sure this is not the Notary node) using an SSH client of your choice (e.g. Putty) and log into the virtual machine using the public IP address and your SSH key or username / password combination you defined in Step 1 of the Azure build process. Type the following command: Connect to one of your Corda nodes (make sure this is not the Notary node) using an SSH client of your choice (e.g. Putty) and log into the virtual machine using the public IP address and your SSH key or username / password combination you defined in Step 1 of the Azure build process. Type the following command:
@ -105,14 +105,14 @@ For Corda nodes running release M10
.. sourcecode:: shell .. sourcecode:: shell
cd /opt/corda/plugins cd /opt/corda/cordapps
wget http://downloads.corda.net/cordapps/net/corda/yo/0.10.1/yo-0.10.1.jar wget http://downloads.corda.net/cordapps/net/corda/yo/0.10.1/yo-0.10.1.jar
For Corda nodes running release M11 For Corda nodes running release M11
.. sourcecode:: shell .. sourcecode:: shell
cd /opt/corda/plugins cd /opt/corda/cordapps
wget http://downloads.corda.net/cordapps/net/corda/yo/0.11.0/yo-0.11.0.jar wget http://downloads.corda.net/cordapps/net/corda/yo/0.11.0/yo-0.11.0.jar
Now restart Corda and the Corda webserver using the following commands or restart your Corda VM from the Azure portal: Now restart Corda and the Corda webserver using the following commands or restart your Corda VM from the Azure portal:

View File

@ -11,6 +11,8 @@ UNRELEASED
* ``FlowLogic`` now exposes a series of function called ``receiveAll(...)`` allowing to join ``receive(...)`` instructions. * ``FlowLogic`` now exposes a series of function called ``receiveAll(...)`` allowing to join ``receive(...)`` instructions.
* Renamed "plugins" directory on nodes to "cordapps"
* The ``Cordformation`` gradle plugin has been split into ``cordformation`` and ``cordapp``. The former builds and * The ``Cordformation`` gradle plugin has been split into ``cordformation`` and ``cordapp``. The former builds and
deploys nodes for development and testing, the latter turns a project into a cordapp project that generates JARs in deploys nodes for development and testing, the latter turns a project into a cordapp project that generates JARs in
the standard CorDapp format. the standard CorDapp format.

View File

@ -78,11 +78,11 @@ For further information about managing dependencies, see
Installing CorDapps Installing CorDapps
------------------- -------------------
At runtime, nodes will load any plugins present in their ``plugins`` folder. Therefore in order to install a cordapp to At runtime, nodes will load any CorDapp JARs present in their ``cordapps`` folder. Therefore in order to install a CorDapp to
a node the cordapp JAR must be added to the ``<node_dir>/plugins/`` folder, where ``node_dir`` is the folder in which the a node the CorDapp JAR must be added to the ``<node_dir>/cordapps/`` folder, where ``node_dir`` is the folder in which the
node's JAR and configuration files are stored). node's JAR and configuration files are stored).
The ``deployNodes`` gradle task, if correctly configured, will automatically place your cordapp JAR as well as any The ``deployNodes`` gradle task, if correctly configured, will automatically place your CorDapp JAR as well as any
dependent cordapp JARs specified into the directory automatically. dependent cordapp JARs specified into the directory automatically.
Example Example

View File

@ -37,13 +37,13 @@ Profiles
notary/ notary/
node.conf node.conf
plugins/ cordapps/
banka/ banka/
node.conf node.conf
plugins/ cordapps/
bankb/ bankb/
node.conf node.conf
plugins/ cordapps/
example-cordapp.jar example-cordapp.jar
... ...
@ -133,7 +133,7 @@ current working directory of the JVM):
corda-webserver.jar corda-webserver.jar
explorer/ explorer/
node-explorer.jar node-explorer.jar
plugins/ cordapps/
bank-of-corda.jar bank-of-corda.jar
.. ..

View File

@ -84,7 +84,7 @@ run all the nodes at once. Each node in the ``nodes`` folder has the following s
. nodeName . nodeName
├── corda.jar // The Corda runtime ├── corda.jar // The Corda runtime
├── node.conf // The node's configuration ├── node.conf // The node's configuration
├── plugins // Any installed CorDapps ├── cordapps // Any installed CorDapps
└── additional-node-infos // Directory containing all the addresses and certificates of the other nodes. └── additional-node-infos // Directory containing all the addresses and certificates of the other nodes.
.. note:: During the build process each node generates a NodeInfo file which is written in its own root directory, .. note:: During the build process each node generates a NodeInfo file which is written in its own root directory,

View File

@ -5,7 +5,7 @@ By this point, :doc:`your dev environment should be set up <getting-set-up>`, yo
:doc:`your first CorDapp <tutorial-cordapp>`, and you're familiar with Corda's :doc:`key concepts <key-concepts>`. What :doc:`your first CorDapp <tutorial-cordapp>`, and you're familiar with Corda's :doc:`key concepts <key-concepts>`. What
comes next? comes next?
If you're a developer, the next step is to write your own CorDapp. Each CorDapp takes the form of a plugin that is If you're a developer, the next step is to write your own CorDapp. Each CorDapp takes the form of a JAR that is
installed on one or more Corda nodes, and gives them the ability to conduct some new process - anything from installed on one or more Corda nodes, and gives them the ability to conduct some new process - anything from
issuing a debt instrument to making a restaurant booking. issuing a debt instrument to making a restaurant booking.

View File

@ -82,7 +82,7 @@ the three node folders. Each node folder has the following structure:
|____dependencies |____dependencies
|____node.conf // The node's configuration file |____node.conf // The node's configuration file
|____additional-node-infos/ // Directory containing all the other nodes' addresses and identities |____additional-node-infos/ // Directory containing all the other nodes' addresses and identities
|____plugins |____cordapps
|____java/kotlin-source-0.1.jar // Our IOU CorDapp |____java/kotlin-source-0.1.jar // Our IOU CorDapp
Let's start the nodes by running the following commands from the root of the project: Let's start the nodes by running the following commands from the root of the project:

View File

@ -146,4 +146,4 @@ The driver takes a parameter called ``extraCordappPackagesToScan`` which is a li
Full Nodes Full Nodes
********** **********
When testing against full nodes simply place your CorDapp into the plugins directory of the node. When testing against full nodes simply place your CorDapp into the cordapps directory of the node.

View File

@ -36,7 +36,7 @@ The core elements of the architecture are:
* A network interface for interacting with other nodes * A network interface for interacting with other nodes
* An RPC interface for interacting with the node's owner * An RPC interface for interacting with the node's owner
* A service hub for allowing the node's flows to call upon the node's other services * A service hub for allowing the node's flows to call upon the node's other services
* A plugin registry for extending the node by installing CorDapps * A cordapp interface and provider for extending the node by installing CorDapps
Persistence layer Persistence layer
----------------- -----------------
@ -68,11 +68,11 @@ updates. The key services provided are:
* Information about the node itself * Information about the node itself
* The current time, as tracked by the node * The current time, as tracked by the node
The plugin registry The CorDapp provider
------------------- --------------------
The plugin registry is where new CorDapps are installed to extend the behavior of the node. The CorDapp provider is where new CorDapps are installed to extend the behavior of the node.
The node also has several plugins installed by default to handle common tasks such as: The node also has several CorDapps installed by default to handle common tasks such as:
* Retrieving transactions and attachments from counterparties * Retrieving transactions and attachments from counterparties
* Upgrading contracts * Upgrading contracts

View File

@ -320,7 +320,7 @@ does this by tracking update notifications from the
``TransactionStorage`` service and processing relevant updates to delete ``TransactionStorage`` service and processing relevant updates to delete
consumed states and insert new states. The resulting update is then consumed states and insert new states. The resulting update is then
persisted to the database. The ``VaultService`` then exposes query and persisted to the database. The ``VaultService`` then exposes query and
event notification APIs to flows and CorDapp plugins to allow them event notification APIs to flows and CorDapp services to allow them
to respond to updates, or query for states meeting various conditions to to respond to updates, or query for states meeting various conditions to
begin the formation of new transactions consuming them. The equivalent begin the formation of new transactions consuming them. The equivalent
services are also forwarded to RPC clients, so that they may show services are also forwarded to RPC clients, so that they may show

View File

@ -10,7 +10,7 @@ already installed. You run each node by navigating to ``<node_dir>`` in a termin
java -jar corda.jar java -jar corda.jar
.. warning:: If your working directory is not ``<node_dir>`` your plugins and configuration will not be used. .. warning:: If your working directory is not ``<node_dir>`` your cordapps and configuration will not be used.
The configuration file and workspace paths can be overridden on the command line. For example: The configuration file and workspace paths can be overridden on the command line. For example:

View File

@ -210,9 +210,9 @@ Building the example CorDapp
. nodeName . nodeName
├── corda.jar ├── corda.jar
├── node.conf ├── node.conf
└── plugins └── cordapps
``corda.jar`` is the Corda runtime, ``plugins`` contains our node's CorDapps, and the node's configuration is ``corda.jar`` is the Corda runtime, ``cordapps`` contains our node's CorDapps, and the node's configuration is
given by ``node.conf`` given by ``node.conf``
Running the example CorDapp Running the example CorDapp

View File

@ -17,7 +17,7 @@ class Node extends CordformNode {
static final String WEBJAR_NAME = 'corda-webserver.jar' static final String WEBJAR_NAME = 'corda-webserver.jar'
/** /**
* Set the list of CorDapps to install to the plugins directory. Each cordapp is a fully qualified Maven * Set the list of CorDapps to install to the cordapps directory. Each cordapp is a fully qualified Maven
* dependency name, eg: com.example:product-name:0.1 * dependency name, eg: com.example:product-name:0.1
* *
* @note Your app will be installed by default and does not need to be included here. * @note Your app will be installed by default and does not need to be included here.
@ -104,7 +104,7 @@ class Node extends CordformNode {
if (config.hasPath("webAddress")) { if (config.hasPath("webAddress")) {
installWebserverJar() installWebserverJar()
} }
installBuiltPlugin() installBuiltCordapp()
installCordapps() installCordapps()
installConfig() installConfig()
appendOptionalConfig() appendOptionalConfig()
@ -157,23 +157,23 @@ class Node extends CordformNode {
/** /**
* Installs this project's cordapp to this directory. * Installs this project's cordapp to this directory.
*/ */
private void installBuiltPlugin() { private void installBuiltCordapp() {
def pluginsDir = new File(nodeDir, "plugins") def cordappsDir = new File(nodeDir, "cordapps")
project.copy { project.copy {
from project.jar from project.jar
into pluginsDir into cordappsDir
} }
} }
/** /**
* Installs other cordapps to this node's plugins directory. * Installs other cordapps to this node's cordapps directory.
*/ */
private void installCordapps() { private void installCordapps() {
def pluginsDir = new File(nodeDir, "plugins") def cordappsDir = new File(nodeDir, "cordapps")
def cordapps = getCordappList() def cordapps = getCordappList()
project.copy { project.copy {
from cordapps from cordapps
into pluginsDir into cordappsDir
} }
} }

View File

@ -69,7 +69,7 @@ class AttachmentLoadingTests : TestDependencyInjectionBase() {
private fun DriverDSLExposedInterface.installIsolatedCordappTo(nodeName: CordaX500Name) { private fun DriverDSLExposedInterface.installIsolatedCordappTo(nodeName: CordaX500Name) {
// Copy the app jar to the first node. The second won't have it. // Copy the app jar to the first node. The second won't have it.
val path = (baseDirectory(nodeName.toString()) / "plugins").createDirectories() / "isolated.jar" val path = (baseDirectory(nodeName.toString()) / "cordapps").createDirectories() / "isolated.jar"
logger.info("Installing isolated jar to $path") logger.info("Installing isolated jar to $path")
isolatedJAR.openStream().buffered().use { input -> isolatedJAR.openStream().buffered().use { input ->
Files.newOutputStream(path).buffered().use { output -> Files.newOutputStream(path).buffered().use { output ->

View File

@ -24,26 +24,27 @@ public class CordaCaplet extends Capsule {
// defined as public static final fields on the Capsule class, therefore referential equality is safe. // defined as public static final fields on the Capsule class, therefore referential equality is safe.
if (ATTR_APP_CLASS_PATH == attr) { if (ATTR_APP_CLASS_PATH == attr) {
T cp = super.attribute(attr); T cp = super.attribute(attr);
return (T) augmentClasspath((List<Path>) cp, "plugins");
(new File("cordapps")).mkdir();
augmentClasspath((List<Path>) cp, "cordapps");
augmentClasspath((List<Path>) cp, "plugins");
return cp;
} }
return super.attribute(attr); return super.attribute(attr);
} }
// TODO: Make directory configurable via the capsule manifest. // TODO: Make directory configurable via the capsule manifest.
// TODO: Add working directory variable to capsules string replacement variables. // TODO: Add working directory variable to capsules string replacement variables.
private List<Path> augmentClasspath(List<Path> classpath, String dirName) { private void augmentClasspath(List<Path> classpath, String dirName) {
File dir = new File(dirName); File dir = new File(dirName);
if (!dir.exists()) { if (dir.exists()) {
dir.mkdir(); File[] files = dir.listFiles();
} for (File file : files) {
if (file.isFile() && isJAR(file)) {
File[] files = dir.listFiles(); classpath.add(file.toPath().toAbsolutePath());
for (File file : files) { }
if (file.isFile() && isJAR(file)) {
classpath.add(file.toPath().toAbsolutePath());
} }
} }
return classpath;
} }
@Override @Override

View File

@ -54,22 +54,30 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
companion object { companion object {
private val logger = loggerFor<CordappLoader>() private val logger = loggerFor<CordappLoader>()
/**
* Default cordapp dir name
*/
val CORDAPPS_DIR_NAME = "cordapps"
/** /**
* Creates a default CordappLoader intended to be used in non-dev or non-test environments. * Creates a default CordappLoader intended to be used in non-dev or non-test environments.
* *
* @param baseDir The directory that this node is running in. Will use this to resolve the plugins directory * @param baseDir The directory that this node is running in. Will use this to resolve the cordapps directory
* for classpath scanning. * for classpath scanning.
*/ */
fun createDefault(baseDir: Path) = CordappLoader(getCordappsInDirectory(getPluginsPath(baseDir))) fun createDefault(baseDir: Path) = CordappLoader(getCordappsInDirectory(getCordappsPath(baseDir)))
/** /**
* Create a dev mode CordappLoader for test environments that creates and loads cordapps from the classpath * Create a dev mode CordappLoader for test environments that creates and loads cordapps from the classpath
* and plugins directory. This is intended mostly for use by the driver. * and cordapps directory. This is intended mostly for use by the driver.
*
* @param baseDir See [createDefault.baseDir]
* @param testPackages See [createWithTestPackages.testPackages]
*/ */
@VisibleForTesting @VisibleForTesting
fun createDefaultWithTestPackages(configuration: NodeConfiguration, testPackages: List<String>): CordappLoader { fun createDefaultWithTestPackages(configuration: NodeConfiguration, testPackages: List<String>): CordappLoader {
check(configuration.devMode) { "Package scanning can only occur in dev mode" } check(configuration.devMode) { "Package scanning can only occur in dev mode" }
return CordappLoader(getCordappsInDirectory(getPluginsPath(configuration.baseDirectory)) + testPackages.flatMap(this::createScanPackage)) return CordappLoader(getCordappsInDirectory(getCordappsPath(configuration.baseDirectory)) + testPackages.flatMap(this::createScanPackage))
} }
/** /**
@ -91,7 +99,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
@VisibleForTesting @VisibleForTesting
fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars) fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars)
private fun getPluginsPath(baseDir: Path): Path = baseDir / "plugins" private fun getCordappsPath(baseDir: Path): Path = baseDir / CORDAPPS_DIR_NAME
private fun createScanPackage(scanPackage: String): List<URL> { private fun createScanPackage(scanPackage: String): List<URL> {
val resource = scanPackage.replace('.', '/') val resource = scanPackage.replace('.', '/')
@ -135,11 +143,11 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
return generatedCordapps[path]!! return generatedCordapps[path]!!
} }
private fun getCordappsInDirectory(pluginsDir: Path): List<URL> { private fun getCordappsInDirectory(cordappsDir: Path): List<URL> {
return if (!pluginsDir.exists()) { return if (!cordappsDir.exists()) {
emptyList<URL>() emptyList<URL>()
} else { } else {
pluginsDir.list { cordappsDir.list {
it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { it.toUri().toURL() }.toList() it.filter { it.isRegularFile() && it.toString().endsWith(".jar") }.map { it.toUri().toURL() }.toList()
} }
} }

View File

@ -11,6 +11,7 @@ import net.corda.core.internal.list
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.smoketesting.NodeConfig import net.corda.smoketesting.NodeConfig
import net.corda.smoketesting.NodeProcess import net.corda.smoketesting.NodeProcess
@ -39,12 +40,12 @@ class CordappSmokeTest {
@Test @Test
fun `FlowContent appName returns the filename of the CorDapp jar`() { fun `FlowContent appName returns the filename of the CorDapp jar`() {
val pluginsDir = (factory.baseDirectory(aliceConfig) / "plugins").createDirectories() val cordappsDir = (factory.baseDirectory(aliceConfig) / CordappLoader.CORDAPPS_DIR_NAME).createDirectories()
// Find the jar file for the smoke tests of this module // Find the jar file for the smoke tests of this module
val selfCordapp = Paths.get("build", "libs").list { val selfCordapp = Paths.get("build", "libs").list {
it.filter { "-smokeTests" in it.toString() }.toList().single() it.filter { "-smokeTests" in it.toString() }.toList().single()
} }
selfCordapp.copyToDirectory(pluginsDir) selfCordapp.copyToDirectory(cordappsDir)
factory.create(aliceConfig).use { alice -> factory.create(aliceConfig).use { alice ->
alice.connect().use { connectionToAlice -> alice.connect().use { connectionToAlice ->
@ -59,8 +60,8 @@ class CordappSmokeTest {
} }
@Test @Test
fun `empty plugins directory`() { fun `empty cordapps directory`() {
(factory.baseDirectory(aliceConfig) / "plugins").createDirectories() (factory.baseDirectory(aliceConfig) / CordappLoader.CORDAPPS_DIR_NAME).createDirectories()
factory.create(aliceConfig).close() factory.create(aliceConfig).close()
} }

View File

@ -122,12 +122,12 @@ distributions {
} }
from(project(':finance').tasks.jar) { from(project(':finance').tasks.jar) {
rename 'corda-finance-(.*)', 'corda-finance.jar' rename 'corda-finance-(.*)', 'corda-finance.jar'
into 'plugins' into 'cordapps'
fileMode = 0444 fileMode = 0444
} }
from(project(':samples:bank-of-corda-demo').jar) { from(project(':samples:bank-of-corda-demo').jar) {
rename 'bank-of-corda-demo-(.*)', 'bank-of-corda.jar' rename 'bank-of-corda-demo-(.*)', 'bank-of-corda.jar'
into 'plugins' into 'cordapps'
fileMode = 0444 fileMode = 0444
} }
} }
@ -201,7 +201,7 @@ task javapackage(dependsOn: distZip) {
fileset(dir: dist_source, type: 'data') { fileset(dir: dist_source, type: 'data') {
include(name: 'corda/*.jar') include(name: 'corda/*.jar')
include(name: 'plugins/*.jar') include(name: 'cordapps/*.jar')
include(name: 'explorer/*.jar') include(name: 'explorer/*.jar')
} }

View File

@ -5,6 +5,7 @@ import net.corda.core.internal.div
import net.corda.core.internal.list import net.corda.core.internal.list
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.demobench.model.JVMConfig import net.corda.demobench.model.JVMConfig
import net.corda.demobench.model.NodeConfig
import net.corda.demobench.model.NodeConfigWrapper import net.corda.demobench.model.NodeConfigWrapper
import net.corda.demobench.readErrorLines import net.corda.demobench.readErrorLines
import tornadofx.* import tornadofx.*
@ -82,11 +83,11 @@ class Explorer internal constructor(private val explorerController: ExplorerCont
// Note: does not copy dependencies because we should soon be making all apps fat jars and dependencies implicit. // Note: does not copy dependencies because we should soon be making all apps fat jars and dependencies implicit.
// //
// TODO: Remove this code when serialisation has been upgraded. // TODO: Remove this code when serialisation has been upgraded.
val pluginsDir = config.explorerDir / "plugins" val cordappsDir = config.explorerDir / NodeConfig.cordappDirName
pluginsDir.createDirectories() cordappsDir.createDirectories()
config.pluginDir.list { config.cordappsDir.list {
it.forEachOrdered { path -> it.forEachOrdered { path ->
val destPath = pluginsDir / path.fileName.toString() val destPath = cordappsDir / path.fileName.toString()
try { try {
// Try making a symlink to make things faster and use less disk space. // Try making a symlink to make things faster and use less disk space.
Files.createSymbolicLink(destPath, path) Files.createSymbolicLink(destPath, path)

View File

@ -2,6 +2,6 @@ package net.corda.demobench.model
import java.nio.file.Path import java.nio.file.Path
interface HasPlugins { interface HasCordapps {
val pluginDir: Path val cordappsDir: Path
} }

View File

@ -37,9 +37,9 @@ class InstallFactory : Controller() {
* Wraps the configuration information for a Node * Wraps the configuration information for a Node
* which isn't ready to be instantiated yet. * which isn't ready to be instantiated yet.
*/ */
class InstallConfig internal constructor(val baseDir: Path, private val config: NodeConfigWrapper) : HasPlugins { class InstallConfig internal constructor(val baseDir: Path, private val config: NodeConfigWrapper) : HasCordapps {
val key = config.key val key = config.key
override val pluginDir: Path = baseDir / "plugins" override val cordappsDir: Path = baseDir / "cordapps"
fun deleteBaseDir(): Boolean = baseDir.toFile().deleteRecursively() fun deleteBaseDir(): Boolean = baseDir.toFile().deleteRecursively()
fun installTo(installDir: Path) = config.copy(baseDir = installDir) fun installTo(installDir: Path) = config.copy(baseDir = installDir)

View File

@ -31,6 +31,7 @@ data class NodeConfig(
companion object { companion object {
val renderOptions: ConfigRenderOptions = ConfigRenderOptions.defaults().setOriginComments(false) val renderOptions: ConfigRenderOptions = ConfigRenderOptions.defaults().setOriginComments(false)
val defaultUser = user("guest") val defaultUser = user("guest")
val cordappDirName = "cordapps"
} }
@Suppress("unused") @Suppress("unused")
@ -56,18 +57,18 @@ data class NotaryService(val validating: Boolean) : ExtraService {
} }
// TODO Think of a better name // TODO Think of a better name
data class NodeConfigWrapper(val baseDir: Path, val nodeConfig: NodeConfig) : HasPlugins { data class NodeConfigWrapper(val baseDir: Path, val nodeConfig: NodeConfig) : HasCordapps {
val key: String = nodeConfig.myLegalName.organisation.toKey() val key: String = nodeConfig.myLegalName.organisation.toKey()
val nodeDir: Path = baseDir / key val nodeDir: Path = baseDir / key
val explorerDir: Path = baseDir / "$key-explorer" val explorerDir: Path = baseDir / "$key-explorer"
override val pluginDir: Path = nodeDir / "plugins" override val cordappsDir: Path = nodeDir / NodeConfig.cordappDirName
var state: NodeState = NodeState.STARTING var state: NodeState = NodeState.STARTING
fun install(cordapps: Collection<Path>) { fun install(cordapps: Collection<Path>) {
if (cordapps.isEmpty()) return if (cordapps.isEmpty()) return
pluginDir.createDirectories() cordappsDir.createDirectories()
for (cordapp in cordapps) { for (cordapp in cordapps) {
cordapp.copyToDirectory(pluginDir, StandardCopyOption.REPLACE_EXISTING) cordapp.copyToDirectory(cordappsDir, StandardCopyOption.REPLACE_EXISTING)
} }
} }
} }

View File

@ -7,7 +7,7 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.noneOrSingle import net.corda.core.internal.noneOrSingle
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.demobench.plugin.PluginController import net.corda.demobench.plugin.CordappController
import net.corda.demobench.pty.R3Pty import net.corda.demobench.pty.R3Pty
import tornadofx.* import tornadofx.*
import java.io.IOException import java.io.IOException
@ -27,7 +27,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
} }
private val jvm by inject<JVMConfig>() private val jvm by inject<JVMConfig>()
private val pluginController by inject<PluginController>() private val cordappController by inject<CordappController>()
private var baseDir: Path = baseDirFor(ManagementFactory.getRuntimeMXBean().startTime) private var baseDir: Path = baseDirFor(ManagementFactory.getRuntimeMXBean().startTime)
private val cordaPath: Path = jvm.applicationDir.resolve("corda").resolve("corda.jar") private val cordaPath: Path = jvm.applicationDir.resolve("corda").resolve("corda.jar")
@ -112,7 +112,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
config.nodeDir.createDirectories() config.nodeDir.createDirectories()
// Install any built-in plugins into the working directory. // Install any built-in plugins into the working directory.
pluginController.populate(config) cordappController.populate(config)
// Write this node's configuration file into its working directory. // Write this node's configuration file into its working directory.
val confFile = config.nodeDir / "node.conf" val confFile = config.nodeDir / "node.conf"
@ -164,9 +164,9 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
fun install(config: InstallConfig): NodeConfigWrapper { fun install(config: InstallConfig): NodeConfigWrapper {
val installed = config.installTo(baseDir) val installed = config.installTo(baseDir)
pluginController.userPluginsFor(config).forEach { cordappController.useCordappsFor(config).forEach {
installed.pluginDir.createDirectories() installed.cordappsDir.createDirectories()
val plugin = it.copyToDirectory(installed.pluginDir) val plugin = it.copyToDirectory(installed.cordappsDir)
log.info("Installed: $plugin") log.info("Installed: $plugin")
} }

View File

@ -0,0 +1,61 @@
package net.corda.demobench.plugin
import net.corda.core.internal.copyToDirectory
import net.corda.core.internal.createDirectories
import net.corda.core.internal.exists
import net.corda.demobench.model.HasCordapps
import net.corda.demobench.model.JVMConfig
import net.corda.demobench.model.NodeConfig
import net.corda.demobench.model.NodeConfigWrapper
import tornadofx.*
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.util.stream.Stream
class CordappController : Controller() {
private val jvm by inject<JVMConfig>()
private val cordappDir: Path = jvm.applicationDir.resolve(NodeConfig.cordappDirName)
private val bankOfCorda: Path = cordappDir.resolve("bank-of-corda.jar")
private val finance: Path = cordappDir.resolve("corda-finance.jar")
/**
* Install any built-in cordapps that this node requires.
*/
@Throws(IOException::class)
fun populate(config: NodeConfigWrapper) {
if (!config.cordappsDir.exists()) {
config.cordappsDir.createDirectories()
}
if (finance.exists()) {
finance.copyToDirectory(config.cordappsDir, StandardCopyOption.REPLACE_EXISTING)
log.info("Installed 'Finance' cordapp")
}
// Nodes cannot issue cash unless they contain the "Bank of Corda" cordapp.
if (config.nodeConfig.issuableCurrencies.isNotEmpty() && bankOfCorda.exists()) {
bankOfCorda.copyToDirectory(config.cordappsDir, StandardCopyOption.REPLACE_EXISTING)
log.info("Installed 'Bank of Corda' cordapp")
}
}
/**
* Generates a stream of a node's non-built-in cordapps.
*/
@Throws(IOException::class)
fun useCordappsFor(config: HasCordapps): Stream<Path> = walkCordapps(config.cordappsDir)
.filter { !bankOfCorda.endsWith(it.fileName) }
.filter { !finance.endsWith(it.fileName) }
private fun walkCordapps(cordappsDir: Path): Stream<Path> {
return if (Files.isDirectory(cordappsDir))
Files.walk(cordappsDir, 1).filter(Path::isCordapp)
else
Stream.empty()
}
}
fun Path.isCordapp(): Boolean = Files.isReadable(this) && this.fileName.toString().endsWith(".jar")
fun Path.inCordappsDir(): Boolean = (this.parent != null) && this.parent.endsWith("cordapps/")

View File

@ -1,58 +0,0 @@
package net.corda.demobench.plugin
import net.corda.core.internal.copyToDirectory
import net.corda.core.internal.createDirectories
import net.corda.core.internal.exists
import net.corda.demobench.model.HasPlugins
import net.corda.demobench.model.JVMConfig
import net.corda.demobench.model.NodeConfigWrapper
import tornadofx.*
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.util.stream.Stream
class PluginController : Controller() {
private val jvm by inject<JVMConfig>()
private val pluginDir: Path = jvm.applicationDir.resolve("plugins")
private val bankOfCorda: Path = pluginDir.resolve("bank-of-corda.jar")
private val finance: Path = pluginDir.resolve("corda-finance.jar")
/**
* Install any built-in plugins that this node requires.
*/
@Throws(IOException::class)
fun populate(config: NodeConfigWrapper) {
config.pluginDir.createDirectories()
if (finance.exists()) {
finance.copyToDirectory(config.pluginDir, StandardCopyOption.REPLACE_EXISTING)
log.info("Installed 'Finance' plugin")
}
// Nodes cannot issue cash unless they contain the "Bank of Corda" plugin.
if (config.nodeConfig.issuableCurrencies.isNotEmpty() && bankOfCorda.exists()) {
bankOfCorda.copyToDirectory(config.pluginDir, StandardCopyOption.REPLACE_EXISTING)
log.info("Installed 'Bank of Corda' plugin")
}
}
/**
* Generates a stream of a node's non-built-in plugins.
*/
@Throws(IOException::class)
fun userPluginsFor(config: HasPlugins): Stream<Path> = walkPlugins(config.pluginDir)
.filter { !bankOfCorda.endsWith(it.fileName) }
.filter { !finance.endsWith(it.fileName) }
private fun walkPlugins(pluginDir: Path): Stream<Path> {
return if (Files.isDirectory(pluginDir))
Files.walk(pluginDir, 1).filter(Path::isPlugin)
else
Stream.empty()
}
}
fun Path.isPlugin(): Boolean = Files.isReadable(this) && this.fileName.toString().endsWith(".jar")
fun Path.inPluginsDir(): Boolean = (this.parent != null) && this.parent.endsWith("plugins/")

View File

@ -6,13 +6,10 @@ import javafx.stage.FileChooser
import javafx.stage.FileChooser.ExtensionFilter import javafx.stage.FileChooser.ExtensionFilter
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.demobench.model.InstallConfig import net.corda.demobench.model.*
import net.corda.demobench.model.InstallFactory import net.corda.demobench.plugin.CordappController
import net.corda.demobench.model.JVMConfig import net.corda.demobench.plugin.inCordappsDir
import net.corda.demobench.model.NodeController import net.corda.demobench.plugin.isCordapp
import net.corda.demobench.plugin.PluginController
import net.corda.demobench.plugin.inPluginsDir
import net.corda.demobench.plugin.isPlugin
import tornadofx.* import tornadofx.*
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -31,7 +28,7 @@ class ProfileController : Controller() {
private val jvm by inject<JVMConfig>() private val jvm by inject<JVMConfig>()
private val baseDir: Path = jvm.dataHome private val baseDir: Path = jvm.dataHome
private val nodeController by inject<NodeController>() private val nodeController by inject<NodeController>()
private val pluginController by inject<PluginController>() private val cordappController by inject<CordappController>()
private val installFactory by inject<InstallFactory>() private val installFactory by inject<InstallFactory>()
private val chooser = FileChooser() private val chooser = FileChooser()
@ -64,11 +61,11 @@ class ProfileController : Controller() {
val file = Files.write(nodeDir / "node.conf", config.nodeConfig.toText().toByteArray(UTF_8)) val file = Files.write(nodeDir / "node.conf", config.nodeConfig.toText().toByteArray(UTF_8))
log.info("Wrote: $file") log.info("Wrote: $file")
// Write all of the non-built-in plugins. // Write all of the non-built-in cordapps.
val pluginDir = Files.createDirectory(nodeDir.resolve("plugins")) val cordappDir = Files.createDirectory(nodeDir.resolve(NodeConfig.cordappDirName))
pluginController.userPluginsFor(config).forEach { cordappController.useCordappsFor(config).forEach {
val plugin = Files.copy(it, pluginDir.resolve(it.fileName.toString())) val cordapp = Files.copy(it, cordappDir.resolve(it.fileName.toString()))
log.info("Wrote: $plugin") log.info("Wrote: $cordapp")
} }
} }
} }
@ -120,16 +117,16 @@ class ProfileController : Controller() {
// Now extract all of the plugins from the ZIP file, // Now extract all of the plugins from the ZIP file,
// and copy them to a temporary location. // and copy them to a temporary location.
StreamSupport.stream(fs.rootDirectories.spliterator(), false) StreamSupport.stream(fs.rootDirectories.spliterator(), false)
.flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inPluginsDir() && p.isPlugin() && attr.isRegularFile }) } .flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inCordappsDir() && p.isCordapp() && attr.isRegularFile }) }
.forEach { plugin -> .forEach { cordapp ->
val config = nodeIndex[plugin.getName(0).toString()] ?: return@forEach val config = nodeIndex[cordapp.getName(0).toString()] ?: return@forEach
try { try {
val pluginDir = Files.createDirectories(config.pluginDir) val cordappDir = Files.createDirectories(config.cordappsDir)
Files.copy(plugin, pluginDir.resolve(plugin.fileName.toString())) Files.copy(cordapp, cordappDir.resolve(cordapp.fileName.toString()))
log.info("Loaded: $plugin") log.info("Loaded: $cordapp")
} catch (e: Exception) { } catch (e: Exception) {
log.log(Level.SEVERE, "Failed to extract '$plugin': ${e.message}", e) log.log(Level.SEVERE, "Failed to extract '$cordapp': ${e.message}", e)
configs.forEach { c -> c.deleteBaseDir() } configs.forEach { c -> c.deleteBaseDir() }
throw e throw e
} }

View File

@ -5,6 +5,7 @@ import com.typesafe.config.ConfigValueFactory
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.NetworkMapInfo import net.corda.node.internal.NetworkMapInfo
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.config.FullNodeConfiguration import net.corda.node.services.config.FullNodeConfiguration
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs import net.corda.nodeapi.config.parseAs

View File

@ -19,7 +19,7 @@ public class ExplorerCaplet extends Capsule {
// defined as public static final fields on the Capsule class, therefore referential equality is safe. // defined as public static final fields on the Capsule class, therefore referential equality is safe.
if (ATTR_APP_CLASS_PATH == attr) { if (ATTR_APP_CLASS_PATH == attr) {
T cp = super.attribute(attr); T cp = super.attribute(attr);
List<Path> classpath = augmentClasspath((List<Path>) cp, "plugins"); List<Path> classpath = augmentClasspath((List<Path>) cp, "cordapps");
return (T) augmentClasspath(classpath, "dependencies"); return (T) augmentClasspath(classpath, "dependencies");
} }
return super.attribute(attr); return super.attribute(attr);