mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
#340: Factor out jvm process start into utility function
This commit is contained in:
parent
48952dfc02
commit
81dcde99bf
@ -0,0 +1,47 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
object ProcessUtilities {
|
||||
inline fun <reified C : Any> startJavaProcess(
|
||||
arguments: List<String>,
|
||||
jdwpPort: Int? = null,
|
||||
extraJvmArguments: List<String> = emptyList(),
|
||||
inheritIO: Boolean = true,
|
||||
errorLogPath: Path? = null,
|
||||
workingDirectory: Path? = null
|
||||
): Process {
|
||||
return startJavaProcess(C::class.java.name, arguments, jdwpPort, extraJvmArguments, inheritIO, errorLogPath, workingDirectory)
|
||||
}
|
||||
|
||||
fun startJavaProcess(
|
||||
className: String,
|
||||
arguments: List<String>,
|
||||
jdwpPort: Int? = null,
|
||||
extraJvmArguments: List<String> = emptyList(),
|
||||
inheritIO: Boolean = true,
|
||||
errorLogPath: Path? = null,
|
||||
workingDirectory: Path? = null
|
||||
): Process {
|
||||
val separator = System.getProperty("file.separator")
|
||||
val classpath = System.getProperty("java.class.path")
|
||||
val javaPath = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
||||
val debugPortArgument = if (jdwpPort == null) {
|
||||
listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$jdwpPort")
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
|
||||
val allArguments = listOf(javaPath) +
|
||||
debugPortArgument +
|
||||
listOf("-Xmx200m", "-XX:+UseG1GC") +
|
||||
extraJvmArguments +
|
||||
listOf("-cp", classpath, className) +
|
||||
arguments.toList()
|
||||
return ProcessBuilder(allArguments).apply {
|
||||
if (errorLogPath != null) redirectError(errorLogPath.toFile())
|
||||
if (inheritIO) inheritIO()
|
||||
if (workingDirectory != null) directory(workingDirectory.toFile())
|
||||
}.start()
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
@file:JvmName("Driver")
|
||||
package net.corda.node.driver
|
||||
|
||||
import co.paralleluniverse.common.util.ProcessUtil
|
||||
import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.*
|
||||
import com.typesafe.config.Config
|
||||
@ -15,6 +16,7 @@ import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.node.services.ServiceType
|
||||
import net.corda.core.utilities.ProcessUtilities
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.LOGS_DIRECTORY_NAME
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
@ -552,78 +554,53 @@ class DriverDSL(
|
||||
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
||||
|
||||
private fun startNode(
|
||||
executorService: ScheduledExecutorService,
|
||||
executorService: ListeningScheduledExecutorService,
|
||||
nodeConf: FullNodeConfiguration,
|
||||
quasarJarPath: String,
|
||||
debugPort: Int?,
|
||||
overriddenSystemProperties: Map<String, String>
|
||||
): ListenableFuture<Process> {
|
||||
// Write node.conf
|
||||
writeConfig(nodeConf.baseDirectory, "node.conf", nodeConf.config)
|
||||
return executorService.submit<Process> {
|
||||
// Write node.conf
|
||||
writeConfig(nodeConf.baseDirectory, "node.conf", nodeConf.config)
|
||||
|
||||
val className = "net.corda.node.Corda" // 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"
|
||||
val systemProperties = mapOf(
|
||||
"name" to nodeConf.myLegalName,
|
||||
"visualvm.display.name" to "Corda"
|
||||
) + overriddenSystemProperties
|
||||
val extraJvmArguments = systemProperties.map { "-D${it.key}=${it.value}" } +
|
||||
"-javaagent:$quasarJarPath"
|
||||
val loggingLevel = if (debugPort == null) "INFO" else "DEBUG"
|
||||
|
||||
val debugPortArg = if (debugPort != null)
|
||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort"
|
||||
else
|
||||
""
|
||||
|
||||
val systemProperties = mapOf(
|
||||
"name" to nodeConf.myLegalName,
|
||||
"visualvm.display.name" to "Corda"
|
||||
) + overriddenSystemProperties
|
||||
|
||||
val loggingLevel = if (debugPort == null) "INFO" else "DEBUG"
|
||||
val javaArgs = listOf(path) +
|
||||
systemProperties.map { "-D${it.key}=${it.value}" } +
|
||||
listOf(
|
||||
"-javaagent:$quasarJarPath",
|
||||
debugPortArg,
|
||||
"-Xmx200m",
|
||||
"-XX:+UseG1GC",
|
||||
"-cp", classpath, className,
|
||||
"--base-directory=${nodeConf.baseDirectory}",
|
||||
"--logging-level=$loggingLevel",
|
||||
"--no-local-shell"
|
||||
).filter(String::isNotEmpty)
|
||||
val process = ProcessBuilder(javaArgs)
|
||||
.redirectError((nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log").toFile())
|
||||
.inheritIO()
|
||||
.directory(nodeConf.baseDirectory.toFile())
|
||||
.start()
|
||||
// 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. Needs rethinking.
|
||||
return addressMustBeBound(executorService, nodeConf.p2pAddress).map { process }
|
||||
ProcessUtilities.startJavaProcess(
|
||||
className = "net.corda.node.Corda", // cannot directly get class for this, so just use string
|
||||
arguments = listOf(
|
||||
"--base-directory=${nodeConf.baseDirectory}",
|
||||
"--logging-level=$loggingLevel",
|
||||
"--no-local-shell"
|
||||
),
|
||||
extraJvmArguments = extraJvmArguments,
|
||||
errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log",
|
||||
workingDirectory = nodeConf.baseDirectory
|
||||
)
|
||||
}.flatMap { process -> addressMustBeBound(executorService, nodeConf.p2pAddress).map { process } }
|
||||
}
|
||||
|
||||
private fun startWebserver(
|
||||
executorService: ScheduledExecutorService,
|
||||
executorService: ListeningScheduledExecutorService,
|
||||
nodeConf: FullNodeConfiguration,
|
||||
debugPort: Int?): ListenableFuture<Process> {
|
||||
val className = "net.corda.webserver.WebServer" // 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"
|
||||
|
||||
val debugPortArg = if (debugPort != null)
|
||||
listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort")
|
||||
else
|
||||
emptyList()
|
||||
|
||||
val javaArgs = listOf(path) +
|
||||
listOf("-Dname=node-${nodeConf.p2pAddress}-webserver") + debugPortArg +
|
||||
listOf(
|
||||
"-cp", classpath, className,
|
||||
"--base-directory", nodeConf.baseDirectory.toString())
|
||||
val builder = ProcessBuilder(javaArgs)
|
||||
builder.redirectError(Paths.get("error.$className.log").toFile())
|
||||
builder.inheritIO()
|
||||
builder.directory(nodeConf.baseDirectory.toFile())
|
||||
val process = builder.start()
|
||||
return addressMustBeBound(executorService, nodeConf.webAddress).map { process }
|
||||
debugPort: Int?
|
||||
): ListenableFuture<Process> {
|
||||
return executorService.submit<Process> {
|
||||
val className = "net.corda.webserver.WebServer"
|
||||
ProcessUtilities.startJavaProcess(
|
||||
className = className, // cannot directly get class for this, so just use string
|
||||
arguments = listOf("--base-directory", nodeConf.baseDirectory.toString()),
|
||||
jdwpPort = debugPort,
|
||||
extraJvmArguments = listOf("-Dname=node-${nodeConf.p2pAddress}-webserver"),
|
||||
errorLogPath = Paths.get("error.$className.log")
|
||||
)
|
||||
}.flatMap { process -> addressMustBeBound(executorService, nodeConf.webAddress).map { process } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package net.corda.testing
|
||||
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun spawn(className: String, args: List<String>, appName: String): Process {
|
||||
val separator = System.getProperty("file.separator")
|
||||
val classpath = System.getProperty("java.class.path")
|
||||
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
||||
val javaArgs = listOf(path, "-Dname=$appName", "-javaagent:lib/quasar.jar", "-cp", classpath, className)
|
||||
val builder = ProcessBuilder(javaArgs + args)
|
||||
builder.redirectError(Paths.get("error.$className.log").toFile())
|
||||
builder.inheritIO()
|
||||
val process = builder.start()
|
||||
return process
|
||||
}
|
||||
|
||||
fun assertExitOrKill(proc: Process) {
|
||||
try {
|
||||
assertEquals(proc.waitFor(2, TimeUnit.MINUTES), true)
|
||||
} catch (e: Throwable) {
|
||||
proc.destroyForcibly()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun assertAliveAndKill(proc: Process) {
|
||||
try {
|
||||
assertEquals(proc.isAlive, true)
|
||||
} finally {
|
||||
proc.destroyForcibly()
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import net.corda.core.div
|
||||
import net.corda.core.map
|
||||
import net.corda.core.random63BitValue
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.utilities.ProcessUtilities
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.driver.*
|
||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||
@ -240,35 +241,16 @@ data class VerifierDriverDSL(
|
||||
override fun startVerifier(address: HostAndPort): ListenableFuture<VerifierHandle> {
|
||||
log.info("Starting verifier connecting to address $address")
|
||||
val id = verifierCount.andIncrement
|
||||
val verifierName = "verifier$id"
|
||||
val baseDirectory = driverDSL.driverDirectory / verifierName
|
||||
val config = createConfiguration(baseDirectory, address)
|
||||
val configFilename = "verifier.conf"
|
||||
writeConfig(baseDirectory, configFilename, config)
|
||||
Verifier.loadConfiguration(baseDirectory, baseDirectory / configFilename).configureDevKeyAndTrustStores(verifierName)
|
||||
|
||||
val className = Verifier::class.java.name
|
||||
val separator = System.getProperty("file.separator")
|
||||
val classpath = System.getProperty("java.class.path")
|
||||
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
||||
val debugPortArg = if (driverDSL.isDebug)
|
||||
listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${driverDSL.debugPortAllocation.nextPort()}")
|
||||
else
|
||||
emptyList()
|
||||
|
||||
val javaArgs =
|
||||
listOf(path) + debugPortArg +
|
||||
listOf(
|
||||
"-Xmx200m",
|
||||
"-XX:+UseG1GC",
|
||||
"-cp", classpath,
|
||||
className,
|
||||
baseDirectory.toString()
|
||||
)
|
||||
val builder = ProcessBuilder(javaArgs)
|
||||
builder.inheritIO()
|
||||
|
||||
val processFuture = driverDSL.executorService.submit<Process> { builder.start() }
|
||||
val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
|
||||
val processFuture = driverDSL.executorService.submit<Process> {
|
||||
val verifierName = "verifier$id"
|
||||
val baseDirectory = driverDSL.driverDirectory / verifierName
|
||||
val config = createConfiguration(baseDirectory, address)
|
||||
val configFilename = "verifier.conf"
|
||||
writeConfig(baseDirectory, configFilename, config)
|
||||
Verifier.loadConfiguration(baseDirectory, baseDirectory / configFilename).configureDevKeyAndTrustStores(verifierName)
|
||||
ProcessUtilities.startJavaProcess<Verifier>(listOf(baseDirectory.toString()), jdwpPort = jdwpPort)
|
||||
}
|
||||
driverDSL.shutdownManager.registerProcessShutdown(processFuture)
|
||||
return processFuture.map(::VerifierHandle)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user