mirror of
https://github.com/corda/corda.git
synced 2025-05-04 17:53:05 +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")
|
@file:JvmName("Driver")
|
||||||
package net.corda.node.driver
|
package net.corda.node.driver
|
||||||
|
|
||||||
|
import co.paralleluniverse.common.util.ProcessUtil
|
||||||
import com.google.common.net.HostAndPort
|
import com.google.common.net.HostAndPort
|
||||||
import com.google.common.util.concurrent.*
|
import com.google.common.util.concurrent.*
|
||||||
import com.typesafe.config.Config
|
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.NodeInfo
|
||||||
import net.corda.core.node.services.ServiceInfo
|
import net.corda.core.node.services.ServiceInfo
|
||||||
import net.corda.core.node.services.ServiceType
|
import net.corda.core.node.services.ServiceType
|
||||||
|
import net.corda.core.utilities.ProcessUtilities
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.LOGS_DIRECTORY_NAME
|
import net.corda.node.LOGS_DIRECTORY_NAME
|
||||||
import net.corda.node.services.config.ConfigHelper
|
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]
|
fun <A> pickA(array: Array<A>): A = array[Math.abs(Random().nextInt()) % array.size]
|
||||||
|
|
||||||
private fun startNode(
|
private fun startNode(
|
||||||
executorService: ScheduledExecutorService,
|
executorService: ListeningScheduledExecutorService,
|
||||||
nodeConf: FullNodeConfiguration,
|
nodeConf: FullNodeConfiguration,
|
||||||
quasarJarPath: String,
|
quasarJarPath: String,
|
||||||
debugPort: Int?,
|
debugPort: Int?,
|
||||||
overriddenSystemProperties: Map<String, String>
|
overriddenSystemProperties: Map<String, String>
|
||||||
): ListenableFuture<Process> {
|
): ListenableFuture<Process> {
|
||||||
// Write node.conf
|
return executorService.submit<Process> {
|
||||||
writeConfig(nodeConf.baseDirectory, "node.conf", nodeConf.config)
|
// 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 systemProperties = mapOf(
|
||||||
val separator = System.getProperty("file.separator")
|
"name" to nodeConf.myLegalName,
|
||||||
val classpath = System.getProperty("java.class.path")
|
"visualvm.display.name" to "Corda"
|
||||||
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
) + 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)
|
ProcessUtilities.startJavaProcess(
|
||||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort"
|
className = "net.corda.node.Corda", // cannot directly get class for this, so just use string
|
||||||
else
|
arguments = listOf(
|
||||||
""
|
"--base-directory=${nodeConf.baseDirectory}",
|
||||||
|
"--logging-level=$loggingLevel",
|
||||||
val systemProperties = mapOf(
|
"--no-local-shell"
|
||||||
"name" to nodeConf.myLegalName,
|
),
|
||||||
"visualvm.display.name" to "Corda"
|
extraJvmArguments = extraJvmArguments,
|
||||||
) + overriddenSystemProperties
|
errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log",
|
||||||
|
workingDirectory = nodeConf.baseDirectory
|
||||||
val loggingLevel = if (debugPort == null) "INFO" else "DEBUG"
|
)
|
||||||
val javaArgs = listOf(path) +
|
}.flatMap { process -> addressMustBeBound(executorService, nodeConf.p2pAddress).map { process } }
|
||||||
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 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startWebserver(
|
private fun startWebserver(
|
||||||
executorService: ScheduledExecutorService,
|
executorService: ListeningScheduledExecutorService,
|
||||||
nodeConf: FullNodeConfiguration,
|
nodeConf: FullNodeConfiguration,
|
||||||
debugPort: Int?): ListenableFuture<Process> {
|
debugPort: Int?
|
||||||
val className = "net.corda.webserver.WebServer" // cannot directly get class for this, so just use string
|
): ListenableFuture<Process> {
|
||||||
val separator = System.getProperty("file.separator")
|
return executorService.submit<Process> {
|
||||||
val classpath = System.getProperty("java.class.path")
|
val className = "net.corda.webserver.WebServer"
|
||||||
val path = System.getProperty("java.home") + separator + "bin" + separator + "java"
|
ProcessUtilities.startJavaProcess(
|
||||||
|
className = className, // cannot directly get class for this, so just use string
|
||||||
val debugPortArg = if (debugPort != null)
|
arguments = listOf("--base-directory", nodeConf.baseDirectory.toString()),
|
||||||
listOf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$debugPort")
|
jdwpPort = debugPort,
|
||||||
else
|
extraJvmArguments = listOf("-Dname=node-${nodeConf.p2pAddress}-webserver"),
|
||||||
emptyList()
|
errorLogPath = Paths.get("error.$className.log")
|
||||||
|
)
|
||||||
val javaArgs = listOf(path) +
|
}.flatMap { process -> addressMustBeBound(executorService, nodeConf.webAddress).map { process } }
|
||||||
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 }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.map
|
||||||
import net.corda.core.random63BitValue
|
import net.corda.core.random63BitValue
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
import net.corda.core.utilities.ProcessUtilities
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.driver.*
|
import net.corda.node.driver.*
|
||||||
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
import net.corda.node.services.config.configureDevKeyAndTrustStores
|
||||||
@ -240,35 +241,16 @@ data class VerifierDriverDSL(
|
|||||||
override fun startVerifier(address: HostAndPort): ListenableFuture<VerifierHandle> {
|
override fun startVerifier(address: HostAndPort): ListenableFuture<VerifierHandle> {
|
||||||
log.info("Starting verifier connecting to address $address")
|
log.info("Starting verifier connecting to address $address")
|
||||||
val id = verifierCount.andIncrement
|
val id = verifierCount.andIncrement
|
||||||
val verifierName = "verifier$id"
|
val jdwpPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
|
||||||
val baseDirectory = driverDSL.driverDirectory / verifierName
|
val processFuture = driverDSL.executorService.submit<Process> {
|
||||||
val config = createConfiguration(baseDirectory, address)
|
val verifierName = "verifier$id"
|
||||||
val configFilename = "verifier.conf"
|
val baseDirectory = driverDSL.driverDirectory / verifierName
|
||||||
writeConfig(baseDirectory, configFilename, config)
|
val config = createConfiguration(baseDirectory, address)
|
||||||
Verifier.loadConfiguration(baseDirectory, baseDirectory / configFilename).configureDevKeyAndTrustStores(verifierName)
|
val configFilename = "verifier.conf"
|
||||||
|
writeConfig(baseDirectory, configFilename, config)
|
||||||
val className = Verifier::class.java.name
|
Verifier.loadConfiguration(baseDirectory, baseDirectory / configFilename).configureDevKeyAndTrustStores(verifierName)
|
||||||
val separator = System.getProperty("file.separator")
|
ProcessUtilities.startJavaProcess<Verifier>(listOf(baseDirectory.toString()), jdwpPort = jdwpPort)
|
||||||
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() }
|
|
||||||
driverDSL.shutdownManager.registerProcessShutdown(processFuture)
|
driverDSL.shutdownManager.registerProcessShutdown(processFuture)
|
||||||
return processFuture.map(::VerifierHandle)
|
return processFuture.map(::VerifierHandle)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user