From b29235e7cd5441e4e9d2217ab502e6df670dd041 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Thu, 9 Feb 2017 15:01:29 +0000 Subject: [PATCH] CORPRIV-665: Ensure tab closes if the node exits. --- .../java/net/corda/demobench/pty/R3Pty.java | 80 ------------------- .../demobench/model/ExplorerController.kt | 2 +- .../net/corda/demobench/model/JVMConfig.kt | 4 +- .../net/corda/demobench/model/NodeConfig.kt | 2 + .../corda/demobench/model/NodeController.kt | 18 +++-- .../net/corda/demobench/model/NodeState.kt | 7 ++ .../demobench/model/ServiceController.kt | 2 +- .../kotlin/net/corda/demobench/pty/R3Pty.kt | 66 +++++++++++++++ .../kotlin/net/corda/demobench/rpc/NodeRPC.kt | 2 +- .../corda/demobench/views/DemoBenchView.kt | 10 ++- .../net/corda/demobench/views/NodeTabView.kt | 46 ++++++----- .../corda/demobench/views/NodeTerminalView.kt | 11 ++- 12 files changed, 136 insertions(+), 114 deletions(-) delete mode 100644 tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java create mode 100644 tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeState.kt create mode 100644 tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt 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 deleted file mode 100644 index 0f79d7557a..0000000000 --- a/tools/demobench/src/main/java/net/corda/demobench/pty/R3Pty.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.corda.demobench.pty; - -import com.jediterm.terminal.TtyConnector; -import com.jediterm.terminal.ui.*; -import com.jediterm.terminal.ui.settings.SettingsProvider; -import com.pty4j.PtyProcess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.awt.*; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import static java.nio.charset.StandardCharsets.UTF_8; - -public class R3Pty implements AutoCloseable { - private static final Logger LOG = LoggerFactory.getLogger(R3Pty.class); - - private final JediTermWidget terminal; - private final String name; - - public R3Pty(String name, SettingsProvider settings, Dimension dimension) { - terminal = new JediTermWidget(dimension, settings); - this.name = name; - } - - @Override - public void close() { - LOG.info("Closing terminal '{}'", name); - terminal.close(); - } - - public String getName() { - return name; - } - - public JediTermWidget getTerminal() { - return terminal; - } - - private TtyConnector createTtyConnector(String[] command, Map environment, String workingDir) { - try { - PtyProcess process = PtyProcess.exec(command, environment, workingDir); - - try { - return new PtyProcessTtyConnector(name, process, UTF_8); - } catch (Exception e) { - process.destroyForcibly(); - process.waitFor(30, TimeUnit.SECONDS); - throw e; - } - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - - public void run(String[] args, Map envs, String workingDir) { - if (terminal.isSessionRunning()) { - throw new IllegalStateException(terminal.getSessionName() + " is already running"); - } - - Map environment = new HashMap<>(envs); - if (!UIUtil.isWindows) { - environment.put("TERM", "xterm"); - } - - TerminalSession session = terminal.createTerminalSession(createTtyConnector(args, environment, workingDir)); - session.start(); - } - - public void run(String[] args, Map envs) { - run(args, envs, null); - } - - public void run(String... args) { - run(args, System.getenv()); - } - -} diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt index a48ca08e0f..eaf56e3276 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt @@ -10,7 +10,7 @@ class ExplorerController : Controller() { private val explorerPath = jvm.applicationDir.resolve("explorer").resolve("node-explorer.jar") init { - log.info("Explorer JAR: " + explorerPath) + log.info("Explorer JAR: $explorerPath") } internal fun execute(cwd: Path, vararg args: String) = jvm.execute(explorerPath, cwd, *args) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt index 6aec7d56ea..08cc1b812b 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt @@ -8,10 +8,10 @@ class JVMConfig : Controller() { val userHome: Path = Paths.get(System.getProperty("user.home")).toAbsolutePath() val javaPath: Path = Paths.get(System.getProperty("java.home"), "bin", "java") - val applicationDir = Paths.get(System.getProperty("user.dir")).toAbsolutePath() + val applicationDir: Path = Paths.get(System.getProperty("user.dir")).toAbsolutePath() init { - log.info("Java executable: " + javaPath) + log.info("Java executable: $javaPath") } fun commandFor(jarPath: Path, vararg args: String): Array { 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 4600b57aa5..25d96f9400 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 @@ -38,6 +38,8 @@ class NodeConfig( var networkMap: NetworkMapConfig? = null + var state: NodeState = NodeState.STARTING + /* * The configuration object depends upon the networkMap, * which is mutable. 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 6f2eb0e247..0d6cb12ca6 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 @@ -38,8 +38,8 @@ class NodeController : Controller() { private var networkMapConfig: NetworkMapConfig? = null init { - log.info("Base directory: " + baseDir) - log.info("Corda JAR: " + cordaPath) + log.info("Base directory: $baseDir") + log.info("Corda JAR: $cordaPath") } fun validate(nodeData: NodeData): NodeConfig? { @@ -54,7 +54,7 @@ class NodeController : Controller() { ) if (nodes.putIfAbsent(config.key, config) != null) { - log.warning("Node with key '" + config.key + "' already exists.") + log.warning("Node with key '${config.key}' already exists.") return null } @@ -64,6 +64,14 @@ class NodeController : Controller() { return config } + fun dispose(config: NodeConfig) { + config.state = NodeState.DEAD + + if (config.networkMap == null) { + log.warning("Network map service (Node '${config.legalName}') has exited.") + } + } + val nextPort: Int get() = port.andIncrement fun isPortAvailable(port: Int): Boolean { @@ -90,7 +98,7 @@ class NodeController : Controller() { config.networkMap = networkMapConfig } else { networkMapConfig = config - log.info("Network map provided by: " + config.legalName) + log.info("Network map provided by: ${config.legalName}") } } @@ -112,7 +120,7 @@ class NodeController : Controller() { // Execute the Corda node pty.run(command, System.getenv(), nodeDir.toString()) - log.info("Launched node: " + config.legalName) + log.info("Launched node: ${config.legalName}") return true } catch (e: Exception) { log.severe("Failed to launch Corda:" + e) diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeState.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeState.kt new file mode 100644 index 0000000000..3147fa7d27 --- /dev/null +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeState.kt @@ -0,0 +1,7 @@ +package net.corda.demobench.model + +enum class NodeState { + STARTING, + RUNNING, + DEAD +} diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt index 5a032f7838..229f8e52b4 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ServiceController.kt @@ -24,7 +24,7 @@ class ServiceController : Controller() { val service = it.trim() set.add(service) - log.info("Supports: " + service) + log.info("Supports: $service") } } return set.toList() diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt new file mode 100644 index 0000000000..a52ee275e9 --- /dev/null +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/pty/R3Pty.kt @@ -0,0 +1,66 @@ +package net.corda.demobench.pty + +import com.jediterm.terminal.TtyConnector +import com.jediterm.terminal.ui.* +import com.jediterm.terminal.ui.settings.SettingsProvider +import com.pty4j.PtyProcess +import org.slf4j.LoggerFactory + +import java.awt.* +import java.nio.charset.StandardCharsets.UTF_8 +import java.util.* +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + +class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension, val onExit: () -> Unit) : AutoCloseable { + private val log = LoggerFactory.getLogger(R3Pty::class.java) + + private val executor = Executors.newSingleThreadExecutor() + + val terminal = JediTermWidget(dimension, settings) + + override fun close() { + log.info("Closing terminal '{}'", name) + executor.shutdown() + terminal.close() + } + + private fun createTtyConnector(command: Array, environment: Map, workingDir: String?): TtyConnector { + try { + val process = PtyProcess.exec(command, environment, workingDir) + + try { + return PtyProcessTtyConnector(name, process, UTF_8) + } catch (e: Exception) { + process.destroyForcibly() + process.waitFor(30, TimeUnit.SECONDS) + throw e + } + } catch (e: Exception) { + throw IllegalStateException(e.message, e) + } + } + + fun run(args: Array, envs: Map, workingDir: String?) { + if (terminal.isSessionRunning) { + throw IllegalStateException(terminal.sessionName + " is already running") + } + + val environment = HashMap(envs) + if (!UIUtil.isWindows) { + environment.put("TERM", "xterm") + } + + val connector = createTtyConnector(args, environment, workingDir) + + executor.submit { + val exitValue = connector.waitFor() + log.info("Terminal has exited (value={})", exitValue) + onExit() + } + + val session = terminal.createTerminalSession(connector) + session.start() + } + +} diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt index 89e6ffaf2f..68881b02fd 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/rpc/NodeRPC.kt @@ -29,7 +29,7 @@ class NodeRPC(config: NodeConfig, start: () -> Unit, invoke: (CordaRPCOps) -> Un // Cancel the "setup" task now that we've created the RPC client. this.cancel() - log.info("Node '{}' is now ready.", config.legalName) + // Run "start-up" task, now that the RPC client is ready. start() // Schedule a new task that will refresh the display once per second. diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/views/DemoBenchView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/views/DemoBenchView.kt index 207bffd941..81c5db5672 100644 --- a/tools/demobench/src/main/kotlin/net/corda/demobench/views/DemoBenchView.kt +++ b/tools/demobench/src/main/kotlin/net/corda/demobench/views/DemoBenchView.kt @@ -13,8 +13,8 @@ class DemoBenchView : View("Corda Demo Bench") { override val root by fxml() - val addNodeButton by fxid