mirror of
https://github.com/corda/corda.git
synced 2025-02-03 01:31:24 +00:00
parent
12fa945077
commit
3dd09fd69b
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=2.0.4
|
gradlePluginsVersion=2.0.5
|
||||||
kotlinVersion=1.1.50
|
kotlinVersion=1.1.50
|
||||||
guavaVersion=21.0
|
guavaVersion=21.0
|
||||||
bouncycastleVersion=1.57
|
bouncycastleVersion=1.57
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
apply plugin: 'net.corda.plugins.cordformation'
|
apply plugin: 'net.corda.plugins.cordformation'
|
||||||
apply plugin: 'net.corda.plugins.cordapp'
|
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -29,7 +29,7 @@ class CordappPlugin : Plugin<Project> {
|
|||||||
private fun configureCordappJar(project: Project) {
|
private fun configureCordappJar(project: Project) {
|
||||||
// Note: project.afterEvaluate did not have full dependency resolution completed, hence a task is used instead
|
// Note: project.afterEvaluate did not have full dependency resolution completed, hence a task is used instead
|
||||||
val task = project.task("configureCordappFatJar")
|
val task = project.task("configureCordappFatJar")
|
||||||
val jarTask = project.tasks.single { it.name == "jar" } as Jar
|
val jarTask = project.tasks.getByName("jar") as Jar
|
||||||
task.doLast {
|
task.doLast {
|
||||||
jarTask.from(getDirectNonCordaDependencies(project).map { project.zipTree(it)}).apply {
|
jarTask.from(getDirectNonCordaDependencies(project).map { project.zipTree(it)}).apply {
|
||||||
exclude("META-INF/*.SF")
|
exclude("META-INF/*.SF")
|
||||||
@ -71,6 +71,4 @@ class CordappPlugin : Plugin<Project> {
|
|||||||
}
|
}
|
||||||
return filteredDeps.map { runtimeConfiguration.files(it) }.flatten().toSet()
|
return filteredDeps.map { runtimeConfiguration.files(it) }.flatten().toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.configuration(name: String): Configuration = configurations.single { it.name == name }
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,17 @@
|
|||||||
package net.corda.plugins
|
package net.corda.plugins
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.Task
|
||||||
import org.gradle.api.artifacts.Configuration
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mimics the "project.ext" functionality in groovy which provides a direct
|
||||||
|
* accessor to the "ext" extention (See: ExtraPropertiesExtension)
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : Any> Project.ext(name: String): T = (extensions.findByName("ext") as ExtraPropertiesExtension).get(name) as T
|
||||||
|
fun Project.configuration(name: String): Configuration = configurations.single { it.name == name }
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
companion object {
|
companion object {
|
||||||
@ -14,4 +24,5 @@ class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -8,7 +8,6 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'groovy'
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'net.corda.plugins.publish-utils'
|
apply plugin: 'net.corda.plugins.publish-utils'
|
||||||
|
|
||||||
@ -34,8 +33,8 @@ sourceSets {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile gradleApi()
|
compile gradleApi()
|
||||||
compile localGroovy()
|
|
||||||
compile project(":cordapp")
|
compile project(":cordapp")
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||||
|
|
||||||
noderunner "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
noderunner "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||||
|
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
package net.corda.plugins
|
|
||||||
|
|
||||||
import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
|
|
||||||
import net.corda.cordform.CordformContext
|
|
||||||
import net.corda.cordform.CordformDefinition
|
|
||||||
import org.apache.tools.ant.filters.FixCrLfFilter
|
|
||||||
import org.gradle.api.DefaultTask
|
|
||||||
import org.gradle.api.plugins.JavaPluginConvention
|
|
||||||
import org.gradle.api.tasks.TaskAction
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates nodes based on the configuration of this task in the gradle configuration DSL.
|
|
||||||
*
|
|
||||||
* See documentation for examples.
|
|
||||||
*/
|
|
||||||
class Cordform extends DefaultTask {
|
|
||||||
/**
|
|
||||||
* Optionally the name of a CordformDefinition subclass to which all configuration will be delegated.
|
|
||||||
*/
|
|
||||||
String definitionClass
|
|
||||||
protected def directory = Paths.get("build", "nodes")
|
|
||||||
private def nodes = new ArrayList<Node>()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the directory to install nodes into.
|
|
||||||
*
|
|
||||||
* @param directory The directory the nodes will be installed into.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
void directory(String directory) {
|
|
||||||
this.directory = Paths.get(directory)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a node configuration.
|
|
||||||
*
|
|
||||||
* @param configureClosure A node configuration that will be deployed.
|
|
||||||
*/
|
|
||||||
void node(Closure configureClosure) {
|
|
||||||
nodes << (Node) project.configure(new Node(project), configureClosure)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a node by name.
|
|
||||||
*
|
|
||||||
* @param name The name of the node as specified in the node configuration DSL.
|
|
||||||
* @return A node instance.
|
|
||||||
*/
|
|
||||||
private Node getNodeByName(String name) {
|
|
||||||
for (Node node : nodes) {
|
|
||||||
if (node.name == name) {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the run script into the nodes directory.
|
|
||||||
*/
|
|
||||||
private void installRunScript() {
|
|
||||||
project.copy {
|
|
||||||
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.jar")
|
|
||||||
fileMode 0755
|
|
||||||
into "${directory}/"
|
|
||||||
}
|
|
||||||
|
|
||||||
project.copy {
|
|
||||||
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes")
|
|
||||||
// Replaces end of line with lf to avoid issues with the bash interpreter and Windows style line endings.
|
|
||||||
filter(FixCrLfFilter.class, eol: FixCrLfFilter.CrLf.newInstance("lf"))
|
|
||||||
fileMode 0755
|
|
||||||
into "${directory}/"
|
|
||||||
}
|
|
||||||
|
|
||||||
project.copy {
|
|
||||||
from Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.bat")
|
|
||||||
into "${directory}/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The definitionClass needn't be compiled until just before our build method, so we load it manually via sourceSets.main.runtimeClasspath.
|
|
||||||
*/
|
|
||||||
private CordformDefinition loadCordformDefinition() {
|
|
||||||
def plugin = project.convention.getPlugin(JavaPluginConvention.class)
|
|
||||||
def classpath = plugin.sourceSets.getByName(MAIN_SOURCE_SET_NAME).runtimeClasspath
|
|
||||||
URL[] urls = classpath.files.collect { it.toURI().toURL() }
|
|
||||||
(CordformDefinition) new URLClassLoader(urls, CordformDefinition.classLoader).loadClass(definitionClass).newInstance()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This task action will create and install the nodes based on the node configurations added.
|
|
||||||
*/
|
|
||||||
@TaskAction
|
|
||||||
void build() {
|
|
||||||
initializeConfiguration()
|
|
||||||
installRunScript()
|
|
||||||
nodes.each {
|
|
||||||
it.build()
|
|
||||||
}
|
|
||||||
generateNodeInfos()
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeConfiguration() {
|
|
||||||
if (null != definitionClass) {
|
|
||||||
def cd = loadCordformDefinition()
|
|
||||||
cd.nodeConfigurers.each { nc ->
|
|
||||||
node { Node it ->
|
|
||||||
nc.accept it
|
|
||||||
it.rootDir directory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cd.setup new CordformContext() {
|
|
||||||
Path baseDirectory(String nodeName) {
|
|
||||||
project.projectDir.toPath().resolve(getNodeByName(nodeName).nodeDir.toPath())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nodes.each {
|
|
||||||
it.rootDir directory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Path fullNodePath(Node node) {
|
|
||||||
return project.projectDir.toPath().resolve(node.nodeDir.toPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
private generateNodeInfos() {
|
|
||||||
nodes.each { Node node ->
|
|
||||||
def process = new ProcessBuilder("java", "-jar", Node.NODEJAR_NAME, "--just-generate-node-info")
|
|
||||||
.directory(fullNodePath(node).toFile())
|
|
||||||
.redirectErrorStream(true)
|
|
||||||
.start()
|
|
||||||
.waitFor()
|
|
||||||
}
|
|
||||||
for (source in nodes) {
|
|
||||||
for (destination in nodes) {
|
|
||||||
if (source.nodeDir != destination.nodeDir) {
|
|
||||||
project.copy {
|
|
||||||
from fullNodePath(source).toString()
|
|
||||||
include 'nodeInfo-*'
|
|
||||||
into fullNodePath(destination).resolve(Node.NODE_INFO_DIRECTORY).toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package net.corda.plugins
|
|
||||||
|
|
||||||
import org.gradle.api.Plugin
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.artifacts.Configuration
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Cordformation plugin deploys nodes to a directory in a state ready to be used by a developer for experimentation,
|
|
||||||
* testing, and debugging. It will prepopulate several fields in the configuration and create a simple node runner.
|
|
||||||
*/
|
|
||||||
class Cordformation implements Plugin<Project> {
|
|
||||||
/**
|
|
||||||
* Gets a resource file from this plugin's JAR file.
|
|
||||||
*
|
|
||||||
* @param project The project environment this plugin executes in.
|
|
||||||
* @param filePathInJar The file in the JAR, relative to root, you wish to access.
|
|
||||||
* @return A file handle to the file in the JAR.
|
|
||||||
*/
|
|
||||||
protected static File getPluginFile(Project project, String filePathInJar) {
|
|
||||||
return project.rootProject.resources.text.fromArchiveEntry(project.rootProject.buildscript.configurations.classpath.find {
|
|
||||||
it.name.contains('cordformation')
|
|
||||||
}, filePathInJar).asFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
void apply(Project project) {
|
|
||||||
Utils.createCompileConfiguration("cordapp", project)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,268 +0,0 @@
|
|||||||
package net.corda.plugins
|
|
||||||
|
|
||||||
import com.typesafe.config.*
|
|
||||||
import net.corda.cordform.CordformNode
|
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import java.nio.charset.StandardCharsets
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a node that will be installed.
|
|
||||||
*/
|
|
||||||
class Node extends CordformNode {
|
|
||||||
static final String NODEJAR_NAME = 'corda.jar'
|
|
||||||
static final String WEBJAR_NAME = 'corda-webserver.jar'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
protected List<String> cordapps = []
|
|
||||||
|
|
||||||
protected File nodeDir
|
|
||||||
private Project project
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether this node will use HTTPS communication.
|
|
||||||
*
|
|
||||||
* @param isHttps True if this node uses HTTPS communication.
|
|
||||||
*/
|
|
||||||
void https(Boolean isHttps) {
|
|
||||||
config = config.withValue("useHTTPS", ConfigValueFactory.fromAnyRef(isHttps))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the H2 port for this node
|
|
||||||
*/
|
|
||||||
void h2Port(Integer h2Port) {
|
|
||||||
config = config.withValue("h2port", ConfigValueFactory.fromAnyRef(h2Port))
|
|
||||||
}
|
|
||||||
|
|
||||||
void useTestClock(Boolean useTestClock) {
|
|
||||||
config = config.withValue("useTestClock", ConfigValueFactory.fromAnyRef(useTestClock))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the HTTP web server port for this node.
|
|
||||||
*
|
|
||||||
* @param webPort The web port number for this node.
|
|
||||||
*/
|
|
||||||
void webPort(Integer webPort) {
|
|
||||||
config = config.withValue("webAddress",
|
|
||||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$webPort".toString()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the network map address for this node.
|
|
||||||
*
|
|
||||||
* @warning This should not be directly set unless you know what you are doing. Use the networkMapName in the
|
|
||||||
* Cordform task instead.
|
|
||||||
* @param networkMapAddress Network map node address.
|
|
||||||
* @param networkMapLegalName Network map node legal name.
|
|
||||||
*/
|
|
||||||
void networkMapAddress(String networkMapAddress, String networkMapLegalName) {
|
|
||||||
def networkMapService = new HashMap()
|
|
||||||
networkMapService.put("address", networkMapAddress)
|
|
||||||
networkMapService.put("legalName", networkMapLegalName)
|
|
||||||
config = config.withValue("networkMapService", ConfigValueFactory.fromMap(networkMapService))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the SSHD port for this node.
|
|
||||||
*
|
|
||||||
* @param sshdPort The SSHD port.
|
|
||||||
*/
|
|
||||||
void sshdPort(Integer sshdPort) {
|
|
||||||
config = config.withValue("sshdAddress",
|
|
||||||
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$sshdPort".toString()))
|
|
||||||
}
|
|
||||||
|
|
||||||
Node(Project project) {
|
|
||||||
this.project = project
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void rootDir(Path rootDir) {
|
|
||||||
def dirName
|
|
||||||
try {
|
|
||||||
X500Name x500Name = new X500Name(name)
|
|
||||||
dirName = x500Name.getRDNs(BCStyle.O).getAt(0).getFirst().getValue().toString()
|
|
||||||
} catch(IllegalArgumentException ignore) {
|
|
||||||
// Can't parse as an X500 name, use the full string
|
|
||||||
dirName = name
|
|
||||||
}
|
|
||||||
nodeDir = new File(rootDir.toFile(), dirName.replaceAll("\\s",""))
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void build() {
|
|
||||||
configureProperties()
|
|
||||||
installCordaJar()
|
|
||||||
if (config.hasPath("webAddress")) {
|
|
||||||
installWebserverJar()
|
|
||||||
}
|
|
||||||
installBuiltCordapp()
|
|
||||||
installCordapps()
|
|
||||||
installConfig()
|
|
||||||
appendOptionalConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the artemis address for this node.
|
|
||||||
*
|
|
||||||
* @return This node's P2P address.
|
|
||||||
*/
|
|
||||||
String getP2PAddress() {
|
|
||||||
return config.getString("p2pAddress")
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureProperties() {
|
|
||||||
config = config.withValue("rpcUsers", ConfigValueFactory.fromIterable(rpcUsers))
|
|
||||||
if (notary) {
|
|
||||||
config = config.withValue("notary", ConfigValueFactory.fromMap(notary))
|
|
||||||
}
|
|
||||||
if (extraConfig) {
|
|
||||||
config = config.withFallback(ConfigFactory.parseMap(extraConfig))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the corda fat JAR to the node directory.
|
|
||||||
*/
|
|
||||||
private void installCordaJar() {
|
|
||||||
def cordaJar = verifyAndGetCordaJar()
|
|
||||||
project.copy {
|
|
||||||
from cordaJar
|
|
||||||
into nodeDir
|
|
||||||
rename cordaJar.name, NODEJAR_NAME
|
|
||||||
fileMode 0755
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the corda webserver JAR to the node directory
|
|
||||||
*/
|
|
||||||
private void installWebserverJar() {
|
|
||||||
def webJar = verifyAndGetWebserverJar()
|
|
||||||
project.copy {
|
|
||||||
from webJar
|
|
||||||
into nodeDir
|
|
||||||
rename webJar.name, WEBJAR_NAME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs this project's cordapp to this directory.
|
|
||||||
*/
|
|
||||||
private void installBuiltCordapp() {
|
|
||||||
def cordappsDir = new File(nodeDir, "cordapps")
|
|
||||||
project.copy {
|
|
||||||
from project.jar
|
|
||||||
into cordappsDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs other cordapps to this node's cordapps directory.
|
|
||||||
*/
|
|
||||||
private void installCordapps() {
|
|
||||||
def cordappsDir = new File(nodeDir, "cordapps")
|
|
||||||
def cordapps = getCordappList()
|
|
||||||
project.copy {
|
|
||||||
from cordapps
|
|
||||||
into cordappsDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the configuration file to this node's directory and detokenises it.
|
|
||||||
*/
|
|
||||||
private void installConfig() {
|
|
||||||
def configFileText = config.root().render(new ConfigRenderOptions(false, false, true, false)).split("\n").toList()
|
|
||||||
|
|
||||||
// Need to write a temporary file first to use the project.copy, which resolves directories correctly.
|
|
||||||
def tmpDir = new File(project.buildDir, "tmp")
|
|
||||||
def tmpConfFile = new File(tmpDir, 'node.conf')
|
|
||||||
Files.write(tmpConfFile.toPath(), configFileText, StandardCharsets.UTF_8)
|
|
||||||
|
|
||||||
project.copy {
|
|
||||||
from tmpConfFile
|
|
||||||
into nodeDir
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends installed config file with properties from an optional file.
|
|
||||||
*/
|
|
||||||
private void appendOptionalConfig() {
|
|
||||||
final configFileProperty = "configFile"
|
|
||||||
File optionalConfig
|
|
||||||
if (project.findProperty(configFileProperty)) { //provided by -PconfigFile command line property when running Gradle task
|
|
||||||
optionalConfig = new File(project.findProperty(configFileProperty))
|
|
||||||
} else if (config.hasPath(configFileProperty)) {
|
|
||||||
optionalConfig = new File(config.getString(configFileProperty))
|
|
||||||
}
|
|
||||||
if (optionalConfig) {
|
|
||||||
if (!optionalConfig.exists()) {
|
|
||||||
println "$configFileProperty '$optionalConfig' not found"
|
|
||||||
} else {
|
|
||||||
def confFile = new File(project.buildDir.getPath() + "/../" + nodeDir, 'node.conf')
|
|
||||||
optionalConfig.withInputStream {
|
|
||||||
input -> confFile << input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the corda JAR amongst the dependencies.
|
|
||||||
*
|
|
||||||
* @return A file representing the Corda JAR.
|
|
||||||
*/
|
|
||||||
private File verifyAndGetCordaJar() {
|
|
||||||
def maybeCordaJAR = project.configurations.runtime.filter {
|
|
||||||
it.toString().contains("corda-${project.corda_release_version}.jar") || it.toString().contains("corda-enterprise-${project.corda_release_version}.jar")
|
|
||||||
}
|
|
||||||
if (maybeCordaJAR.size() == 0) {
|
|
||||||
throw new RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-${project.corda_release_version}.jar\"")
|
|
||||||
} else {
|
|
||||||
def cordaJar = maybeCordaJAR.getSingleFile()
|
|
||||||
assert(cordaJar.isFile())
|
|
||||||
return cordaJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the corda JAR amongst the dependencies
|
|
||||||
*
|
|
||||||
* @return A file representing the Corda webserver JAR
|
|
||||||
*/
|
|
||||||
private File verifyAndGetWebserverJar() {
|
|
||||||
def maybeJar = project.configurations.runtime.filter {
|
|
||||||
it.toString().contains("corda-webserver-${project.corda_release_version}.jar")
|
|
||||||
}
|
|
||||||
if (maybeJar.size() == 0) {
|
|
||||||
throw new RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-${project.corda_release_version}.jar\"")
|
|
||||||
} else {
|
|
||||||
def jar = maybeJar.getSingleFile()
|
|
||||||
assert(jar.isFile())
|
|
||||||
return jar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a list of cordapps based on what dependent cordapps were specified.
|
|
||||||
*
|
|
||||||
* @return List of this node's cordapps.
|
|
||||||
*/
|
|
||||||
private Collection<File> getCordappList() {
|
|
||||||
// Cordapps can sometimes contain a GString instance which fails the equality test with the Java string
|
|
||||||
List<String> cordapps = this.cordapps.collect { it.toString() }
|
|
||||||
return project.configurations.cordapp.files {
|
|
||||||
cordapps.contains(it.group + ":" + it.name + ":" + it.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,198 @@
|
|||||||
|
package net.corda.plugins
|
||||||
|
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import net.corda.cordform.CordformDefinition
|
||||||
|
import net.corda.cordform.CordformNode
|
||||||
|
import org.apache.tools.ant.filters.FixCrLfFilter
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.plugins.JavaPluginConvention
|
||||||
|
import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates nodes based on the configuration of this task in the gradle configuration DSL.
|
||||||
|
*
|
||||||
|
* See documentation for examples.
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
open class Cordform : DefaultTask() {
|
||||||
|
/**
|
||||||
|
* Optionally the name of a CordformDefinition subclass to which all configuration will be delegated.
|
||||||
|
*/
|
||||||
|
@Suppress("MemberVisibilityCanPrivate")
|
||||||
|
var definitionClass: String? = null
|
||||||
|
private var directory = Paths.get("build", "nodes")
|
||||||
|
private val nodes = mutableListOf<Node>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the directory to install nodes into.
|
||||||
|
*
|
||||||
|
* @param directory The directory the nodes will be installed into.
|
||||||
|
*/
|
||||||
|
fun directory(directory: String) {
|
||||||
|
this.directory = Paths.get(directory)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a node configuration.
|
||||||
|
*
|
||||||
|
* @param configureClosure A node configuration that will be deployed.
|
||||||
|
*/
|
||||||
|
@Suppress("MemberVisibilityCanPrivate")
|
||||||
|
fun node(configureClosure: Closure<in Node>) {
|
||||||
|
nodes += project.configure(Node(project), configureClosure) as Node
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a node configuration
|
||||||
|
*
|
||||||
|
* @param configureFunc A node configuration that will be deployed
|
||||||
|
*/
|
||||||
|
@Suppress("MemberVisibilityCanPrivate")
|
||||||
|
fun node(configureFunc: Node.() -> Any?): Node {
|
||||||
|
val node = Node(project).apply { configureFunc() }
|
||||||
|
nodes += node
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a node by name.
|
||||||
|
*
|
||||||
|
* @param name The name of the node as specified in the node configuration DSL.
|
||||||
|
* @return A node instance.
|
||||||
|
*/
|
||||||
|
private fun getNodeByName(name: String): Node? = nodes.firstOrNull { it.name == name }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the run script into the nodes directory.
|
||||||
|
*/
|
||||||
|
private fun installRunScript() {
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.jar"))
|
||||||
|
fileMode = Cordformation.executableFileMode
|
||||||
|
into("$directory/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(Cordformation.getPluginFile(project, "net/corda/plugins/runnodes"))
|
||||||
|
// Replaces end of line with lf to avoid issues with the bash interpreter and Windows style line endings.
|
||||||
|
filter(mapOf("eol" to FixCrLfFilter.CrLf.newInstance("lf")), FixCrLfFilter::class.java)
|
||||||
|
fileMode = Cordformation.executableFileMode
|
||||||
|
into("$directory/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(Cordformation.getPluginFile(project, "net/corda/plugins/runnodes.bat"))
|
||||||
|
into("$directory/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definitionClass needn't be compiled until just before our build method, so we load it manually via sourceSets.main.runtimeClasspath.
|
||||||
|
*/
|
||||||
|
private fun loadCordformDefinition(): CordformDefinition {
|
||||||
|
val plugin = project.convention.getPlugin(JavaPluginConvention::class.java)
|
||||||
|
val classpath = plugin.sourceSets.getByName(MAIN_SOURCE_SET_NAME).runtimeClasspath
|
||||||
|
val urls = classpath.files.map { it.toURI().toURL() }.toTypedArray()
|
||||||
|
return URLClassLoader(urls, CordformDefinition::class.java.classLoader)
|
||||||
|
.loadClass(definitionClass)
|
||||||
|
.asSubclass(CordformDefinition::class.java)
|
||||||
|
.newInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This task action will create and install the nodes based on the node configurations added.
|
||||||
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
|
@TaskAction
|
||||||
|
fun build() {
|
||||||
|
project.logger.info("Running Cordform task")
|
||||||
|
initializeConfiguration()
|
||||||
|
installRunScript()
|
||||||
|
nodes.forEach(Node::build)
|
||||||
|
generateAndInstallNodeInfos()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeConfiguration() {
|
||||||
|
if (definitionClass != null) {
|
||||||
|
val cd = loadCordformDefinition()
|
||||||
|
cd.nodeConfigurers.forEach {
|
||||||
|
val node = node { }
|
||||||
|
it.accept(node)
|
||||||
|
node.rootDir(directory)
|
||||||
|
}
|
||||||
|
cd.setup { nodeName -> project.projectDir.toPath().resolve(getNodeByName(nodeName)!!.nodeDir.toPath()) }
|
||||||
|
} else {
|
||||||
|
nodes.forEach {
|
||||||
|
it.rootDir(directory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fullNodePath(node: Node): Path = project.projectDir.toPath().resolve(node.nodeDir.toPath())
|
||||||
|
|
||||||
|
private fun generateAndInstallNodeInfos() {
|
||||||
|
generateNodeInfos()
|
||||||
|
installNodeInfos()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateNodeInfos() {
|
||||||
|
project.logger.info("Generating node infos")
|
||||||
|
val generateTimeoutSeconds = 60L
|
||||||
|
val processes = nodes.map { node ->
|
||||||
|
project.logger.info("Generating node info for ${fullNodePath(node)}")
|
||||||
|
val logDir = File(fullNodePath(node).toFile(), "logs")
|
||||||
|
logDir.mkdirs() // Directory may not exist at this point
|
||||||
|
Pair(node, ProcessBuilder("java", "-jar", Node.nodeJarName, "--just-generate-node-info")
|
||||||
|
.directory(fullNodePath(node).toFile())
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
// InheritIO causes hangs on windows due the gradle buffer also not being flushed.
|
||||||
|
// Must redirect to output or logger (node log is still written, this is just startup banner)
|
||||||
|
.redirectOutput(File(logDir, "generate-info-log.txt"))
|
||||||
|
.start())
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
processes.parallelStream().forEach { (node, process) ->
|
||||||
|
if (!process.waitFor(generateTimeoutSeconds, TimeUnit.SECONDS)) {
|
||||||
|
throw GradleException("Node took longer $generateTimeoutSeconds seconds than too to generate node info - see node log at ${fullNodePath(node)}/logs")
|
||||||
|
} else if (process.exitValue() != 0) {
|
||||||
|
throw GradleException("Node exited with ${process.exitValue()} when generating node infos - see node log at ${fullNodePath(node)}/logs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// This will be a no-op on success - abort remaining on failure
|
||||||
|
processes.forEach {
|
||||||
|
it.second.destroyForcibly()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun installNodeInfos() {
|
||||||
|
project.logger.info("Installing node infos")
|
||||||
|
for (source in nodes) {
|
||||||
|
for (destination in nodes) {
|
||||||
|
if (source.nodeDir != destination.nodeDir) {
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(fullNodePath(source).toString())
|
||||||
|
include("nodeInfo-*")
|
||||||
|
into(fullNodePath(destination).resolve(CordformNode.NODE_INFO_DIRECTORY).toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.corda.plugins
|
||||||
|
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Cordformation plugin deploys nodes to a directory in a state ready to be used by a developer for experimentation,
|
||||||
|
* testing, and debugging. It will prepopulate several fields in the configuration and create a simple node runner.
|
||||||
|
*/
|
||||||
|
class Cordformation : Plugin<Project> {
|
||||||
|
internal companion object {
|
||||||
|
/**
|
||||||
|
* Gets a resource file from this plugin's JAR file.
|
||||||
|
*
|
||||||
|
* @param project The project environment this plugin executes in.
|
||||||
|
* @param filePathInJar The file in the JAR, relative to root, you wish to access.
|
||||||
|
* @return A file handle to the file in the JAR.
|
||||||
|
*/
|
||||||
|
fun getPluginFile(project: Project, filePathInJar: String): File {
|
||||||
|
val archive: File? = project.rootProject.buildscript.configurations.single { it.name == "classpath" }.find {
|
||||||
|
it.name.contains("cordformation")
|
||||||
|
}
|
||||||
|
return project.rootProject.resources.text.fromArchiveEntry(archive, filePathInJar).asFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
val executableFileMode = "0755".toInt(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(project: Project) {
|
||||||
|
Utils.createCompileConfiguration("cordapp", project)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,284 @@
|
|||||||
|
package net.corda.plugins
|
||||||
|
|
||||||
|
import com.typesafe.config.*
|
||||||
|
import net.corda.cordform.CordformNode
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a node that will be installed.
|
||||||
|
*/
|
||||||
|
class Node(private val project: Project) : CordformNode() {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
val nodeJarName = "corda.jar"
|
||||||
|
@JvmStatic
|
||||||
|
val webJarName = "corda-webserver.jar"
|
||||||
|
private val configFileProperty = "configFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of CorDapps to install to the plugins 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.
|
||||||
|
* @note Type is any due to gradle's use of "GStrings" - each value will have "toString" called on it
|
||||||
|
*/
|
||||||
|
var cordapps = mutableListOf<Any>()
|
||||||
|
|
||||||
|
private val releaseVersion = project.rootProject.ext<String>("corda_release_version")
|
||||||
|
internal lateinit var nodeDir: File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this node will use HTTPS communication.
|
||||||
|
*
|
||||||
|
* @param isHttps True if this node uses HTTPS communication.
|
||||||
|
*/
|
||||||
|
fun https(isHttps: Boolean) {
|
||||||
|
config = config.withValue("useHTTPS", ConfigValueFactory.fromAnyRef(isHttps))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the H2 port for this node
|
||||||
|
*/
|
||||||
|
fun h2Port(h2Port: Int) {
|
||||||
|
config = config.withValue("h2port", ConfigValueFactory.fromAnyRef(h2Port))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun useTestClock(useTestClock: Boolean) {
|
||||||
|
config = config.withValue("useTestClock", ConfigValueFactory.fromAnyRef(useTestClock))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the HTTP web server port for this node.
|
||||||
|
*
|
||||||
|
* @param webPort The web port number for this node.
|
||||||
|
*/
|
||||||
|
fun webPort(webPort: Int) {
|
||||||
|
config = config.withValue("webAddress",
|
||||||
|
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$webPort"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the network map address for this node.
|
||||||
|
*
|
||||||
|
* @warning This should not be directly set unless you know what you are doing. Use the networkMapName in the
|
||||||
|
* Cordform task instead.
|
||||||
|
* @param networkMapAddress Network map node address.
|
||||||
|
* @param networkMapLegalName Network map node legal name.
|
||||||
|
*/
|
||||||
|
fun networkMapAddress(networkMapAddress: String, networkMapLegalName: String) {
|
||||||
|
val networkMapService = mutableMapOf<String, String>()
|
||||||
|
networkMapService.put("address", networkMapAddress)
|
||||||
|
networkMapService.put("legalName", networkMapLegalName)
|
||||||
|
config = config.withValue("networkMapService", ConfigValueFactory.fromMap(networkMapService))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the SSHD port for this node.
|
||||||
|
*
|
||||||
|
* @param sshdPort The SSHD port.
|
||||||
|
*/
|
||||||
|
fun sshdPort(sshdPort: Int) {
|
||||||
|
config = config.withValue("sshdAddress",
|
||||||
|
ConfigValueFactory.fromAnyRef("$DEFAULT_HOST:$sshdPort"))
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun build() {
|
||||||
|
configureProperties()
|
||||||
|
installCordaJar()
|
||||||
|
if (config.hasPath("webAddress")) {
|
||||||
|
installWebserverJar()
|
||||||
|
}
|
||||||
|
installBuiltCordapp()
|
||||||
|
installCordapps()
|
||||||
|
installConfig()
|
||||||
|
appendOptionalConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the artemis address for this node.
|
||||||
|
*
|
||||||
|
* @return This node's P2P address.
|
||||||
|
*/
|
||||||
|
fun getP2PAddress(): String {
|
||||||
|
return config.getString("p2pAddress")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun rootDir(rootDir: Path) {
|
||||||
|
if(name == null) {
|
||||||
|
project.logger.error("Node has a null name - cannot create node")
|
||||||
|
throw IllegalStateException("Node has a null name - cannot create node")
|
||||||
|
}
|
||||||
|
|
||||||
|
val dirName = try {
|
||||||
|
X500Name(name).getRDNs(BCStyle.O).first().first.value.toString()
|
||||||
|
} catch(_ : IllegalArgumentException) {
|
||||||
|
// Can't parse as an X500 name, use the full string
|
||||||
|
name
|
||||||
|
}
|
||||||
|
nodeDir = File(rootDir.toFile(), dirName.replace("\\s", ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureProperties() {
|
||||||
|
config = config.withValue("rpcUsers", ConfigValueFactory.fromIterable(rpcUsers))
|
||||||
|
if (notary != null) {
|
||||||
|
config = config.withValue("notary", ConfigValueFactory.fromMap(notary))
|
||||||
|
}
|
||||||
|
if (extraConfig != null) {
|
||||||
|
config = config.withFallback(ConfigFactory.parseMap(extraConfig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the corda fat JAR to the node directory.
|
||||||
|
*/
|
||||||
|
private fun installCordaJar() {
|
||||||
|
val cordaJar = verifyAndGetCordaJar()
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(cordaJar)
|
||||||
|
into(nodeDir)
|
||||||
|
rename(cordaJar.name, nodeJarName)
|
||||||
|
fileMode = Cordformation.executableFileMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the corda webserver JAR to the node directory
|
||||||
|
*/
|
||||||
|
private fun installWebserverJar() {
|
||||||
|
val webJar = verifyAndGetWebserverJar()
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(webJar)
|
||||||
|
into(nodeDir)
|
||||||
|
rename(webJar.name, webJarName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs this project's cordapp to this directory.
|
||||||
|
*/
|
||||||
|
private fun installBuiltCordapp() {
|
||||||
|
val cordappsDir = File(nodeDir, "cordapps")
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(project.tasks.getByName("jar"))
|
||||||
|
into(cordappsDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs other cordapps to this node's cordapps directory.
|
||||||
|
*/
|
||||||
|
private fun installCordapps() {
|
||||||
|
val cordappsDir = File(nodeDir, "cordapps")
|
||||||
|
val cordapps = getCordappList()
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(cordapps)
|
||||||
|
into(cordappsDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the configuration file to this node's directory and detokenises it.
|
||||||
|
*/
|
||||||
|
private fun installConfig() {
|
||||||
|
val options = ConfigRenderOptions.defaults().setOriginComments(false).setComments(false).setFormatted(false).setJson(false)
|
||||||
|
val configFileText = config.root().render(options).split("\n").toList()
|
||||||
|
|
||||||
|
// Need to write a temporary file first to use the project.copy, which resolves directories correctly.
|
||||||
|
val tmpDir = File(project.buildDir, "tmp")
|
||||||
|
val tmpConfFile = File(tmpDir, "node.conf")
|
||||||
|
Files.write(tmpConfFile.toPath(), configFileText, StandardCharsets.UTF_8)
|
||||||
|
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(tmpConfFile)
|
||||||
|
into(nodeDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends installed config file with properties from an optional file.
|
||||||
|
*/
|
||||||
|
private fun appendOptionalConfig() {
|
||||||
|
val optionalConfig: File? = when {
|
||||||
|
project.findProperty(configFileProperty) != null -> //provided by -PconfigFile command line property when running Gradle task
|
||||||
|
File(project.findProperty(configFileProperty) as String)
|
||||||
|
config.hasPath(configFileProperty) -> File(config.getString(configFileProperty))
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionalConfig != null) {
|
||||||
|
if (!optionalConfig.exists()) {
|
||||||
|
project.logger.error("$configFileProperty '$optionalConfig' not found")
|
||||||
|
} else {
|
||||||
|
val confFile = File(project.buildDir.path + "/../" + nodeDir, "node.conf")
|
||||||
|
confFile.appendBytes(optionalConfig.readBytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the corda JAR amongst the dependencies.
|
||||||
|
*
|
||||||
|
* @return A file representing the Corda JAR.
|
||||||
|
*/
|
||||||
|
private fun verifyAndGetCordaJar(): File {
|
||||||
|
val maybeCordaJAR = project.configuration("runtime").filter {
|
||||||
|
it.toString().contains("corda-$releaseVersion.jar") || it.toString().contains("corda-enterprise-$releaseVersion.jar")
|
||||||
|
}
|
||||||
|
if (maybeCordaJAR.isEmpty) {
|
||||||
|
throw RuntimeException("No Corda Capsule JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-$releaseVersion.jar\"")
|
||||||
|
} else {
|
||||||
|
val cordaJar = maybeCordaJAR.singleFile
|
||||||
|
assert(cordaJar.isFile)
|
||||||
|
return cordaJar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the corda JAR amongst the dependencies
|
||||||
|
*
|
||||||
|
* @return A file representing the Corda webserver JAR
|
||||||
|
*/
|
||||||
|
private fun verifyAndGetWebserverJar(): File {
|
||||||
|
val maybeJar = project.configuration("runtime").filter {
|
||||||
|
it.toString().contains("corda-webserver-$releaseVersion.jar")
|
||||||
|
}
|
||||||
|
if (maybeJar.isEmpty) {
|
||||||
|
throw RuntimeException("No Corda Webserver JAR found. Have you deployed the Corda project to Maven? Looked for \"corda-webserver-$releaseVersion.jar\"")
|
||||||
|
} else {
|
||||||
|
val jar = maybeJar.singleFile
|
||||||
|
assert(jar.isFile)
|
||||||
|
return jar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of cordapps based on what dependent cordapps were specified.
|
||||||
|
*
|
||||||
|
* @return List of this node's cordapps.
|
||||||
|
*/
|
||||||
|
private fun getCordappList(): Collection<File> {
|
||||||
|
// Cordapps can sometimes contain a GString instance which fails the equality test with the Java string
|
||||||
|
@Suppress("RemoveRedundantCallsOfConversionMethods")
|
||||||
|
val cordapps: List<String> = cordapps.map { it.toString() }
|
||||||
|
return project.configuration("cordapp").files {
|
||||||
|
cordapps.contains(it.group + ":" + it.name + ":" + it.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -80,6 +80,7 @@ open class NodeStartup(val args: Array<String>) {
|
|||||||
exitProcess(1)
|
exitProcess(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Node exiting successfully")
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ import net.corda.testing.internal.demorun.notary
|
|||||||
import net.corda.testing.internal.demorun.rpcUsers
|
import net.corda.testing.internal.demorun.rpcUsers
|
||||||
import net.corda.testing.internal.demorun.runNodes
|
import net.corda.testing.internal.demorun.runNodes
|
||||||
|
|
||||||
fun main(args: Array<String>) = BFTNotaryCordform.runNodes()
|
fun main(args: Array<String>) = BFTNotaryCordform().runNodes()
|
||||||
|
|
||||||
private val clusterSize = 4 // Minimum size that tolerates a faulty replica.
|
private val clusterSize = 4 // Minimum size that tolerates a faulty replica.
|
||||||
private val notaryNames = createNotaryNames(clusterSize)
|
private val notaryNames = createNotaryNames(clusterSize)
|
||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
||||||
// NOT use this as a design to copy.
|
// NOT use this as a design to copy.
|
||||||
object BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
class BFTNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
||||||
private val clusterName = CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH")
|
private val clusterName = CordaX500Name(BFTNonValidatingNotaryService.id, "BFT", "Zurich", "CH")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -3,7 +3,7 @@ package net.corda.notarydemo
|
|||||||
import net.corda.testing.internal.demorun.clean
|
import net.corda.testing.internal.demorun.clean
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
listOf(SingleNotaryCordform, RaftNotaryCordform, BFTNotaryCordform).forEach {
|
listOf(SingleNotaryCordform(), RaftNotaryCordform(), BFTNotaryCordform()).forEach {
|
||||||
it.clean()
|
it.clean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ import net.corda.testing.BOB
|
|||||||
import net.corda.testing.DUMMY_NOTARY
|
import net.corda.testing.DUMMY_NOTARY
|
||||||
import net.corda.testing.internal.demorun.*
|
import net.corda.testing.internal.demorun.*
|
||||||
|
|
||||||
fun main(args: Array<String>) = CustomNotaryCordform.runNodes()
|
fun main(args: Array<String>) = CustomNotaryCordform().runNodes()
|
||||||
|
|
||||||
object CustomNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
class CustomNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
||||||
init {
|
init {
|
||||||
node {
|
node {
|
||||||
name(ALICE.name)
|
name(ALICE.name)
|
||||||
|
@ -14,7 +14,7 @@ import net.corda.testing.ALICE
|
|||||||
import net.corda.testing.BOB
|
import net.corda.testing.BOB
|
||||||
import net.corda.testing.internal.demorun.*
|
import net.corda.testing.internal.demorun.*
|
||||||
|
|
||||||
fun main(args: Array<String>) = RaftNotaryCordform.runNodes()
|
fun main(args: Array<String>) = RaftNotaryCordform().runNodes()
|
||||||
|
|
||||||
internal fun createNotaryNames(clusterSize: Int) = (0 until clusterSize).map { CordaX500Name("Notary Service $it", "Zurich", "CH") }
|
internal fun createNotaryNames(clusterSize: Int) = (0 until clusterSize).map { CordaX500Name("Notary Service $it", "Zurich", "CH") }
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ private val notaryNames = createNotaryNames(3)
|
|||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
||||||
// NOT use this as a design to copy.
|
// NOT use this as a design to copy.
|
||||||
object RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
class RaftNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
||||||
private val clusterName = CordaX500Name(RaftValidatingNotaryService.id, "Raft", "Zurich", "CH")
|
private val clusterName = CordaX500Name(RaftValidatingNotaryService.id, "Raft", "Zurich", "CH")
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -17,13 +17,13 @@ import net.corda.testing.internal.demorun.notary
|
|||||||
import net.corda.testing.internal.demorun.rpcUsers
|
import net.corda.testing.internal.demorun.rpcUsers
|
||||||
import net.corda.testing.internal.demorun.runNodes
|
import net.corda.testing.internal.demorun.runNodes
|
||||||
|
|
||||||
fun main(args: Array<String>) = SingleNotaryCordform.runNodes()
|
fun main(args: Array<String>) = SingleNotaryCordform().runNodes()
|
||||||
|
|
||||||
val notaryDemoUser = User("demou", "demop", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<RPCStartableNotaryFlowClient>()))
|
val notaryDemoUser = User("demou", "demop", setOf(startFlowPermission<DummyIssueAndMove>(), startFlowPermission<RPCStartableNotaryFlowClient>()))
|
||||||
|
|
||||||
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
// This is not the intended final design for how to use CordformDefinition, please treat this as experimental and DO
|
||||||
// NOT use this as a design to copy.
|
// NOT use this as a design to copy.
|
||||||
object SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
class SingleNotaryCordform : CordformDefinition("build" / "notary-demo-nodes") {
|
||||||
init {
|
init {
|
||||||
node {
|
node {
|
||||||
name(ALICE.name)
|
name(ALICE.name)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user