From 6e38c4a95d9af7d86768b67ba1bf07aeccb03de7 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 26 Jan 2017 18:02:53 +0000 Subject: [PATCH] Write configuration parameters into node.conf, and then run corda.jar in its own directory. --- tools/demobench/build.gradle | 2 + .../demobench/libs/jediterm-terminal-2.5.jar | Bin 260519 -> 260530 bytes .../java/net/corda/demobench/pty/R3Pty.java | 8 +-- .../net/corda/demobench/model/NodeConfig.kt | 42 +++++++++++++-- .../corda/demobench/model/NodeController.kt | 48 +++++++++++++++++- .../net/corda/demobench/model/NodeData.kt | 9 ++-- .../corda/demobench/model/NodeDataModel.kt | 1 + .../net/corda/demobench/views/NodeTabView.kt | 22 +++++++- .../corda/demobench/views/NodeTerminalView.kt | 15 ++++-- 9 files changed, 129 insertions(+), 18 deletions(-) diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle index a9fd82175b..58ae835a85 100644 --- a/tools/demobench/build.gradle +++ b/tools/demobench/build.gradle @@ -9,6 +9,7 @@ buildscript { ext.guava_version = '14.0.1' ext.slf4j_version = '1.7.22' ext.logback_version = '1.1.3' + ext.typesafeconfig_version = '1.3.1' repositories { mavenCentral() @@ -50,6 +51,7 @@ dependencies { compile "org.slf4j:log4j-over-slf4j:$slf4j_version" compile "org.slf4j:jul-to-slf4j:$slf4j_version" compile "ch.qos.logback:logback-classic:$logback_version" + compile "com.typesafe:config:$typesafeconfig_version" compile ":jediterm-terminal-2.5" compile ':pty4j-0.7.2' diff --git a/tools/demobench/libs/jediterm-terminal-2.5.jar b/tools/demobench/libs/jediterm-terminal-2.5.jar index 66937731a2ccc50f4e7ba2d48405a71b9bd68b48..b211b2d08ec8eec74dd046a1d023cba3224cbe15 100644 GIT binary patch delta 23227 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 OUAq`yVwVa=-Twd$E7T+a delta 23131 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 MEpA;7VAM_j19tpqSO5S3 diff --git a/tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java b/tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java index 5a0ec1213e..0f79d7557a 100644 --- a/tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java +++ b/tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java @@ -28,9 +28,7 @@ public class R3Pty implements AutoCloseable { @Override public void close() { LOG.info("Closing terminal '{}'", name); - if (terminal.getTerminalStarter() != null) { - terminal.close(); - } + terminal.close(); } public String getName() { @@ -63,7 +61,9 @@ public class R3Pty implements AutoCloseable { } Map environment = new HashMap<>(envs); - environment.put("TERM", "xterm"); + if (!UIUtil.isWindows) { + environment.put("TERM", "xterm"); + } TerminalSession session = terminal.createTerminalSession(createTtyConnector(args, environment, workingDir)); session.start(); diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt index c5798abe9d..f25700b2fa 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt @@ -1,14 +1,23 @@ package net.corda.demobench.model -class NodeConfig(name: String, p2pPort: Int, artemisPort: Int, webPort: Int) { +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory +import com.typesafe.config.ConfigValue +import com.typesafe.config.ConfigValueFactory - private var keyValue: String = toKey(name) +class NodeConfig(legalName: String, nearestCity: String, p2pPort: Int, artemisPort: Int, webPort: Int) { + + private var keyValue: String = toKey(legalName) val key : String get() { return keyValue } - private var nameValue: String = name - val name : String - get() { return nameValue } + private var legalNameValue: String = legalName + val legalName : String + get() { return legalNameValue } + + private var nearestCityName: String = nearestCity + val nearestCity : String + get() { return nearestCityName } private var p2pPortValue: Int = p2pPort val p2pPort : Int @@ -26,4 +35,27 @@ class NodeConfig(name: String, p2pPort: Int, artemisPort: Int, webPort: Int) { return value.replace("\\s++", "").toLowerCase() } + val toFileConfig : Config + get() = ConfigFactory.empty() + .withValue("myLegalName", valueFor(legalName)) + .withValue("nearestCity", valueFor(nearestCity)) + .withValue("extraAdvertisedServiceIds", valueFor("")) + .withFallback(ConfigFactory.empty() + .withValue("address", addressValueFor(p2pPort)) + .withValue("legalName", valueFor("Notary")) + .atPath("networkMapService") + ) + .withValue("artemisAddress", addressValueFor(artemisPort)) + .withValue("webAddress", addressValueFor(webPort)) + .withValue("rpcUsers", valueFor(listOf())) + .withValue("useTestClock", valueFor(true)) + +} + +private fun valueFor(any: T): ConfigValue? { + return ConfigValueFactory.fromAnyRef(any) +} + +private fun addressValueFor(port: Int): ConfigValue? { + return valueFor("localhost:%d".format(port)) } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt index 025816eabc..70fdf0464b 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeController.kt @@ -1,18 +1,35 @@ package net.corda.demobench.model -import tornadofx.Controller +import com.jediterm.terminal.ui.UIUtil +import com.typesafe.config.ConfigRenderOptions +import java.lang.management.ManagementFactory +import java.nio.file.Paths +import java.text.SimpleDateFormat +import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicInteger +import net.corda.demobench.pty.R3Pty +import tornadofx.Controller class NodeController : Controller() { private val FIRST_PORT = 10000 + private val workDir = Paths.get("work", localDir).toAbsolutePath() + + private val javaExe = if (UIUtil.isWindows) "java.exe" else "java" + private val javaPath = Paths.get(System.getProperty("java.home"), "bin", javaExe) + private val cordaPath = Paths.get("corda", "corda.jar").toAbsolutePath() + private val command = arrayOf(javaPath.toString(), "-jar", cordaPath.toString()) + + private val renderOptions = ConfigRenderOptions.defaults().setOriginComments(false) + private val nodes = ConcurrentHashMap() private val port = AtomicInteger(FIRST_PORT) fun validate(nodeData: NodeData): NodeConfig? { val config = NodeConfig( nodeData.legalName.value, + nodeData.nearestCity.value, nodeData.p2pPort.value, nodeData.artemisPort.value, nodeData.webPort.value @@ -28,4 +45,33 @@ class NodeController : Controller() { val nextPort: Int get() { return port.andIncrement } + fun runCorda(pty: R3Pty, config: NodeConfig): Boolean { + val nodeDir = workDir.resolve(config.key).toFile() + + if (nodeDir.mkdirs()) { + try { + // Write this nodes configuration file into its working directory. + val confFile = nodeDir.resolve("node.conf") + val fileData = config.toFileConfig + confFile.writeText(fileData.root().render(renderOptions)) + + pty.run(command, System.getenv(), nodeDir.toString()) + return true + } catch (e: Exception) { + log.severe("Failed to launch Corda:" + e) + return false + } + } else { + return false + } + } + + private val localDir: String + get() = SimpleDateFormat("yyyyMMddHHmmss") + .format(Date(ManagementFactory.getRuntimeMXBean().startTime)) + + init { + log.info("Working directory: " + workDir) + log.info("Java executable: " + javaPath) + } } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt index 60a7240155..672cdfc344 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeData.kt @@ -5,9 +5,10 @@ import javafx.beans.property.SimpleStringProperty class NodeData { - var legalName : SimpleStringProperty = SimpleStringProperty("") - var p2pPort: SimpleIntegerProperty = SimpleIntegerProperty(0) - val artemisPort: SimpleIntegerProperty = SimpleIntegerProperty(0) - val webPort: SimpleIntegerProperty = SimpleIntegerProperty(0) + var legalName = SimpleStringProperty("") + val nearestCity = SimpleStringProperty("London") + var p2pPort = SimpleIntegerProperty(0) + val artemisPort = SimpleIntegerProperty(0) + val webPort = SimpleIntegerProperty(0) } \ No newline at end of file diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeDataModel.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeDataModel.kt index a58bc6b7ae..9791b468a8 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeDataModel.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeDataModel.kt @@ -5,6 +5,7 @@ import tornadofx.ItemViewModel class NodeDataModel : ItemViewModel(NodeData()) { val legalName = bind { item?.legalName } + val nearestCity = bind { item?.nearestCity } val p2pPort = bind { item?.p2pPort } val artemisPort = bind { item?.artemisPort } val webPort = bind { item?.webPort } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt index 87514430f8..d3996198a5 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTabView.kt @@ -33,6 +33,19 @@ class NodeTabView : Fragment() { } } } + field("Nearest City") { + textfield(model.nearestCity) { + minWidth = 200.0 + maxWidth = 200.0 + validator { + if (it.isNullOrBlank()) { + error("Nearest city is required") + } else { + null + } + } + } + } field("P2P Port") { textfield(model.p2pPort, NumberStringConverter(INTEGER_FORMAT)) { minWidth = 100.0 @@ -99,8 +112,15 @@ class NodeTabView : Fragment() { val config = controller.validate(model.item) if (config != null) { nodeConfigView.isVisible = false - nodeTab.text = config.name + nodeTab.text = config.legalName nodeTerminalView.open(config) + + nodeTab.setOnSelectionChanged { + if (nodeTab.isSelected) { + // Doesn't work yet + nodeTerminalView.refreshTerminal() + } + } } } diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt index c1b400d56c..961f47417c 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/NodeTerminalView.kt @@ -11,6 +11,7 @@ import javafx.scene.layout.Priority import javafx.scene.layout.VBox import javax.swing.SwingUtilities import net.corda.demobench.model.NodeConfig +import net.corda.demobench.model.NodeController import net.corda.demobench.pty.R3Pty import net.corda.demobench.ui.PropertyLabel import tornadofx.Fragment @@ -19,6 +20,8 @@ import tornadofx.vgrow class NodeTerminalView : Fragment() { override val root by fxml() + private val controller by inject() + private val nodeName by fxid