mirror of
https://github.com/corda/corda.git
synced 2025-04-07 11:27:01 +00:00
Avoid errors if Corda / Explorer cannot be found at runtime. (#501)
* Avoid NPE if corda.jar cannot be found. * Log an error if Node Explorer or WebServer fail to start. * Display an error dialog if we cannot find corda.jar at start-up. * Use official notUsed() function for unwanted Observables. * Fix unit tests. * Rename function to readErrorLines().
This commit is contained in:
parent
0a60d389d7
commit
4829524244
@ -4,6 +4,8 @@ import javafx.scene.image.Image
|
||||
import net.corda.demobench.views.DemoBenchView
|
||||
import tornadofx.App
|
||||
import tornadofx.addStageIcon
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
|
||||
/**
|
||||
* README!
|
||||
@ -49,3 +51,5 @@ class DemoBench : App(DemoBenchView::class) {
|
||||
addStageIcon(Image("cordalogo.png"))
|
||||
}
|
||||
}
|
||||
|
||||
fun Process.readErrorLines(): List<String> = InputStreamReader(this.errorStream, UTF_8).readLines()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.demobench.explorer
|
||||
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.demobench.readErrorLines
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.Executors
|
||||
import net.corda.demobench.model.NodeConfig
|
||||
@ -40,13 +41,18 @@ class Explorer internal constructor(private val explorerController: ExplorerCont
|
||||
// Close these streams because no-one is using them.
|
||||
safeClose(p.outputStream)
|
||||
safeClose(p.inputStream)
|
||||
safeClose(p.errorStream)
|
||||
|
||||
executor.submit {
|
||||
val exitValue = p.waitFor()
|
||||
val errors = p.readErrorLines()
|
||||
process = null
|
||||
|
||||
log.info("Node Explorer for '{}' has exited (value={})", config.legalName, exitValue)
|
||||
if (errors.isEmpty()) {
|
||||
log.info("Node Explorer for '{}' has exited (value={})", config.legalName, exitValue)
|
||||
} else {
|
||||
log.error("Node Explorer for '{}' has exited (value={}, {})", config.legalName, exitValue, errors)
|
||||
}
|
||||
|
||||
onExit(config)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
|
@ -2,6 +2,9 @@ package net.corda.demobench.model
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import javafx.scene.control.Alert
|
||||
import javafx.scene.control.Alert.AlertType.ERROR
|
||||
import javafx.stage.Stage
|
||||
import tornadofx.Controller
|
||||
|
||||
class JVMConfig : Controller() {
|
||||
@ -24,3 +27,21 @@ class JVMConfig : Controller() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typealias atRuntime = (Path, String) -> Unit
|
||||
|
||||
fun checkExists(path: Path, header: String) {
|
||||
if (!path.toFile().exists()) {
|
||||
val alert = Alert(ERROR)
|
||||
alert.isResizable = true
|
||||
alert.headerText = header
|
||||
alert.contentText = "'$path' does not exist.\n" +
|
||||
"Please install all of DemoBench's runtime dependencies or run the installer. " +
|
||||
"See the documentation for more details."
|
||||
|
||||
val stage = alert.dialogPane.scene.window as Stage
|
||||
stage.isAlwaysOnTop = true
|
||||
|
||||
alert.show()
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import net.corda.demobench.plugin.PluginController
|
||||
import net.corda.demobench.pty.R3Pty
|
||||
import tornadofx.Controller
|
||||
|
||||
class NodeController : Controller() {
|
||||
class NodeController(check: atRuntime = ::checkExists) : Controller() {
|
||||
companion object {
|
||||
const val firstPort = 10000
|
||||
const val minPort = 1024
|
||||
@ -39,6 +39,10 @@ class NodeController : Controller() {
|
||||
init {
|
||||
log.info("Base directory: $baseDir")
|
||||
log.info("Corda JAR: $cordaPath")
|
||||
|
||||
// Check that the Corda capsule is available.
|
||||
// We do NOT want to do this during unit testing!
|
||||
check(cordaPath, "Cannot find Corda JAR.")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
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
|
||||
@ -21,13 +20,15 @@ class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension,
|
||||
|
||||
val terminal = JediTermWidget(dimension, settings)
|
||||
|
||||
val isConnected: Boolean get() = terminal.ttyConnector?.isConnected ?: false
|
||||
|
||||
override fun close() {
|
||||
log.info("Closing terminal '{}'", name)
|
||||
executor.shutdown()
|
||||
terminal.close()
|
||||
}
|
||||
|
||||
private fun createTtyConnector(command: Array<String>, environment: Map<String, String>, workingDir: String?): TtyConnector {
|
||||
private fun createTtyConnector(command: Array<String>, environment: Map<String, String>, workingDir: String?): PtyProcessTtyConnector {
|
||||
val process = PtyProcess.exec(command, environment, workingDir)
|
||||
|
||||
try {
|
||||
|
@ -5,12 +5,13 @@ import com.jediterm.terminal.TextStyle
|
||||
import com.jediterm.terminal.ui.settings.DefaultSettingsProvider
|
||||
import java.awt.Dimension
|
||||
import java.util.logging.Level
|
||||
import javax.swing.SwingUtilities
|
||||
import javafx.application.Platform
|
||||
import javafx.embed.swing.SwingNode
|
||||
import javafx.scene.control.Button
|
||||
import javafx.scene.control.Label
|
||||
import javafx.scene.layout.VBox
|
||||
import javax.swing.SwingUtilities
|
||||
import net.corda.client.rpc.notUsed
|
||||
import net.corda.demobench.explorer.ExplorerController
|
||||
import net.corda.demobench.model.*
|
||||
import net.corda.demobench.pty.R3Pty
|
||||
@ -61,17 +62,28 @@ class NodeTerminalView : Fragment() {
|
||||
val r3pty = R3Pty(config.legalName, TerminalSettingsProvider(), Dimension(160, 80), onExit)
|
||||
pty = r3pty
|
||||
|
||||
swingTerminal.content = r3pty.terminal
|
||||
nodeController.runCorda(r3pty, config)
|
||||
if (nodeController.runCorda(r3pty, config)) {
|
||||
swingTerminal.content = r3pty.terminal
|
||||
|
||||
configureDatabaseButton(config)
|
||||
configureExplorerButton(config)
|
||||
configureWebButton(config)
|
||||
configureDatabaseButton(config)
|
||||
configureExplorerButton(config)
|
||||
configureWebButton(config)
|
||||
|
||||
/*
|
||||
* Start RPC client that will update node statistics on UI.
|
||||
*/
|
||||
rpc = launchRPC(config)
|
||||
/*
|
||||
* Start RPC client that will update node statistics on UI.
|
||||
*/
|
||||
rpc = launchRPC(config)
|
||||
|
||||
/*
|
||||
* Check whether the PTY has exited unexpectedly,
|
||||
* and close the RPC client if it has.
|
||||
*/
|
||||
if (!r3pty.isConnected) {
|
||||
log.severe("Node '${config.legalName}' has failed to start.")
|
||||
swingTerminal.content = null
|
||||
rpc?.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -158,7 +170,7 @@ class NodeTerminalView : Fragment() {
|
||||
|
||||
// TODO - Will change when we modify RPC Observables handling.
|
||||
private fun <T> fetchAndDrop(pair: Pair<T, rx.Observable<*>>): T {
|
||||
pair.second.subscribe().unsubscribe()
|
||||
pair.second.notUsed()
|
||||
return pair.first
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.demobench.web
|
||||
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.demobench.readErrorLines
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.Executors
|
||||
import net.corda.demobench.model.NodeConfig
|
||||
@ -34,13 +35,18 @@ class WebServer internal constructor(private val webServerController: WebServerC
|
||||
// Close these streams because no-one is using them.
|
||||
safeClose(p.outputStream)
|
||||
safeClose(p.inputStream)
|
||||
safeClose(p.errorStream)
|
||||
|
||||
executor.submit {
|
||||
val exitValue = p.waitFor()
|
||||
val errors = p.readErrorLines()
|
||||
process = null
|
||||
|
||||
log.info("Web Server for '{}' has exited (value={})", config.legalName, exitValue)
|
||||
if (errors.isEmpty()) {
|
||||
log.info("Web Server for '{}' has exited (value={})", config.legalName, exitValue)
|
||||
} else {
|
||||
log.error("Web Server for '{}' has exited (value={}, {})", config.legalName, exitValue, errors)
|
||||
}
|
||||
|
||||
onExit(config)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
|
@ -9,7 +9,7 @@ import org.junit.Test
|
||||
class NodeControllerTest {
|
||||
|
||||
private val baseDir: Path = Paths.get(".").toAbsolutePath()
|
||||
private val controller = NodeController()
|
||||
private val controller = NodeController({_,_ ->})
|
||||
|
||||
@Test
|
||||
fun `test unique nodes after validate`() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user