mirror of
https://github.com/corda/corda.git
synced 2025-03-14 16:26:36 +00:00
Merge remote-tracking branch 'open/master' into os-merge-aefd90f
# Conflicts: # CONTRIBUTORS.md
This commit is contained in:
commit
5d55a87d70
@ -48,7 +48,6 @@ import org.junit.Before
|
||||
import org.junit.ClassRule
|
||||
import org.junit.Test
|
||||
import rx.subjects.PublishSubject
|
||||
import java.io.File.pathSeparator
|
||||
import java.net.URLClassLoader
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
@ -249,15 +248,12 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
|
||||
@Test
|
||||
fun `additional class loader used by WireTransaction when it deserialises its components`() {
|
||||
val financeLocation = Cash::class.java.location.toPath().toString()
|
||||
val classpathWithoutFinance = ProcessUtilities.defaultClassPath
|
||||
.split(pathSeparator)
|
||||
.filter { financeLocation !in it }
|
||||
.joinToString(pathSeparator)
|
||||
val classPathWithoutFinance = ProcessUtilities.defaultClassPath.filter { financeLocation !in it }
|
||||
|
||||
// Create a Cash.State object for the StandaloneCashRpcClient to get
|
||||
node.services.startFlow(CashIssueFlow(100.POUNDS, OpaqueBytes.of(1), identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow()
|
||||
val outOfProcessRpc = ProcessUtilities.startJavaProcess<StandaloneCashRpcClient>(
|
||||
classpath = classpathWithoutFinance,
|
||||
classPath = classPathWithoutFinance,
|
||||
arguments = listOf(node.internals.configuration.rpcOptions.address.toString(), financeLocation)
|
||||
)
|
||||
assertThat(outOfProcessRpc.waitFor()).isZero() // i.e. no exceptions were thrown
|
||||
|
@ -27,11 +27,11 @@ Uploading and downloading
|
||||
To upload an attachment to the node, or download an attachment named by its hash, you use :doc:`clientrpc`. This
|
||||
is also available for interactive use via the shell. To **upload** run:
|
||||
|
||||
``>>> run uploadAttachment jar: /path/to/the/file.jar``
|
||||
``>>> run uploadAttachment jar: path/to/the/file.jar``
|
||||
|
||||
or
|
||||
|
||||
``>>> run uploadAttachmentWithMetadata jar: /path/to/the/file.jar, uploader: myself, filename: original_name.jar``
|
||||
``>>> run uploadAttachmentWithMetadata jar: path/to/the/file.jar, uploader: myself, filename: original_name.jar``
|
||||
|
||||
to include the metadata with the attachment which can be used to find it later on. Note, that currently both uploader
|
||||
and filename are just plain strings (there is no connection between uploader and the RPC users for example).
|
||||
|
@ -99,7 +99,7 @@ Let's add a ``CommercialPaper`` transaction:
|
||||
}
|
||||
|
||||
We can add a transaction to the ledger using the ``transaction`` primitive. The transaction in turn may be defined by
|
||||
specifying ``input``-s, ``output``-s, ``command``-s and ``attachment``-s.
|
||||
specifying ``input``s, ``output``s, ``command``s and ``attachment``s.
|
||||
|
||||
The above ``input`` call is a bit special; transactions don't actually contain input states, just references
|
||||
to output states of other transactions. Under the hood the above ``input`` call creates a dummy transaction in the
|
||||
|
@ -12,4 +12,4 @@
|
||||
# Note: sadly, due to present limitation of IntelliJ-IDEA in processing resource files, these constants cannot be
|
||||
# imported from top-level 'constants.properties' file
|
||||
|
||||
jolokiaAgentVersion=1.5.0
|
||||
jolokiaAgentVersion=1.6.0
|
||||
|
@ -75,20 +75,18 @@ class IRSDemoTest : IntegrationTest() {
|
||||
isDebug = true,
|
||||
extraCordappPackagesToScan = listOf("net.corda.irs")
|
||||
)) {
|
||||
val (nodeA, nodeB) = listOf(
|
||||
val (controller, nodeA, nodeB) = listOf(
|
||||
defaultNotaryNode,
|
||||
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = rpcUsers),
|
||||
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = rpcUsers),
|
||||
startNode(providedName = CordaX500Name("Regulator", "Moscow", "RU"))
|
||||
).map { it.getOrThrow() }
|
||||
val controller = defaultNotaryNode.getOrThrow()
|
||||
|
||||
log.info("All nodes started")
|
||||
|
||||
val controllerAddrFuture = startSpringBootWebapp(IrsDemoWebApplication::class.java, controller, "/api/irs/demodate")
|
||||
val nodeAAddrFuture = startSpringBootWebapp(IrsDemoWebApplication::class.java, nodeA, "/api/irs/demodate")
|
||||
val nodeBAddrFuture = startSpringBootWebapp(IrsDemoWebApplication::class.java, nodeB, "/api/irs/demodate")
|
||||
val (controllerAddr, nodeAAddr, nodeBAddr) =
|
||||
listOf(controllerAddrFuture, nodeAAddrFuture, nodeBAddrFuture).map { it.getOrThrow().listenAddress }
|
||||
val (controllerAddr, nodeAAddr, nodeBAddr) = listOf(controller, nodeA, nodeB).map {
|
||||
startSpringBootWebapp(IrsDemoWebApplication::class.java, it, "/api/irs/demodate")
|
||||
}.map { it.getOrThrow().listenAddress }
|
||||
|
||||
log.info("All webservers started")
|
||||
|
||||
|
@ -85,16 +85,14 @@ data class SpringBootDriverDSL(private val driverDSL: DriverDSLImpl) : InternalD
|
||||
}
|
||||
|
||||
private fun startApplication(handle: NodeHandle, debugPort: Int?, clazz: Class<*>): Process {
|
||||
val className = clazz.canonicalName
|
||||
return ProcessUtilities.startJavaProcessImpl(
|
||||
className = className, // cannot directly get class for this, so just use string
|
||||
return ProcessUtilities.startJavaProcess(
|
||||
className = clazz.canonicalName, // cannot directly get class for this, so just use string
|
||||
jdwpPort = debugPort,
|
||||
extraJvmArguments = listOf(
|
||||
"-Dname=node-${handle.p2pAddress}-webserver",
|
||||
"-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}"
|
||||
// Inherit from parent process
|
||||
),
|
||||
classpath = ProcessUtilities.defaultClassPath,
|
||||
workingDirectory = handle.baseDirectory,
|
||||
arguments = listOf(
|
||||
"--base-directory", handle.baseDirectory.toString(),
|
||||
@ -102,8 +100,7 @@ data class SpringBootDriverDSL(private val driverDSL: DriverDSLImpl) : InternalD
|
||||
"--corda.host=${handle.rpcAddress}",
|
||||
"--corda.user=${handle.rpcUsers.first().username}",
|
||||
"--corda.password=${handle.rpcUsers.first().password}"
|
||||
),
|
||||
maximumHeapSize = null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.millis
|
||||
import net.corda.node.NodeRegistrationOption
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.internal.ConfigurationException
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.Permissions
|
||||
@ -846,7 +845,7 @@ class DriverDSLImpl(
|
||||
it += extraCmdLineFlag
|
||||
}.toList()
|
||||
|
||||
return ProcessUtilities.startCordaProcess(
|
||||
return ProcessUtilities.startJavaProcess(
|
||||
className = "net.corda.node.Corda", // cannot directly get class for this, so just use string
|
||||
arguments = arguments,
|
||||
jdwpPort = debugPort,
|
||||
@ -859,13 +858,12 @@ class DriverDSLImpl(
|
||||
private fun startWebserver(handle: NodeHandleInternal, debugPort: Int?, maximumHeapSize: String): Process {
|
||||
val className = "net.corda.webserver.WebServer"
|
||||
writeConfig(handle.baseDirectory, "web-server.conf", handle.toWebServerConfig())
|
||||
return ProcessUtilities.startCordaProcess(
|
||||
return ProcessUtilities.startJavaProcess(
|
||||
className = className, // cannot directly get class for this, so just use string
|
||||
arguments = listOf("--base-directory", handle.baseDirectory.toString()),
|
||||
jdwpPort = debugPort,
|
||||
extraJvmArguments = listOf("-Dname=node-${handle.p2pAddress}-webserver") +
|
||||
inheritFromParentProcess().map { "-D${it.first}=${it.second}" },
|
||||
workingDirectory = null,
|
||||
maximumHeapSize = maximumHeapSize
|
||||
)
|
||||
}
|
||||
|
@ -11,40 +11,32 @@
|
||||
package net.corda.testing.node.internal
|
||||
|
||||
import net.corda.core.internal.div
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
object ProcessUtilities {
|
||||
inline fun <reified C : Any> startJavaProcess(
|
||||
arguments: List<String>,
|
||||
classpath: String = defaultClassPath,
|
||||
classPath: List<String> = defaultClassPath,
|
||||
workingDirectory: Path? = null,
|
||||
jdwpPort: Int? = null,
|
||||
extraJvmArguments: List<String> = emptyList()
|
||||
extraJvmArguments: List<String> = emptyList(),
|
||||
maximumHeapSize: String? = null
|
||||
): Process {
|
||||
return startJavaProcessImpl(C::class.java.name, arguments, classpath, jdwpPort, extraJvmArguments, null, null)
|
||||
return startJavaProcess(C::class.java.name, arguments, classPath, workingDirectory, jdwpPort, extraJvmArguments, maximumHeapSize)
|
||||
}
|
||||
|
||||
fun startCordaProcess(
|
||||
fun startJavaProcess(
|
||||
className: String,
|
||||
arguments: List<String>,
|
||||
jdwpPort: Int?,
|
||||
extraJvmArguments: List<String>,
|
||||
workingDirectory: Path?,
|
||||
maximumHeapSize: String
|
||||
): Process {
|
||||
return startJavaProcessImpl(className, arguments, defaultClassPath, jdwpPort, extraJvmArguments, workingDirectory, maximumHeapSize)
|
||||
}
|
||||
|
||||
fun startJavaProcessImpl(
|
||||
className: String,
|
||||
arguments: List<String>,
|
||||
classpath: String,
|
||||
jdwpPort: Int?,
|
||||
extraJvmArguments: List<String>,
|
||||
workingDirectory: Path?,
|
||||
maximumHeapSize: String?
|
||||
classPath: List<String> = defaultClassPath,
|
||||
workingDirectory: Path? = null,
|
||||
jdwpPort: Int? = null,
|
||||
extraJvmArguments: List<String> = emptyList(),
|
||||
maximumHeapSize: String? = null
|
||||
): Process {
|
||||
val command = mutableListOf<String>().apply {
|
||||
add((System.getProperty("java.home") / "bin" / "java").toString())
|
||||
add(javaPath)
|
||||
(jdwpPort != null) && add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$jdwpPort")
|
||||
if (maximumHeapSize != null) add("-Xmx$maximumHeapSize")
|
||||
add("-XX:+UseG1GC")
|
||||
@ -54,7 +46,7 @@ object ProcessUtilities {
|
||||
}
|
||||
return ProcessBuilder(command).apply {
|
||||
inheritIO()
|
||||
environment()["CLASSPATH"] = classpath
|
||||
environment()["CLASSPATH"] = classPath.joinToString(File.pathSeparator)
|
||||
if (workingDirectory != null) {
|
||||
redirectError((workingDirectory / "$className.stderr.log").toFile())
|
||||
redirectOutput((workingDirectory / "$className.stdout.log").toFile())
|
||||
@ -63,5 +55,7 @@ object ProcessUtilities {
|
||||
}.start()
|
||||
}
|
||||
|
||||
val defaultClassPath: String get() = System.getProperty("java.class.path")
|
||||
private val javaPath = (System.getProperty("java.home") / "bin" / "java").toString()
|
||||
|
||||
val defaultClassPath: List<String> = System.getProperty("java.class.path").split(File.pathSeparator)
|
||||
}
|
@ -7,7 +7,6 @@ import net.corda.bootstrapper.notaries.NotaryCopier
|
||||
import net.corda.bootstrapper.notaries.NotaryFinder
|
||||
import java.io.File
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
interface NetworkBuilder {
|
||||
|
||||
@ -23,7 +22,6 @@ interface NetworkBuilder {
|
||||
fun onNodePushed(callback: (PushedNode) -> Unit): NetworkBuilder
|
||||
fun onNodeInstance(callback: (NodeInstance) -> Unit): NetworkBuilder
|
||||
|
||||
fun withNodeCounts(map: Map<String, Int>): NetworkBuilder
|
||||
fun withNetworkName(networtName: String): NetworkBuilder
|
||||
fun withBasedir(baseDir: File): NetworkBuilder
|
||||
fun withBackend(backendType: Backend.BackendType): NetworkBuilder
|
||||
@ -104,11 +102,6 @@ private class NetworkBuilderImpl : NetworkBuilder {
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withNodeCounts(map: Map<String, Int>): NetworkBuilder {
|
||||
nodeCounts = ConcurrentHashMap(map.entries.map { it.key.toLowerCase() to it.value }.toMap())
|
||||
return this
|
||||
}
|
||||
|
||||
override fun withNetworkName(networtName: String): NetworkBuilder {
|
||||
this.networkName = networtName
|
||||
return this
|
||||
|
@ -8,6 +8,7 @@ import net.corda.bootstrapper.context.Context
|
||||
import net.corda.bootstrapper.nodes.NodeAdder
|
||||
import net.corda.bootstrapper.nodes.NodeInstantiator
|
||||
import net.corda.bootstrapper.toSingleFuture
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import java.io.File
|
||||
|
||||
@ -23,7 +24,6 @@ class CommandLineInterface {
|
||||
val (_, context) = NetworkBuilder.instance()
|
||||
.withBasedir(baseDir)
|
||||
.withNetworkName(networkName)
|
||||
.withNodeCounts(parsedArgs.nodes)
|
||||
.onNodeBuild { builtNode -> println("Built node: ${builtNode.name} to image: ${builtNode.localImageId}") }
|
||||
.onNodePushed { pushedNode -> println("Pushed node: ${pushedNode.name} to: ${pushedNode.remoteImageName}") }
|
||||
.onNodeInstance { instance ->
|
||||
@ -40,7 +40,7 @@ class CommandLineInterface {
|
||||
val (_, instantiator, _) = Backend.fromContext(context, cacheDir)
|
||||
val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context))
|
||||
parsedArgs.nodesToAdd.map {
|
||||
nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.toLowerCase(), ""))
|
||||
nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.key.toLowerCase(), ""), CordaX500Name.parse(it.value))
|
||||
}.toSingleFuture().getOrThrow()
|
||||
persistContext(contextFile, objectMapper, context)
|
||||
}
|
||||
|
@ -20,11 +20,9 @@ open class CliParser {
|
||||
@Option(names = ["-b", "--backend"], description = ["The backend to use when instantiating nodes"])
|
||||
var backendType: Backend.BackendType = Backend.BackendType.LOCAL_DOCKER
|
||||
|
||||
@Option(names = ["--nodes"], split = ":", description = ["The number of each node to create. NodeX:2 will create two instances of NodeX"])
|
||||
var nodes: MutableMap<String, Int> = hashMapOf()
|
||||
|
||||
@Option(names = ["--add", "-a"])
|
||||
var nodesToAdd: MutableList<String> = arrayListOf()
|
||||
@Option(names = ["--add"], split = ":", description = ["The node to add. Format is <Name>:<X500>. Eg; \"Node1:O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name\""])
|
||||
var nodesToAdd: MutableMap<String, String> = hashMapOf()
|
||||
|
||||
fun isNew(): Boolean {
|
||||
return nodesToAdd.isEmpty()
|
||||
|
@ -21,6 +21,7 @@ import net.corda.bootstrapper.baseArgs
|
||||
import net.corda.bootstrapper.context.Context
|
||||
import net.corda.bootstrapper.nodes.*
|
||||
import net.corda.bootstrapper.notaries.NotaryFinder
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import org.apache.commons.lang3.RandomStringUtils
|
||||
import org.controlsfx.control.SegmentedButton
|
||||
import tornadofx.*
|
||||
@ -70,7 +71,6 @@ class BootstrapperView : View("Corda Network Builder") {
|
||||
}
|
||||
}
|
||||
|
||||
val nodeCount = controller.foundNodes.map { it.id to it.count }.toMap()
|
||||
val result = NetworkBuilder.instance()
|
||||
.withBasedir(controller.baseDir.get())
|
||||
.withNetworkName(networkName)
|
||||
@ -81,7 +81,6 @@ class BootstrapperView : View("Corda Network Builder") {
|
||||
.onNodeInstancesRequested(controller::addInstanceRequests)
|
||||
.onNodeInstance(controller::addInstance)
|
||||
.withBackend(selectedBackEnd)
|
||||
.withNodeCounts(nodeCount)
|
||||
.withBackendOptions(backendParams)
|
||||
.build()
|
||||
|
||||
@ -118,6 +117,10 @@ class BootstrapperView : View("Corda Network Builder") {
|
||||
enableWhen { controller.networkContext.isNotNull }
|
||||
action {
|
||||
templateChoiceBox.selectionModel.selectedItem?.let { nodeToAdd ->
|
||||
|
||||
val textInputDialog = TextInputDialog("O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name")
|
||||
textInputDialog.title = "X500 of node to add"
|
||||
val x500ToUse = textInputDialog.showAndWait().orElseGet { null }
|
||||
val context = controller.networkContext.value
|
||||
runLater {
|
||||
val (_, instantiator, _) = Backend.fromContext(
|
||||
@ -125,7 +128,7 @@ class BootstrapperView : View("Corda Network Builder") {
|
||||
File(controller.baseDir.get(), Constants.BOOTSTRAPPER_DIR_NAME))
|
||||
val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context))
|
||||
controller.addInstanceRequest(nodeToAdd)
|
||||
nodeAdder.addNode(context, nodeToAdd).handleAsync { instanceInfo, t ->
|
||||
nodeAdder.addNode(context, nodeToAdd, x500ToUse?.let { CordaX500Name.parse(it) }).handleAsync { instanceInfo, t ->
|
||||
t?.let {
|
||||
GuiUtils.showException("Failed", "Failed to add node", it)
|
||||
}
|
||||
@ -263,10 +266,6 @@ class BootstrapperView : View("Corda Network Builder") {
|
||||
compareValues(o1.nodeType.toString() + o1.templateId, o2.nodeType.toString() + o2.templateId) * -1
|
||||
})
|
||||
|
||||
fun clear() {
|
||||
networkContext.set(null)
|
||||
}
|
||||
|
||||
fun clearAll() {
|
||||
networkContext.set(null)
|
||||
foundNodes.clear()
|
||||
|
@ -2,17 +2,18 @@ package net.corda.bootstrapper.nodes
|
||||
|
||||
import net.corda.bootstrapper.containers.instance.InstanceInfo
|
||||
import net.corda.bootstrapper.context.Context
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class NodeAdder(val context: Context,
|
||||
val nodeInstantiator: NodeInstantiator) {
|
||||
|
||||
fun addNode(context: Context, nodeGroupName: String): CompletableFuture<InstanceInfo> {
|
||||
fun addNode(context: Context, nodeGroupName: String, x500ToAdd: CordaX500Name?): CompletableFuture<InstanceInfo> {
|
||||
return synchronized(context) {
|
||||
val nodeGroup = context.nodes[nodeGroupName]!!
|
||||
val nodeInfo = nodeGroup.iterator().next()
|
||||
val currentNodeSize = nodeGroup.size
|
||||
val newInstanceX500 = nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString()
|
||||
val newInstanceX500 = x500ToAdd?.toString() ?: nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString()
|
||||
val newInstanceName = nodeGroupName + (currentNodeSize)
|
||||
val nextNodeInfo = nodeInfo.copy(
|
||||
instanceX500 = newInstanceX500,
|
||||
|
@ -21,10 +21,10 @@ open class NodeBuilder {
|
||||
val copiedNodeConfig = copiedNode.copiedNodeConfig
|
||||
val nodeDir = copiedNodeConfig.parentFile
|
||||
if (!copiedNodeConfig.exists()) {
|
||||
throw IllegalStateException("There is no nodeConfig for dir: " + copiedNodeConfig)
|
||||
throw IllegalStateException("There is no nodeConfig for dir: $copiedNodeConfig")
|
||||
}
|
||||
val nodeConfig = ConfigFactory.parseFile(copiedNodeConfig)
|
||||
LOG.info("starting to build docker image for: " + nodeDir)
|
||||
LOG.info("starting to build docker image for: $nodeDir")
|
||||
val nodeImageId = localDockerClient.buildImageCmd()
|
||||
.withDockerfile(File(nodeDir, "Dockerfile"))
|
||||
.withBaseDirectory(nodeDir)
|
||||
|
Loading…
x
Reference in New Issue
Block a user