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

View File

@ -89,12 +89,12 @@ class StandaloneCordaRPClientTest {
}
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
val financeJar = Paths.get("build", "resources", "smokeTest").list {
it.filter { "corda-finance" in it.toString() }.toList().single()
}
financeJar.copyToDirectory(pluginsDir)
financeJar.copyToDirectory(cordappsDir)
}
@Test

View File

@ -1,4 +1,4 @@
gradlePluginsVersion=2.0.3
gradlePluginsVersion=2.0.4
kotlinVersion=1.1.50
guavaVersion=21.0
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**
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:
@ -105,14 +105,14 @@ For Corda nodes running release M10
.. 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
For Corda nodes running release M11
.. 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
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.
* Renamed "plugins" directory on nodes to "cordapps"
* 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
the standard CorDapp format.

View File

@ -78,11 +78,11 @@ For further information about managing dependencies, see
Installing CorDapps
-------------------
At runtime, nodes will load any plugins present in their ``plugins`` 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
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>/cordapps/`` folder, where ``node_dir`` is the folder in which the
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.
Example

View File

@ -37,13 +37,13 @@ Profiles
notary/
node.conf
plugins/
cordapps/
banka/
node.conf
plugins/
cordapps/
bankb/
node.conf
plugins/
cordapps/
example-cordapp.jar
...
@ -133,7 +133,7 @@ current working directory of the JVM):
corda-webserver.jar
explorer/
node-explorer.jar
plugins/
cordapps/
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
├── corda.jar // The Corda runtime
├── 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.
.. 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
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
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
|____node.conf // The node's configuration file
|____additional-node-infos/ // Directory containing all the other nodes' addresses and identities
|____plugins
|____cordapps
|____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:

View File

@ -146,4 +146,4 @@ The driver takes a parameter called ``extraCordappPackagesToScan`` which is a li
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
* 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 plugin registry for extending the node by installing CorDapps
* A cordapp interface and provider for extending the node by installing CorDapps
Persistence layer
-----------------
@ -68,11 +68,11 @@ updates. The key services provided are:
* Information about the node itself
* The current time, as tracked by the node
The plugin registry
-------------------
The plugin registry is where new CorDapps are installed to extend the behavior of the node.
The CorDapp provider
--------------------
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
* Upgrading contracts

View File

@ -320,7 +320,7 @@ does this by tracking update notifications from the
``TransactionStorage`` service and processing relevant updates to delete
consumed states and insert new states. The resulting update is then
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
begin the formation of new transactions consuming them. The equivalent
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
.. 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:

View File

@ -210,9 +210,9 @@ Building the example CorDapp
. nodeName
├── corda.jar
├── 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``
Running the example CorDapp

View File

