The first node now becomes the session's Network Map service used by all other nodes. Force nodes to be created one-by-one.

This commit is contained in:
Chris Rankin 2017-01-27 11:36:46 +00:00
parent 6e38c4a95d
commit c670ed6bdd
8 changed files with 74 additions and 50 deletions

View File

@ -0,0 +1,23 @@
package net.corda.demobench.model
open class NetworkMapConfig(legalName: String, artemisPort: Int) {
private var keyValue: String = toKey(legalName)
val key : String
get() { return keyValue }
private var legalNameValue: String = legalName
val legalName : String
get() { return legalNameValue }
private var artemisPortValue: Int = artemisPort
val artemisPort : Int
get() { return artemisPortValue }
}
private val WHITESPACE = Regex("\\s++")
fun toKey(value: String): String {
return value.replace(WHITESPACE, "").toLowerCase()
}

View File

@ -5,47 +5,31 @@ import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValue import com.typesafe.config.ConfigValue
import com.typesafe.config.ConfigValueFactory import com.typesafe.config.ConfigValueFactory
class NodeConfig(legalName: String, nearestCity: String, p2pPort: Int, artemisPort: Int, webPort: Int) { class NodeConfig(legalName: String, artemisPort: Int, nearestCity: String, webPort: Int) : NetworkMapConfig(legalName, artemisPort){
private var keyValue: String = toKey(legalName)
val key : String
get() { return keyValue }
private var legalNameValue: String = legalName
val legalName : String
get() { return legalNameValue }
private var nearestCityName: String = nearestCity private var nearestCityName: String = nearestCity
val nearestCity : String val nearestCity : String
get() { return nearestCityName } get() { return nearestCityName }
private var p2pPortValue: Int = p2pPort
val p2pPort : Int
get() { return p2pPortValue }
private var artemisPortValue: Int = artemisPort
val artemisPort : Int
get() { return artemisPortValue }
private var webPortValue: Int = webPort private var webPortValue: Int = webPort
val webPort : Int val webPort : Int
get() { return webPortValue } get() { return webPortValue }
private fun toKey(value: String): String { private var networkMapValue: NetworkMapConfig? = null
return value.replace("\\s++", "").toLowerCase() var networkMap : NetworkMapConfig?
} get() { return networkMapValue }
set(value) { networkMapValue = value }
val toFileConfig : Config val toFileConfig : Config
get() = ConfigFactory.empty() get() = ConfigFactory.empty()
.withValue("myLegalName", valueFor(legalName)) .withValue("myLegalName", valueFor(legalName))
.withValue("artemisAddress", addressValueFor(artemisPort))
.withValue("nearestCity", valueFor(nearestCity)) .withValue("nearestCity", valueFor(nearestCity))
.withValue("extraAdvertisedServiceIds", valueFor("")) .withValue("extraAdvertisedServiceIds", valueFor(""))
.withFallback(ConfigFactory.empty() .withFallback(optional("networkMapService", networkMap, {
.withValue("address", addressValueFor(p2pPort)) c, n -> c.withValue("address", addressValueFor(n.artemisPort))
.withValue("legalName", valueFor("Notary")) .withValue("legalName", valueFor(n.legalName))
.atPath("networkMapService") } ))
)
.withValue("artemisAddress", addressValueFor(artemisPort))
.withValue("webAddress", addressValueFor(webPort)) .withValue("webAddress", addressValueFor(webPort))
.withValue("rpcUsers", valueFor(listOf<String>())) .withValue("rpcUsers", valueFor(listOf<String>()))
.withValue("useTestClock", valueFor(true)) .withValue("useTestClock", valueFor(true))
@ -59,3 +43,8 @@ private fun <T> valueFor(any: T): ConfigValue? {
private fun addressValueFor(port: Int): ConfigValue? { private fun addressValueFor(port: Int): ConfigValue? {
return valueFor("localhost:%d".format(port)) return valueFor("localhost:%d".format(port))
} }
private fun <T> optional(path: String, obj: T?, body: (c: Config, o: T) -> Config): Config {
val config = ConfigFactory.empty()
return if (obj == null) config else body(config, obj).atPath(path)
}

View File

@ -26,25 +26,44 @@ class NodeController : Controller() {
private val nodes = ConcurrentHashMap<String, NodeConfig>() private val nodes = ConcurrentHashMap<String, NodeConfig>()
private val port = AtomicInteger(FIRST_PORT) private val port = AtomicInteger(FIRST_PORT)
private var networkMapConfig: NetworkMapConfig? = null
fun validate(nodeData: NodeData): NodeConfig? { fun validate(nodeData: NodeData): NodeConfig? {
val config = NodeConfig( val config = NodeConfig(
nodeData.legalName.value, nodeData.legalName.value,
nodeData.nearestCity.value,
nodeData.p2pPort.value,
nodeData.artemisPort.value, nodeData.artemisPort.value,
nodeData.nearestCity.value,
nodeData.webPort.value nodeData.webPort.value
) )
log.info("Node key: " + config.key)
if (nodes.putIfAbsent(config.key, config) != null) { if (nodes.putIfAbsent(config.key, config) != null) {
return null return null
} }
// The first node becomes our network map
chooseNetworkMap(config)
return config return config
} }
val nextPort: Int val nextPort: Int
get() { return port.andIncrement } get() { return port.andIncrement }
fun exists(name: String): Boolean {
return nodes.keys.contains(toKey(name))
}
fun chooseNetworkMap(config: NodeConfig) {
if (networkMapConfig != null) {
config.networkMap = networkMapConfig
} else {
networkMapConfig = config
log.info("Network map provided by: " + config.legalName)
}
}
fun runCorda(pty: R3Pty, config: NodeConfig): Boolean { fun runCorda(pty: R3Pty, config: NodeConfig): Boolean {
val nodeDir = workDir.resolve(config.key).toFile() val nodeDir = workDir.resolve(config.key).toFile()
@ -73,5 +92,6 @@ class NodeController : Controller() {
init { init {
log.info("Working directory: " + workDir) log.info("Working directory: " + workDir)
log.info("Java executable: " + javaPath) log.info("Java executable: " + javaPath)
log.info("Corda JAR: " + command[0])
} }
} }

View File

@ -7,7 +7,6 @@ class NodeData {
var legalName = SimpleStringProperty("") var legalName = SimpleStringProperty("")
val nearestCity = SimpleStringProperty("London") val nearestCity = SimpleStringProperty("London")
var p2pPort = SimpleIntegerProperty(0)
val artemisPort = SimpleIntegerProperty(0) val artemisPort = SimpleIntegerProperty(0)
val webPort = SimpleIntegerProperty(0) val webPort = SimpleIntegerProperty(0)

View File

@ -6,7 +6,6 @@ class NodeDataModel : ItemViewModel<NodeData>(NodeData()) {
val legalName = bind { item?.legalName } val legalName = bind { item?.legalName }
val nearestCity = bind { item?.nearestCity } val nearestCity = bind { item?.nearestCity }
val p2pPort = bind { item?.p2pPort }
val artemisPort = bind { item?.artemisPort } val artemisPort = bind { item?.artemisPort }
val webPort = bind { item?.webPort } val webPort = bind { item?.webPort }

View File

@ -29,6 +29,9 @@ class DemoBenchView : View("Corda Demo Bench") {
addNodeButton.setOnAction { addNodeButton.setOnAction {
val nodeTab = createNodeTab() val nodeTab = createNodeTab()
nodeTabPane.selectionModel.select(nodeTab) nodeTabPane.selectionModel.select(nodeTab)
// Prevent us from creating new nodes until we have created the Network Map
addNodeButton.isDisable = true
} }
addNodeButton.fire() addNodeButton.fire()
} }
@ -47,4 +50,7 @@ class DemoBenchView : View("Corda Demo Bench") {
return nodeTab return nodeTab
} }
fun enableAddNodes() {
addNodeButton.isDisable = false
}
} }

View File

@ -10,6 +10,8 @@ import tornadofx.*
class NodeTabView : Fragment() { class NodeTabView : Fragment() {
override val root = stackpane {} override val root = stackpane {}
private val main by inject<DemoBenchView>()
private val INTEGER_FORMAT = DecimalFormat() private val INTEGER_FORMAT = DecimalFormat()
private val NOT_NUMBER = Regex("[^\\d]") private val NOT_NUMBER = Regex("[^\\d]")
@ -25,8 +27,10 @@ class NodeTabView : Fragment() {
minWidth = 200.0 minWidth = 200.0
maxWidth = 200.0 maxWidth = 200.0
validator { validator {
if (it.isNullOrBlank()) { if ((it == null) || it.isBlank()) {
error("Node name is required") error("Node name is required")
} else if (controller.exists(it)) {
error("Node with this name already exists")
} else { } else {
null null
} }
@ -47,21 +51,6 @@ class NodeTabView : Fragment() {
} }
} }
field("P2P Port") { field("P2P Port") {
textfield(model.p2pPort, NumberStringConverter(INTEGER_FORMAT)) {
minWidth = 100.0
maxWidth = 100.0
validator {
if ((it == null) || it.isEmpty()) {
error("Port number required")
} else if (it.contains(NOT_NUMBER)) {
error("Invalid port number")
} else {
null
}
}
}
}
field("Artemis Port") {
textfield(model.artemisPort, NumberStringConverter(INTEGER_FORMAT)) { textfield(model.artemisPort, NumberStringConverter(INTEGER_FORMAT)) {
minWidth = 100.0 minWidth = 100.0
maxWidth = 100.0 maxWidth = 100.0
@ -94,12 +83,12 @@ class NodeTabView : Fragment() {
} }
fieldset("Plugins") { fieldset("Plugins") {
} }
button("Create Node") { button("Create Node") {
setOnAction() { setOnAction() {
launch() launch()
main.enableAddNodes()
} }
} }
} }
@ -135,7 +124,6 @@ class NodeTabView : Fragment() {
root.add(nodeConfigView) root.add(nodeConfigView)
root.add(nodeTerminalView) root.add(nodeTerminalView)
model.p2pPort.value = controller.nextPort
model.artemisPort.value = controller.nextPort model.artemisPort.value = controller.nextPort
model.webPort.value = controller.nextPort model.webPort.value = controller.nextPort
} }

View File

@ -35,7 +35,7 @@ class NodeTerminalView : Fragment() {
fun open(config: NodeConfig) { fun open(config: NodeConfig) {
nodeName.text = config.legalName nodeName.text = config.legalName
p2pPort.value = config.p2pPort.toString() p2pPort.value = config.artemisPort.toString()
val swingTerminal = SwingNode() val swingTerminal = SwingNode()
swingTerminal.setOnMouseClicked { swingTerminal.setOnMouseClicked {