Merged in mnesbit-cleanup-driver-use-standalone-node (pull request #340)

Use standalone Corda main class and configuration in the Driver, rather than a separate class.
This commit is contained in:
Matthew Nesbit 2016-09-08 14:59:18 +01:00
commit 4fb0148f96
2 changed files with 29 additions and 151 deletions

View File

@ -7,6 +7,7 @@ import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.NetworkMapCache
import com.r3corda.core.node.services.ServiceType
import com.r3corda.node.services.config.FullNodeConfiguration
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.config.NodeConfigurationFromConfig
import com.r3corda.node.services.messaging.ArtemisMessagingClient
@ -14,6 +15,7 @@ import com.r3corda.node.services.messaging.ArtemisMessagingComponent
import com.r3corda.node.services.messaging.ArtemisMessagingServer
import com.r3corda.node.services.network.InMemoryNetworkMapCache
import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.services.transactions.NotaryService
import com.r3corda.node.utilities.AffinityExecutor
import com.typesafe.config.Config
import com.typesafe.config.ConfigRenderOptions
@ -21,6 +23,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.net.*
import java.nio.file.Path
import java.nio.file.Paths
import java.text.SimpleDateFormat
import java.util.*
@ -289,25 +292,24 @@ class DriverDSL(
val name = providedName ?: "${pickA(name)}-${messagingAddress.port}"
val nodeDirectory = "$baseDirectory/$name"
val useNotary = advertisedServices.any { it.isSubTypeOf(NotaryService.Type) }
val config = NodeConfiguration.loadConfig(
baseDirectoryPath = Paths.get(nodeDirectory),
allowMissingConfig = true,
configOverrides = mapOf(
"myLegalName" to name
"myLegalName" to name,
"basedir" to Paths.get(nodeDirectory).normalize().toString(),
"artemisAddress" to messagingAddress.toString(),
"webAddress" to apiAddress.toString(),
"hostNotaryServiceLocally" to useNotary.toString(),
"extraAdvertisedServiceIds" to advertisedServices.map { x -> x.id }.joinToString(","),
"networkMapAddress" to networkMapAddress.toString()
)
)
val driverCliParams = NodeRunner.CliParams(
services = advertisedServices,
networkMapAddress = networkMapAddress,
messagingAddress = messagingAddress,
apiAddress = apiAddress,
baseDirectory = nodeDirectory
)
return Executors.newSingleThreadExecutor().submit(Callable<NodeInfo> {
registerProcess(DriverDSL.startNode(config, driverCliParams, name, quasarJarPath, debugPort))
registerProcess(DriverDSL.startNode(config, quasarJarPath, debugPort))
poll("network map cache for $name") {
networkMapCache.partyNodes.forEach {
if (it.identity.name == name) {
@ -406,19 +408,17 @@ class DriverDSL(
baseDirectoryPath = Paths.get(nodeDirectory),
allowMissingConfig = true,
configOverrides = mapOf(
"myLegalName" to networkMapName
"myLegalName" to networkMapName,
"basedir" to Paths.get(nodeDirectory).normalize().toString(),
"artemisAddress" to networkMapAddress.toString(),
"webAddress" to apiAddress.toString(),
"hostNotaryServiceLocally" to "false",
"extraAdvertisedServiceIds" to ""
)
)
val driverCliParams = NodeRunner.CliParams(
services = setOf(NetworkMapService.Type),
networkMapAddress = null,
messagingAddress = networkMapAddress,
apiAddress = apiAddress,
baseDirectory = nodeDirectory
)
log.info("Starting network-map-service")
registerProcess(startNode(config, driverCliParams, networkMapName, quasarJarPath, debugPort))
registerProcess(startNode(config, quasarJarPath, debugPort))
}
companion object {
@ -433,16 +433,14 @@ class DriverDSL(
private fun startNode(
config: Config,
cliParams: NodeRunner.CliParams,
legalName: String,
quasarJarPath: String,
debugPort: Int?
): Process {
val nodeConf = FullNodeConfiguration(config)
// Write node.conf
writeConfig(cliParams.baseDirectory, "node.conf", config)
writeConfig(nodeConf.basedir, "node.conf", config)
val className = NodeRunner::class.java.canonicalName
val className = "com.r3corda.node.MainKt" // cannot directly get class for this, so just use string
val separator = System.getProperty("file.separator")
val classpath = System.getProperty("java.class.path")
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
@ -453,26 +451,27 @@ class DriverDSL(
emptyList()
val javaArgs = listOf(path) +
listOf("-Dname=$legalName", "-javaagent:$quasarJarPath") + debugPortArg +
listOf("-Dname=${nodeConf.myLegalName}", "-javaagent:$quasarJarPath") + debugPortArg +
listOf("-cp", classpath, className) +
cliParams.toCliArguments()
"--base-directory=${nodeConf.basedir}"
val builder = ProcessBuilder(javaArgs)
builder.redirectError(Paths.get("error.$className.log").toFile())
builder.inheritIO()
builder.directory(nodeConf.basedir.toFile())
val process = builder.start()
addressMustBeBound(cliParams.messagingAddress)
addressMustBeBound(nodeConf.artemisAddress)
// TODO There is a race condition here. Even though the messaging address is bound it may be the case that
// the handlers for the advertised services are not yet registered. A hacky workaround is that we wait for
// the web api address to be bound as well, as that starts after the services. Needs rethinking.
addressMustBeBound(cliParams.apiAddress)
addressMustBeBound(nodeConf.webAddress)
return process
}
}
}
fun writeConfig(path: String, filename: String, config: Config) {
File(path).mkdirs()
fun writeConfig(path: Path, filename: String, config: Config) {
path.toFile().mkdirs()
File("$path/$filename").writeText(config.root().render(ConfigRenderOptions.concise()))
}

View File

@ -1,121 +0,0 @@
package com.r3corda.node.driver
import com.google.common.net.HostAndPort
import com.r3corda.core.node.services.ServiceType
import com.r3corda.node.internal.Node
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.config.NodeConfigurationFromConfig
import com.r3corda.node.services.messaging.ArtemisMessagingClient
import joptsimple.ArgumentAcceptingOptionSpec
import joptsimple.OptionParser
import joptsimple.OptionSet
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.nio.file.Path
import java.nio.file.Paths
import java.util.*
private val log: Logger = LoggerFactory.getLogger(NodeRunner::class.java)
class NodeRunner {
companion object {
@JvmStatic fun main(arguments: Array<String>) {
val cliParams = CliParams.parse(CliParams.parser.parse(*arguments))
val nodeDirectory = Paths.get(cliParams.baseDirectory)
createNodeRunDirectory(nodeDirectory)
with(cliParams) {
val networkMapNodeInfo =
if (networkMapAddress != null) {
ArtemisMessagingClient.makeNetworkMapAddress(networkMapAddress)
} else {
null
}
val nodeConfiguration = NodeConfigurationFromConfig(
NodeConfiguration.loadConfig(
baseDirectoryPath = nodeDirectory,
allowMissingConfig = false
)
)
val node = Node(
dir = nodeDirectory,
p2pAddr = messagingAddress,
webServerAddr = apiAddress,
configuration = nodeConfiguration,
networkMapAddress = networkMapNodeInfo,
advertisedServices = services.toSet()
)
log.info("Starting ${nodeConfiguration.myLegalName} with services $services on addresses $messagingAddress and $apiAddress")
node.start()
node.run()
}
}
}
class CliParams (
val services: Set<ServiceType>,
val networkMapAddress: HostAndPort?,
val messagingAddress: HostAndPort,
val apiAddress: HostAndPort,
val baseDirectory: String
) {
companion object {
val parser = OptionParser()
val services =
parser.accepts("services").withRequiredArg().ofType(String::class.java)
val networkMapAddress =
parser.accepts("network-map-address").withOptionalArg().ofType(String::class.java)
val messagingAddress =
parser.accepts("messaging-address").withRequiredArg().ofType(String::class.java)
val apiAddress =
parser.accepts("api-address").withRequiredArg().ofType(String::class.java)
val baseDirectory =
parser.accepts("base-directory").withRequiredArg().ofType(String::class.java)
private fun <T> requiredArgument(optionSet: OptionSet, spec: ArgumentAcceptingOptionSpec<T>) =
optionSet.valueOf(spec) ?: throw IllegalArgumentException("Must provide $spec")
fun parse(optionSet: OptionSet): CliParams {
val services = optionSet.valuesOf(services)
val networkMapAddress = optionSet.valueOf(networkMapAddress)
val messagingAddress = requiredArgument(optionSet, messagingAddress)
val apiAddress = requiredArgument(optionSet, apiAddress)
val baseDirectory = requiredArgument(optionSet, baseDirectory)
return CliParams(
services = services.map { object : ServiceType(it) {} }.toSet(),
messagingAddress = HostAndPort.fromString(messagingAddress),
apiAddress = HostAndPort.fromString(apiAddress),
baseDirectory = baseDirectory,
networkMapAddress = networkMapAddress?.let { HostAndPort.fromString(it) }
)
}
}
fun toCliArguments(): List<String> {
val cliArguments = LinkedList<String>()
if (services.isNotEmpty()) {
cliArguments.add("--services")
cliArguments.addAll(services.map { it.toString() })
}
if (networkMapAddress != null) {
cliArguments.add("--network-map-address")
cliArguments.add(networkMapAddress.toString())
}
cliArguments.add("--messaging-address")
cliArguments.add(messagingAddress.toString())
cliArguments.add("--api-address")
cliArguments.add(apiAddress.toString())
cliArguments.add("--base-directory")
cliArguments.add(baseDirectory.toString())
return cliArguments
}
}
}
fun createNodeRunDirectory(directory: Path) = directory.toFile().mkdirs()