@ -17,7 +17,7 @@ class Node extends CordformNode {
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
*
* @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")) {
installWebserverJar()
}
installBuiltPlugin()
installBuiltCordapp()
installCordapps()
installConfig()
appendOptionalConfig()
@ -157,23 +157,23 @@ class Node extends CordformNode {
/**
* Installs this project's cordapp to this directory.
*/
private void installBuiltPlugin() {
def pluginsDir = new File(nodeDir, "plugins")
private void installBuiltCordapp() {
def cordappsDir = new File(nodeDir, "cordapps")
project.copy {
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() {
def pluginsDir = new File(nodeDir, "plugins")
def cordappsDir = new File(nodeDir, "cordapps")
def cordapps = getCordappList()
project.copy {
from cordapps
into pluginsDir
into cordappsDir
}
}

View File

@ -69,7 +69,7 @@ class AttachmentLoadingTests : TestDependencyInjectionBase() {
private fun DriverDSLExposedInterface.installIsolatedCordappTo(nodeName: CordaX500Name) {
// 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")
isolatedJAR.openStream().buffered().use { input ->
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.
if (ATTR_APP_CLASS_PATH == 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);
}
// 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, String dirName) {
private void augmentClasspath(List<Path> classpath, String dirName) {
File dir = new File(dirName);
if (!dir.exists()) {
dir.mkdir();
}
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile() && isJAR(file)) {
classpath.add(file.toPath().toAbsolutePath());
if (dir.exists()) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile() && isJAR(file)) {
classpath.add(file.toPath().toAbsolutePath());
}
}
}
return classpath;
}
@Override

View File

@ -54,22 +54,30 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
companion object {
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.
*
* @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.
*/
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
* 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
fun createDefaultWithTestPackages(configuration: NodeConfiguration, testPackages: List<String>): CordappLoader {
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
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> {
val resource = scanPackage.replace('.', '/')
@ -135,11 +143,11 @@ class CordappLoader private constructor(private val cordappJarPaths: List<URL>)
return generatedCordapps[path]!!
}
private fun getCordappsInDirectory(pluginsDir: Path): List<URL> {
return if (!pluginsDir.exists()) {
private fun getCordappsInDirectory(cordappsDir: Path): List<URL> {
return if (!cordappsDir.exists()) {
emptyList<URL>()
} else {
pluginsDir.list {
cordappsDir.list {
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.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.nodeapi.User
import net.corda.smoketesting.NodeConfig
import net.corda.smoketesting.NodeProcess
@ -39,12 +40,12 @@ class CordappSmokeTest {
@Test
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
val selfCordapp = Paths.get("build", "libs").list {
it.filter { "-smokeTests" in it.toString() }.toList().single()
}
selfCordapp.copyToDirectory(pluginsDir)
selfCordapp.copyToDirectory(cordappsDir)
factory.create(aliceConfig).use { alice ->
alice.connect().use { connectionToAlice ->
@ -59,8 +60,8 @@ class CordappSmokeTest {
}
@Test
fun `empty plugins directory`() {
(factory.baseDirectory(aliceConfig) / "plugins").createDirectories()
fun `empty cordapps directory`() {
(factory.baseDirectory(aliceConfig) / CordappLoader.CORDAPPS_DIR_NAME).createDirectories()
factory.create(aliceConfig).close()
}

View File

@ -122,12 +122,12 @@ distributions {
}
from(project(':finance').tasks.jar) {
rename 'corda-finance-(.*)', 'corda-finance.jar'
into 'plugins'
into 'cordapps'
fileMode = 0444
}
from(project(':samples:bank-of-corda-demo').jar) {
rename 'bank-of-corda-demo-(.*)', 'bank-of-corda.jar'
into 'plugins'
into 'cordapps'
fileMode = 0444
}
}
@ -201,7 +201,7 @@ task javapackage(dependsOn: distZip) {
fileset(dir: dist_source, type: 'data') {
include(name: 'corda/*.jar')
include(name: 'plugins/*.jar')
include(name: 'cordapps/*.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.utilities.loggerFor
import net.corda.demobench.model.JVMConfig
import net.corda.demobench.model.NodeConfig
import net.corda.demobench.model.NodeConfigWrapper
import net.corda.demobench.readErrorLines
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.
//
// TODO: Remove this code when serialisation has been upgraded.
val pluginsDir = config.explorerDir / "plugins"
pluginsDir.createDirectories()
config.pluginDir.list {
val cordappsDir = config.explorerDir / NodeConfig.cordappDirName
cordappsDir.createDirectories()
config.cordappsDir.list {
it.forEachOrdered { path ->
val destPath = pluginsDir / path.fileName.toString()
val destPath = cordappsDir / path.fileName.toString()
try {
// Try making a symlink to make things faster and use less disk space.
Files.createSymbolicLink(destPath, path)

View File

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

View File

@ -37,9 +37,9 @@ class InstallFactory : Controller() {
* Wraps the configuration information for a Node
* 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
override val pluginDir: Path = baseDir / "plugins"
override val cordappsDir: Path = baseDir / "cordapps"
fun deleteBaseDir(): Boolean = baseDir.toFile().deleteRecursively()
fun installTo(installDir: Path) = config.copy(baseDir = installDir)

View File

@ -31,6 +31,7 @@ data class NodeConfig(
companion object {
val renderOptions: ConfigRenderOptions = ConfigRenderOptions.defaults().setOriginComments(false)
val defaultUser = user("guest")
val cordappDirName = "cordapps"
}
@Suppress("unused")
@ -56,18 +57,18 @@ data class NotaryService(val validating: Boolean) : ExtraService {
}
// 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 nodeDir: Path = baseDir / key
val explorerDir: Path = baseDir / "$key-explorer"
override val pluginDir: Path = nodeDir / "plugins"
override val cordappsDir: Path = nodeDir / NodeConfig.cordappDirName
var state: NodeState = NodeState.STARTING
fun install(cordapps: Collection<Path>) {
if (cordapps.isEmpty()) return
pluginDir.createDirectories()
cordappsDir.createDirectories()
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.noneOrSingle
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 tornadofx.*
import java.io.IOException
@ -27,7 +27,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
}
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 val cordaPath: Path = jvm.applicationDir.resolve("corda").resolve("corda.jar")
@ -112,7 +112,7 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
config.nodeDir.createDirectories()
// 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.
val confFile = config.nodeDir / "node.conf"
@ -164,9 +164,9 @@ class NodeController(check: atRuntime = ::checkExists) : Controller() {
fun install(config: InstallConfig): NodeConfigWrapper {
val installed = config.installTo(baseDir)
pluginController.userPluginsFor(config).forEach {
installed.pluginDir.createDirectories()
val plugin = it.copyToDirectory(installed.pluginDir)
cordappController.useCordappsFor(config).forEach {
installed.cordappsDir.createDirectories()
val plugin = it.copyToDirectory(installed.cordappsDir)
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 net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.demobench.model.InstallConfig
import net.corda.demobench.model.InstallFactory
import net.corda.demobench.model.JVMConfig
import net.corda.demobench.model.NodeController
import net.corda.demobench.plugin.PluginController
import net.corda.demobench.plugin.inPluginsDir
import net.corda.demobench.plugin.isPlugin
import net.corda.demobench.model.*
import net.corda.demobench.plugin.CordappController
import net.corda.demobench.plugin.inCordappsDir
import net.corda.demobench.plugin.isCordapp
import tornadofx.*
import java.io.File
import java.io.IOException
@ -31,7 +28,7 @@ class ProfileController : Controller() {
private val jvm by inject<JVMConfig>()
private val baseDir: Path = jvm.dataHome
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 chooser = FileChooser()
@ -64,11 +61,11 @@ class ProfileController : Controller() {
val file = Files.write(nodeDir / "node.conf", config.nodeConfig.toText().toByteArray(UTF_8))
log.info("Wrote: $file")
// Write all of the non-built-in plugins.
val pluginDir = Files.createDirectory(nodeDir.resolve("plugins"))
pluginController.userPluginsFor(config).forEach {
val plugin = Files.copy(it, pluginDir.resolve(it.fileName.toString()))
log.info("Wrote: $plugin")
// Write all of the non-built-in cordapps.
val cordappDir = Files.createDirectory(nodeDir.resolve(NodeConfig.cordappDirName))
cordappController.useCordappsFor(config).forEach {
val cordapp = Files.copy(it, cordappDir.resolve(it.fileName.toString()))
log.info("Wrote: $cordapp")
}
}
}
@ -120,16 +117,16 @@ class ProfileController : Controller() {
// Now extract all of the plugins from the ZIP file,
// and copy them to a temporary location.
StreamSupport.stream(fs.rootDirectories.spliterator(), false)
.flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inPluginsDir() && p.isPlugin() && attr.isRegularFile }) }
.forEach { plugin ->
val config = nodeIndex[plugin.getName(0).toString()] ?: return@forEach
.flatMap { Files.find(it, 3, BiPredicate { p, attr -> p.inCordappsDir() && p.isCordapp() && attr.isRegularFile }) }
.forEach { cordapp ->
val config = nodeIndex[cordapp.getName(0).toString()] ?: return@forEach
try {
val pluginDir = Files.createDirectories(config.pluginDir)
Files.copy(plugin, pluginDir.resolve(plugin.fileName.toString()))
log.info("Loaded: $plugin")
val cordappDir = Files.createDirectories(config.cordappsDir)
Files.copy(cordapp, cordappDir.resolve(cordapp.fileName.toString()))
log.info("Loaded: $cordapp")
} 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() }
throw e
}

View File

@ -5,6 +5,7 @@ import com.typesafe.config.ConfigValueFactory
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.NetworkMapInfo
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.nodeapi.User
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.
if (ATTR_APP_CLASS_PATH == 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 super.attribute(attr);