diff --git a/build.gradle b/build.gradle
index 78c6cd1a9d..00017526b2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,6 +29,7 @@ buildscript {
ext.jopt_simple_version = '5.0.2'
ext.jansi_version = '1.14'
ext.hibernate_version = '5.2.6.Final'
+ ext.h2_version = '1.4.193'
ext.dokka_version = '0.9.13'
repositories {
diff --git a/doorman/src/main/resources/reference.conf b/doorman/src/main/resources/reference.conf
index 355d6f1095..dcf1ccff1c 100644
--- a/doorman/src/main/resources/reference.conf
+++ b/doorman/src/main/resources/reference.conf
@@ -11,3 +11,11 @@ dataSourceProperties {
"dataSource.password" = ""
}
h2port = 0
+
+jiraConfig{
+ address = "https://doorman-jira-host/"
+ projectCode = "TD"
+ username = "username"
+ password = "password"
+ doneTransitionCode = 41
+}
diff --git a/node/build.gradle b/node/build.gradle
index a061ad7f4f..0b79c39e63 100644
--- a/node/build.gradle
+++ b/node/build.gradle
@@ -130,7 +130,7 @@ dependencies {
testCompile project(':core')
// For H2 database support in persistence
- compile "com.h2database:h2:1.4.193"
+ compile "com.h2database:h2:$h2_version"
// Exposed: Kotlin SQL library - under evaluation
// TODO: Upgrade to Exposed 0.7 (has API changes)
diff --git a/package-demobench-dmg.sh b/package-demobench-dmg.sh
new file mode 100755
index 0000000000..18f4c6c1ba
--- /dev/null
+++ b/package-demobench-dmg.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+DIRNAME=$(dirname $0)
+
+if [ -z "$JAVA_HOME" -o ! -x $JAVA_HOME/bin/java ]; then
+ echo "Please set JAVA_HOME correctly"
+ exit 1
+fi
+
+exec $DIRNAME/gradlew -PpackageType=dmg javapackage $*
diff --git a/package-demobench-exe.bat b/package-demobench-exe.bat
new file mode 100644
index 0000000000..682fd3de1f
--- /dev/null
+++ b/package-demobench-exe.bat
@@ -0,0 +1,17 @@
+@echo off
+
+@rem Creates an EXE installer for DemoBench.
+@rem Assumes that Inno Setup 5+ has already been installed (http://www.jrsoftware.org/isinfo.php)
+
+if not defined JAVA_HOME goto NoJavaHome
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+
+call %DIRNAME%\gradlew -PpackageType=exe javapackage
+goto end
+
+:NoJavaHome
+echo "Please set JAVA_HOME correctly"
+
+:end
diff --git a/settings.gradle b/settings.gradle
index 966b143624..3a82a6f1b2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -11,8 +11,9 @@ include 'doorman'
include 'experimental'
include 'experimental:sandbox'
include 'test-utils'
-include 'tools:demobench'
include 'tools:explorer'
+include 'tools:explorer:capsule'
+include 'tools:demobench'
include 'tools:loadtest'
include 'docs/source/example-code' // Note that we are deliberately choosing to use '/' here. With ':' gradle would treat the directories as actual projects.
include 'samples:attachment-demo'
diff --git a/tools/demobench/build.gradle b/tools/demobench/build.gradle
index c6dded517b..8977461c1b 100644
--- a/tools/demobench/build.gradle
+++ b/tools/demobench/build.gradle
@@ -1,10 +1,20 @@
-group 'net.corda'
-version '0.7-SNAPSHOT'
-
buildscript {
ext.kotlin_version = '1.0.6'
+ ext.tornadofx_version = '1.6.2'
+ ext.jna_version = '4.1.0'
+ ext.purejavacomm_version = '0.0.17'
+ ext.guava_version = '14.0.1'
+ ext.slf4j_version = '1.7.22'
+ ext.logback_version = '1.1.10'
+ ext.controlsfx_version = '8.40.12'
+
+ ext.java_home = System.properties.'java.home'
+ ext.pkg_source = "$buildDir/packagesrc"
+ ext.dist_source = "$pkg_source/demobench-$version"
+ ext.pkg_version = "$version".indexOf('-') >= 0 ? "$version".substring(0, "$version".indexOf('-')) : version
repositories {
+ mavenLocal()
mavenCentral()
}
dependencies {
@@ -14,17 +24,185 @@ buildscript {
apply plugin: 'java'
apply plugin: 'kotlin'
+apply plugin: 'application'
+
+evaluationDependsOn(':tools:explorer:capsule')
sourceCompatibility = 1.8
+mainClassName = 'net.corda.demobench.DemoBench'
+applicationDefaultJvmArgs = ['-Djava.util.logging.config.class=net.corda.demobench.config.LoggingConfig']
repositories {
+ flatDir {
+ dirs 'libs'
+ }
+
+ mavenLocal()
mavenCentral()
+ jcenter()
+ maven {
+ url 'http://www.sparetimelabs.com/maven2'
+ }
+ maven {
+ url 'https://dl.bintray.com/kotlin/exposed'
+ }
}
dependencies {
- compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- testCompile group: 'junit', name: 'junit', version: '4.11'
-
// TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's.
- compile 'no.tornado:tornadofx:1.5.7'
+ compile "no.tornado:tornadofx:$tornadofx_version"
+ compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+
+ // Controls FX: more java FX components http://fxexperience.com/controlsfx/
+ compile "org.controlsfx:controlsfx:$controlsfx_version"
+
+ // ONLY USING THE RPC CLIENT!?
+ compile project(':node')
+
+ compile "com.h2database:h2:$h2_version"
+ compile "net.java.dev.jna:jna:$jna_version"
+ compile "net.java.dev.jna:jna-platform:$jna_version"
+ compile "com.google.guava:guava:$guava_version"
+ compile "com.sparetimelabs:purejavacomm:$purejavacomm_version"
+ compile "org.apache.logging.log4j:log4j-to-slf4j:$log4j_version"
+ compile "org.slf4j:log4j-over-slf4j:$slf4j_version"
+ compile "org.slf4j:jcl-over-slf4j:$slf4j_version"
+ compile "org.slf4j:jul-to-slf4j:$slf4j_version"
+ compile "ch.qos.logback:logback-classic:$logback_version"
+ compile "com.typesafe:config:$typesafe_config_version"
+
+ // These libraries don't exist in any Maven repository I can find.
+ // See: https://github.com/JetBrains/jediterm
+ //
+ // The terminal JAR here has also been tweaked:
+ // See: https://github.com/JetBrains/jediterm/issues/144
+ compile ':jediterm-terminal-2.5'
+ compile ':pty4j-0.7.2'
+
+ testCompile group: 'junit', name: 'junit', version: junit_version
}
+
+// We don't want the Node to drag these transitive dependencies in either!
+configurations.all {
+ exclude module: 'commons-logging'
+ exclude module: 'log4j-slf4j-impl'
+ exclude module: 'log4j-core'
+}
+
+jar {
+ manifest {
+ attributes(
+ 'Corda-Version': corda_version,
+ 'Main-Class': mainClassName,
+ 'Class-Path': configurations.compile.collect { it.getName() }.join(' ')
+ )
+ }
+}
+
+distributions {
+ main() {
+ contents {
+ into('lib/linux') {
+ from 'libs/linux'
+ }
+ into('lib/macosx') {
+ from 'libs/macosx'
+ }
+ into('lib/win') {
+ from 'libs/win'
+ }
+ from(project(':tools:explorer:capsule').tasks.buildExplorerJAR) {
+ rename 'node-explorer-(.*)', 'node-explorer.jar'
+ into 'explorer'
+ }
+ from(project(':node:capsule').tasks.buildCordaJAR) {
+ rename 'corda-(.*)', 'corda.jar'
+ into 'corda'
+ }
+ from(project(':samples:bank-of-corda-demo').jar) {
+ rename 'bank-of-corda-demo-(.*)', 'bank-of-corda.jar'
+ into 'plugins'
+ }
+ }
+ }
+}
+
+/*
+ * Bundles the application using JavaPackager,
+ * using the ZIP distribution as source.
+ */
+task javapackage(dependsOn: 'distZip') {
+
+ doLast {
+ delete([pkg_source, "$buildDir/exedir"])
+
+ copy {
+ from(zipTree(distZip.outputs.files.singleFile))
+ into pkg_source
+ }
+
+ copy {
+ /*
+ * Copy non-text formats "as-is".
+ */
+ from("$projectDir/package") {
+ exclude '**/*.spec'
+ exclude '**/*.sh'
+ exclude '**/*.wsf'
+ exclude '**/*.manifest'
+ }
+ into "$pkg_source/package"
+ }
+
+ copy {
+ /*
+ * Expand tokens for text formats.
+ */
+ from("$projectDir/package") {
+ include '**/*.spec'
+ include '**/*.sh'
+ include '**/*.wsf'
+ include '**/*.manifest'
+ }
+ filter {
+ line -> line.replaceAll('@pkg_version@', pkg_version)
+ }
+ into "$pkg_source/package"
+ }
+
+ ant.taskdef(
+ resource: 'com/sun/javafx/tools/ant/antlib.xml',
+ classpath: "$pkg_source:$java_home/../lib/ant-javafx.jar"
+ )
+
+ ant.deploy(nativeBundles: packageType, outdir: "$buildDir/exedir", outfile: 'DemoBench', verbose: 'true') {
+ application(name: 'DemoBench', version: pkg_version, mainClass: mainClassName)
+ info(title: 'DemoBench', vendor: 'R3', description: 'A sales and educational tool for demonstrating Corda.')
+ resources {
+ fileset(dir: "$dist_source/lib", type: 'jar') {
+ include(name: '*.jar')
+ }
+
+ fileset(dir: "$dist_source/lib", type: 'native') {
+ include(name: "macosx/**/*.dylib")
+ include(name: "win/**/*.dll")
+ include(name: "win/**/*.exe")
+ include(name: "linux/**/*.so")
+ }
+
+ fileset(dir: dist_source, type: 'data') {
+ include(name: 'corda/*.jar')
+ include(name: 'plugins/*.jar')
+ include(name: 'explorer/*.jar')
+ }
+ }
+
+ platform {
+ property(name: 'java.util.logging.config.class', value: 'net.corda.demobench.config.LoggingConfig')
+ }
+
+ preferences(install: false)
+ }
+ }
+}
+
diff --git a/tools/demobench/libs/jediterm-terminal-2.5.jar b/tools/demobench/libs/jediterm-terminal-2.5.jar
new file mode 100644
index 0000000000..b211b2d08e
Binary files /dev/null and b/tools/demobench/libs/jediterm-terminal-2.5.jar differ
diff --git a/tools/demobench/libs/linux/x86/libpty.so b/tools/demobench/libs/linux/x86/libpty.so
new file mode 100755
index 0000000000..832504bc8d
Binary files /dev/null and b/tools/demobench/libs/linux/x86/libpty.so differ
diff --git a/tools/demobench/libs/linux/x86_64/libpty.so b/tools/demobench/libs/linux/x86_64/libpty.so
new file mode 100755
index 0000000000..cd41f3b15b
Binary files /dev/null and b/tools/demobench/libs/linux/x86_64/libpty.so differ
diff --git a/tools/demobench/libs/macosx/x86/libpty.dylib b/tools/demobench/libs/macosx/x86/libpty.dylib
new file mode 100755
index 0000000000..f05fb026cf
Binary files /dev/null and b/tools/demobench/libs/macosx/x86/libpty.dylib differ
diff --git a/tools/demobench/libs/macosx/x86_64/libpty.dylib b/tools/demobench/libs/macosx/x86_64/libpty.dylib
new file mode 100755
index 0000000000..1093ba1c84
Binary files /dev/null and b/tools/demobench/libs/macosx/x86_64/libpty.dylib differ
diff --git a/tools/demobench/libs/pty4j-0.7.2.jar b/tools/demobench/libs/pty4j-0.7.2.jar
new file mode 100644
index 0000000000..e336572696
Binary files /dev/null and b/tools/demobench/libs/pty4j-0.7.2.jar differ
diff --git a/tools/demobench/libs/win/x86/libwinpty.dll b/tools/demobench/libs/win/x86/libwinpty.dll
new file mode 100644
index 0000000000..e1644b8ee8
Binary files /dev/null and b/tools/demobench/libs/win/x86/libwinpty.dll differ
diff --git a/tools/demobench/libs/win/x86/winpty-agent.exe b/tools/demobench/libs/win/x86/winpty-agent.exe
new file mode 100644
index 0000000000..3abad80b84
Binary files /dev/null and b/tools/demobench/libs/win/x86/winpty-agent.exe differ
diff --git a/tools/demobench/libs/win/x86/winpty.dll b/tools/demobench/libs/win/x86/winpty.dll
new file mode 100644
index 0000000000..f07b95a27b
Binary files /dev/null and b/tools/demobench/libs/win/x86/winpty.dll differ
diff --git a/tools/demobench/libs/win/x86_64/cyglaunch.exe b/tools/demobench/libs/win/x86_64/cyglaunch.exe
new file mode 100644
index 0000000000..d84e6e964c
Binary files /dev/null and b/tools/demobench/libs/win/x86_64/cyglaunch.exe differ
diff --git a/tools/demobench/libs/win/x86_64/winpty-agent.exe b/tools/demobench/libs/win/x86_64/winpty-agent.exe
new file mode 100644
index 0000000000..e1963c4e3c
Binary files /dev/null and b/tools/demobench/libs/win/x86_64/winpty-agent.exe differ
diff --git a/tools/demobench/libs/win/x86_64/winpty.dll b/tools/demobench/libs/win/x86_64/winpty.dll
new file mode 100644
index 0000000000..f9bdec0394
Binary files /dev/null and b/tools/demobench/libs/win/x86_64/winpty.dll differ
diff --git a/tools/demobench/libs/win/xp/winpty-agent.exe b/tools/demobench/libs/win/xp/winpty-agent.exe
new file mode 100644
index 0000000000..cc18efda8c
Binary files /dev/null and b/tools/demobench/libs/win/xp/winpty-agent.exe differ
diff --git a/tools/demobench/libs/win/xp/winpty.dll b/tools/demobench/libs/win/xp/winpty.dll
new file mode 100644
index 0000000000..bd40cd1e9d
Binary files /dev/null and b/tools/demobench/libs/win/xp/winpty.dll differ
diff --git a/tools/demobench/package/linux/DemoBench.png b/tools/demobench/package/linux/DemoBench.png
new file mode 100644
index 0000000000..d72d6ad543
Binary files /dev/null and b/tools/demobench/package/linux/DemoBench.png differ
diff --git a/tools/demobench/package/linux/DemoBench.spec b/tools/demobench/package/linux/DemoBench.spec
new file mode 100644
index 0000000000..48b2f3c9f1
--- /dev/null
+++ b/tools/demobench/package/linux/DemoBench.spec
@@ -0,0 +1,70 @@
+Summary: DemoBench
+Name: demobench
+Version: @pkg_version@
+Release: 1
+License: Unknown
+Vendor: Unknown
+Prefix: /opt
+Provides: demobench
+Requires: ld-linux.so.2 libX11.so.6 libXext.so.6 libXi.so.6 libXrender.so.1 libXtst.so.6 libasound.so.2 libc.so.6 libdl.so.2 libgcc_s.so.1 libm.so.6 libpthread.so.0 libthread_db.so.1
+Autoprov: 0
+Autoreq: 0
+
+#avoid ARCH subfolder
+%define _rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
+
+#comment line below to enable effective jar compression
+#it could easily get your package size from 40 to 15Mb but
+#build time will substantially increase and it may require unpack200/system java to install
+%define __jar_repack %{nil}
+
+%define _javaHome %{getenv:JAVA_HOME}
+
+%description
+DemoBench
+
+%prep
+
+%build
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/opt
+cp -r %{_sourcedir}/DemoBench %{buildroot}/opt
+mkdir -p %{buildroot}/opt/DemoBench/runtime/bin
+cp %{_javaHome}/jre/bin/java %{buildroot}/opt/DemoBench/runtime/bin
+
+%files
+
+/opt/DemoBench
+
+%post
+
+
+xdg-desktop-menu install --novendor /opt/DemoBench/DemoBench.desktop
+
+if [ "false" = "true" ]; then
+ cp /opt/DemoBench/demobench.init /etc/init.d/demobench
+ if [ -x "/etc/init.d/demobench" ]; then
+ /sbin/chkconfig --add demobench
+ if [ "false" = "true" ]; then
+ /etc/init.d/demobench start
+ fi
+ fi
+fi
+
+%preun
+
+xdg-desktop-menu uninstall --novendor /opt/DemoBench/DemoBench.desktop
+
+if [ "false" = "true" ]; then
+ if [ -x "/etc/init.d/demobench" ]; then
+ if [ "true" = "true" ]; then
+ /etc/init.d/demobench stop
+ fi
+ /sbin/chkconfig --del demobench
+ rm -f /etc/init.d/demobench
+ fi
+fi
+
+%clean
diff --git a/tools/demobench/package/macosx/DemoBench-post-image.sh b/tools/demobench/package/macosx/DemoBench-post-image.sh
new file mode 100644
index 0000000000..14c2c28bea
--- /dev/null
+++ b/tools/demobench/package/macosx/DemoBench-post-image.sh
@@ -0,0 +1,11 @@
+if [ -z "$JAVA_HOME" ]; then
+ echo "**** Please set JAVA_HOME correctly."
+ exit 1
+fi
+
+# Switch to folder containing application.
+cd ../images/image-*/DemoBench.app
+
+INSTALL_HOME=Contents/PlugIns/Java.runtime/Contents/Home/jre/bin
+mkdir -p $INSTALL_HOME
+cp $JAVA_HOME/jre/bin/java $INSTALL_HOME
diff --git a/tools/demobench/package/macosx/DemoBench-volume.icns b/tools/demobench/package/macosx/DemoBench-volume.icns
new file mode 100644
index 0000000000..447d28df81
Binary files /dev/null and b/tools/demobench/package/macosx/DemoBench-volume.icns differ
diff --git a/tools/demobench/package/macosx/DemoBench.icns b/tools/demobench/package/macosx/DemoBench.icns
new file mode 100644
index 0000000000..447d28df81
Binary files /dev/null and b/tools/demobench/package/macosx/DemoBench.icns differ
diff --git a/tools/demobench/package/windows/DemoBench-INVALID-setup-icon.bmp b/tools/demobench/package/windows/DemoBench-INVALID-setup-icon.bmp
new file mode 100644
index 0000000000..7402e28224
Binary files /dev/null and b/tools/demobench/package/windows/DemoBench-INVALID-setup-icon.bmp differ
diff --git a/tools/demobench/package/windows/DemoBench-post-image.wsf b/tools/demobench/package/windows/DemoBench-post-image.wsf
new file mode 100644
index 0000000000..ebb02900db
--- /dev/null
+++ b/tools/demobench/package/windows/DemoBench-post-image.wsf
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/tools/demobench/package/windows/DemoBench.exe.manifest b/tools/demobench/package/windows/DemoBench.exe.manifest
new file mode 100644
index 0000000000..d632713b5e
--- /dev/null
+++ b/tools/demobench/package/windows/DemoBench.exe.manifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
diff --git a/tools/demobench/package/windows/DemoBench.ico b/tools/demobench/package/windows/DemoBench.ico
new file mode 100644
index 0000000000..cf9590ceae
Binary files /dev/null and b/tools/demobench/package/windows/DemoBench.ico differ
diff --git a/tools/demobench/src/main/java/net/corda/demobench/config/LoggingConfig.java b/tools/demobench/src/main/java/net/corda/demobench/config/LoggingConfig.java
new file mode 100644
index 0000000000..44e4c4b251
--- /dev/null
+++ b/tools/demobench/src/main/java/net/corda/demobench/config/LoggingConfig.java
@@ -0,0 +1,34 @@
+package net.corda.demobench.config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.logging.LogManager;
+
+/**
+ * Configuration class for JUL / TornadoFX.
+ * Requires -Djava.util.logging.config.class=net.corda.demobench.config.LoggingConfig
+ * to be added to the JVM's command line.
+ */
+public class LoggingConfig {
+
+ public LoggingConfig() throws IOException {
+ try (InputStream input = getLoggingProperties()) {
+ LogManager manager = LogManager.getLogManager();
+ manager.readConfiguration(input);
+ }
+ }
+
+ private static InputStream getLoggingProperties() throws IOException {
+ ClassLoader classLoader = LoggingConfig.class.getClassLoader();
+ InputStream input = classLoader.getResourceAsStream("logging.properties");
+ if (input == null) {
+ Path javaHome = Paths.get(System.getProperty("java.home"));
+ input = Files.newInputStream(javaHome.resolve("lib").resolve("logging.properties"));
+ }
+ return input;
+ }
+
+}
diff --git a/tools/demobench/src/main/java/net/corda/demobench/pty/PtyProcessTtyConnector.java b/tools/demobench/src/main/java/net/corda/demobench/pty/PtyProcessTtyConnector.java
new file mode 100644
index 0000000000..3648f21480
--- /dev/null
+++ b/tools/demobench/src/main/java/net/corda/demobench/pty/PtyProcessTtyConnector.java
@@ -0,0 +1,42 @@
+package net.corda.demobench.pty;
+
+import com.jediterm.terminal.ProcessTtyConnector;
+import com.pty4j.PtyProcess;
+import com.pty4j.WinSize;
+
+import java.nio.charset.Charset;
+
+/**
+ * Copied from JediTerm pty.
+ * JediTerm is not available in any Maven repository.
+ * @author traff
+ */
+public class PtyProcessTtyConnector extends ProcessTtyConnector {
+ private final PtyProcess myProcess;
+ private final String name;
+
+ PtyProcessTtyConnector(String name, PtyProcess process, Charset charset) {
+ super(process, charset);
+ myProcess = process;
+ this.name = name;
+ }
+
+ @Override
+ protected void resizeImmediately() {
+ if (getPendingTermSize() != null && getPendingPixelSize() != null) {
+ myProcess.setWinSize(
+ new WinSize(getPendingTermSize().width, getPendingTermSize().height, getPendingPixelSize().width, getPendingPixelSize().height));
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ return myProcess.isRunning();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBench.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBench.kt
index 84b84da37a..b9447be9da 100644
--- a/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBench.kt
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBench.kt
@@ -1,6 +1,11 @@
package net.corda.demobench
+import javafx.scene.image.Image
+import net.corda.demobench.views.DemoBenchView
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
import tornadofx.App
+import tornadofx.addStageIcon
/**
* README!
@@ -32,6 +37,22 @@ import tornadofx.App
*/
class DemoBench : App(DemoBenchView::class) {
- init {
+
+ /*
+ * This entry point is needed by JavaPackager, as
+ * otherwise the packaged application cannot run.
+ */
+ companion object {
+ @JvmStatic
+ fun main(args: Array) = launch(DemoBench::class.java, *args)
}
-}
\ No newline at end of file
+
+ init {
+ addStageIcon(Image("cordalogo.png"))
+ }
+}
+
+/*
+ * Trivial utility function to create SLF4J Logger.
+ */
+inline fun loggerFor(): Logger = LoggerFactory.getLogger(T::class.java)
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBenchView.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBenchView.kt
deleted file mode 100644
index e81c5f706e..0000000000
--- a/tools/demobench/src/main/kotlin/net/corda/demobench/DemoBenchView.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.corda.demobench
-
-import javafx.scene.Parent
-import tornadofx.View
-import tornadofx.importStylesheet
-
-class DemoBenchView : View("Corda Demo Bench") {
- override val root: Parent by fxml()
-
- init {
- importStylesheet("/net/corda/demobench/style.css")
- }
-}
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/DBViewer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/DBViewer.kt
new file mode 100644
index 0000000000..6047cd5ec0
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/DBViewer.kt
@@ -0,0 +1,54 @@
+package net.corda.demobench.model
+
+import net.corda.demobench.loggerFor
+import org.h2.server.web.LocalWebServer
+import org.h2.tools.Server
+import org.h2.util.JdbcUtils
+import java.util.concurrent.Executors
+import kotlin.reflect.jvm.jvmName
+
+class DBViewer : AutoCloseable {
+ private companion object {
+ val log = loggerFor()
+ }
+
+ private val webServer: Server
+ private val pool = Executors.newCachedThreadPool()
+
+ init {
+ val ws = LocalWebServer()
+ webServer = Server(ws, "-webPort", "0")
+ ws.setShutdownHandler(webServer)
+
+ webServer.setShutdownHandler {
+ webServer.stop()
+ }
+
+ pool.submit {
+ webServer.start()
+ }
+ }
+
+ override fun close() {
+ log.info("Shutting down")
+ pool.shutdown()
+ webServer.shutdown()
+ }
+
+ fun openBrowser(h2Port: Int) {
+ val conn = JdbcUtils.getConnection(
+ org.h2.Driver::class.jvmName,
+ "jdbc:h2:tcp://localhost:$h2Port/node",
+ "sa",
+ ""
+ )
+
+ val url = (webServer.service as LocalWebServer).addSession(conn)
+ log.info("Session: {}", url)
+
+ pool.execute {
+ Server.openBrowser(url)
+ }
+ }
+
+}
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/Explorer.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/Explorer.kt
new file mode 100644
index 0000000000..8ba46f4e06
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/Explorer.kt
@@ -0,0 +1,64 @@
+package net.corda.demobench.model
+
+import net.corda.demobench.loggerFor
+import java.util.concurrent.Executors
+
+class Explorer(val explorerController: ExplorerController) : AutoCloseable {
+ private companion object {
+ val log = loggerFor()
+ }
+
+ private val executor = Executors.newSingleThreadExecutor()
+ private var process: Process? = null
+
+ fun open(config: NodeConfig, onExit: (NodeConfig) -> Unit) {
+ val explorerDir = config.explorerDir.toFile()
+
+ if (!explorerDir.isDirectory && !explorerDir.mkdirs()) {
+ log.warn("Failed to create working directory '{}'", explorerDir.absolutePath)
+ onExit(config)
+ return
+ }
+
+ val p = explorerController.process(
+ "--host=localhost",
+ "--port=${config.artemisPort}",
+ "--username=${config.users[0]["user"]}",
+ "--password=${config.users[0]["password"]}",
+ "--certificatesDir=${config.ssl.certificatesDirectory}",
+ "--keyStorePassword=${config.ssl.keyStorePassword}",
+ "--trustStorePassword=${config.ssl.trustStorePassword}")
+ .directory(explorerDir)
+ .start()
+ process = p
+
+ log.info("Launched Node Explorer for '{}'", config.legalName)
+
+ // Close these streams because no-one is using them.
+ safeClose(p.outputStream)
+ safeClose(p.inputStream)
+ safeClose(p.errorStream)
+
+ executor.submit {
+ val exitValue = p.waitFor()
+ process = null
+
+ log.info("Node Explorer for '{}' has exited (value={})", config.legalName, exitValue)
+ onExit(config)
+ }
+ }
+
+ override fun close() {
+ executor.shutdown()
+ process?.destroy()
+ }
+
+ private fun safeClose(c: AutoCloseable) {
+ try {
+ c.close()
+ } catch (e: Exception) {
+ log.error("Failed to close stream: '{}'", e.message)
+ }
+ }
+
+}
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt
new file mode 100644
index 0000000000..b0325be4b8
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/ExplorerController.kt
@@ -0,0 +1,18 @@
+package net.corda.demobench.model
+
+import tornadofx.Controller
+
+class ExplorerController : Controller() {
+
+ private val jvm by inject()
+ private val explorerPath = jvm.applicationDir.resolve("explorer").resolve("node-explorer.jar")
+
+ init {
+ log.info("Explorer JAR: $explorerPath")
+ }
+
+ internal fun process(vararg args: String) = jvm.processFor(explorerPath, *args)
+
+ fun explorer() = Explorer(this)
+
+}
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt
new file mode 100644
index 0000000000..4b2eb284db
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/JVMConfig.kt
@@ -0,0 +1,26 @@
+package net.corda.demobench.model
+
+import java.nio.file.Path
+import java.nio.file.Paths
+import tornadofx.Controller
+
+class JVMConfig : Controller() {
+
+ val userHome: Path = Paths.get(System.getProperty("user.home")).toAbsolutePath()
+ val javaPath: Path = Paths.get(System.getProperty("java.home"), "bin", "java")
+ val applicationDir: Path = Paths.get(System.getProperty("user.dir")).toAbsolutePath()
+
+ init {
+ log.info("Java executable: $javaPath")
+ }
+
+ fun commandFor(jarPath: Path, vararg args: String): Array {
+ return arrayOf(javaPath.toString(), "-jar", jarPath.toString(), *args)
+ }
+
+ fun processFor(jarPath: Path, vararg args: String): ProcessBuilder {
+ return ProcessBuilder(commandFor(jarPath, *args).toList())
+ }
+
+}
+
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt
new file mode 100644
index 0000000000..326b9fd60c
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NetworkMapConfig.kt
@@ -0,0 +1,12 @@
+package net.corda.demobench.model
+
+open class NetworkMapConfig(val legalName: String, val artemisPort: Int) {
+
+ private var keyValue = toKey(legalName)
+ val key: String get() = keyValue
+
+}
+
+private val WHITESPACE = "\\s++".toRegex()
+
+fun toKey(value: String) = value.replace(WHITESPACE, "").toLowerCase()
diff --git a/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt
new file mode 100644
index 0000000000..5a3b5b8654
--- /dev/null
+++ b/tools/demobench/src/main/kotlin/net/corda/demobench/model/NodeConfig.kt
@@ -0,0 +1,82 @@
+package net.corda.demobench.model
+
+import com.typesafe.config.*
+import java.lang.String.join
+import java.nio.file.Path
+import net.corda.node.services.config.SSLConfiguration
+
+class NodeConfig(
+ baseDir: Path,
+ legalName: String,
+ artemisPort: Int,
+ val nearestCity: String,
+ val webPort: Int,
+ val h2Port: Int,
+ val extraServices: List,
+ val users: List