Merge branch 'master' into clint-irsdemowindowsfix

This commit is contained in:
Clinton 2017-01-05 09:51:02 +00:00 committed by GitHub
commit f74fc67737
32 changed files with 397 additions and 290 deletions

View File

@ -6,17 +6,29 @@ buildscript {
// Our version: bump this on release. // Our version: bump this on release.
ext.corda_version = "0.7-SNAPSHOT" ext.corda_version = "0.7-SNAPSHOT"
ext.gradle_plugins_version = props.getProperty("gradlePluginsVersion") ext.gradle_plugins_version = props.getProperty("gradlePluginsVersion")
// Dependency versions. Can run 'gradle dependencyUpdates' to find new versions of things.
//
// TODO: Sort this alphabetically.
ext.kotlin_version = '1.0.5-2' ext.kotlin_version = '1.0.5-2'
ext.quasar_version = '0.7.6' ext.quasar_version = '0.7.6' // TODO: Upgrade to 0.7.7+ when Quasar bug 238 is resolved.
ext.asm_version = '0.5.3' ext.asm_version = '0.5.3'
ext.artemis_version = '1.4.0' ext.artemis_version = '1.5.1'
ext.jackson_version = '2.8.0.rc2' ext.jackson_version = '2.8.5'
ext.jetty_version = '9.3.9.v20160517' ext.jetty_version = '9.3.9.v20160517'
ext.jersey_version = '2.23.1' ext.jersey_version = '2.25'
ext.jolokia_version = '2.0.0-M1' ext.jolokia_version = '2.0.0-M3'
ext.assertj_version = '3.5.1' ext.assertj_version = '3.6.1'
ext.log4j_version = '2.6.2' ext.log4j_version = '2.7'
ext.bouncycastle_version = '1.54' ext.bouncycastle_version = '1.56'
ext.guava_version = '19.0'
ext.quickcheck_version = '0.7'
ext.okhttp_version = '3.5.0'
ext.typesafe_config_version = '1.3.1'
ext.junit_version = '4.12'
ext.jopt_simple_version = '5.0.2'
ext.jansi_version = '1.14'
ext.hibernate_version = '5.2.6.Final'
repositories { repositories {
mavenLocal() mavenLocal()
@ -33,9 +45,7 @@ buildscript {
classpath "net.corda.plugins:publish-utils:$gradle_plugins_version" classpath "net.corda.plugins:publish-utils:$gradle_plugins_version"
classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version" classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version"
classpath "net.corda.plugins:cordformation:$gradle_plugins_version" classpath "net.corda.plugins:cordformation:$gradle_plugins_version"
classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0'
// Can run 'gradle dependencyUpdates' to find new versions of things.
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
} }
} }
@ -95,7 +105,7 @@ repositories {
// Required for building out the fat JAR. // Required for building out the fat JAR.
dependencies { dependencies {
compile project(':node') compile project(':node')
compile "com.google.guava:guava:19.0" compile "com.google.guava:guava:$guava_version"
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
} }
@ -177,4 +187,4 @@ bintrayConfig {
name = 'R3' name = 'R3'
email = 'dev@corda.net' email = 'dev@corda.net'
} }
} }

View File

@ -5,5 +5,6 @@ repositories {
} }
dependencies { dependencies {
compile "com.google.guava:guava:19.0" // Cannot use ext.guava_version here :(
compile "com.google.guava:guava:20.0"
} }

View File

@ -51,7 +51,7 @@ dependencies {
compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
compile "org.apache.logging.log4j:log4j-core:${log4j_version}" compile "org.apache.logging.log4j:log4j-core:${log4j_version}"
compile "com.google.guava:guava:19.0" compile "com.google.guava:guava:$guava_version"
// ReactFX: Functional reactive UI programming. // ReactFX: Functional reactive UI programming.
compile 'org.reactfx:reactfx:2.0-M5' compile 'org.reactfx:reactfx:2.0-M5'
@ -61,16 +61,16 @@ dependencies {
compile "org.apache.activemq:artemis-core-client:${artemis_version}" compile "org.apache.activemq:artemis-core-client:${artemis_version}"
// Unit testing helpers. // Unit testing helpers.
testCompile 'junit:junit:4.12' testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}" testCompile "org.assertj:assertj-core:${assertj_version}"
testCompile project(':test-utils') testCompile project(':test-utils')
// Integration test helpers // Integration test helpers
integrationTestCompile 'junit:junit:4.12' integrationTestCompile "junit:junit:$junit_version"
} }
task integrationTest(type: Test) { task integrationTest(type: Test) {
testClassesDir = sourceSets.integrationTest.output.classesDir testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath classpath = sourceSets.integrationTest.runtimeClasspath
} }

View File

@ -31,11 +31,11 @@ sourceSets {
} }
dependencies { dependencies {
testCompile 'junit:junit:4.12' testCompile "junit:junit:$junit_version"
testCompile "commons-fileupload:commons-fileupload:1.3.2" testCompile "commons-fileupload:commons-fileupload:1.3.2"
// Guava: Google test library (collections test suite) // Guava: Google test library (collections test suite)
testCompile "com.google.guava:guava-testlib:19.0" testCompile "com.google.guava:guava-testlib:$guava_version"
// Bring in the MockNode infrastructure for writing protocol unit tests. // Bring in the MockNode infrastructure for writing protocol unit tests.
testCompile project(":node") testCompile project(":node")
@ -43,7 +43,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.2" compile "org.jetbrains.kotlinx:kotlinx-support-jdk8:0.3"
compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
// Thread safety annotations // Thread safety annotations
@ -56,18 +56,19 @@ dependencies {
// AssertJ: for fluent assertions for testing // AssertJ: for fluent assertions for testing
testCompile "org.assertj:assertj-core:${assertj_version}" testCompile "org.assertj:assertj-core:${assertj_version}"
compile 'com.pholser:junit-quickcheck-core:0.6' compile "com.pholser:junit-quickcheck-core:$quickcheck_version"
compile 'com.pholser:junit-quickcheck-generators:0.6' compile "com.pholser:junit-quickcheck-generators:$quickcheck_version"
// Guava: Google utilities library. // Guava: Google utilities library.
compile "com.google.guava:guava:19.0" compile "com.google.guava:guava:$guava_version"
// RxJava: observable streams of events. // RxJava: observable streams of events.
// TODO: We can't upgrade past 1.1.6 due to a behaviour change in RxJava breaking our code. See PR #99 for discussion. Resolve.
compile "io.reactivex:rxjava:1.1.6" compile "io.reactivex:rxjava:1.1.6"
// Kryo: object graph serialization. // Kryo: object graph serialization.
compile "com.esotericsoftware:kryo:4.0.0" compile "com.esotericsoftware:kryo:4.0.0"
compile "de.javakaffee:kryo-serializers:0.38" compile "de.javakaffee:kryo-serializers:0.41"
// Apache JEXL: An embeddable expression evaluation library. // Apache JEXL: An embeddable expression evaluation library.
// This may be temporary until we experiment with other ways to do on-the-fly contract specialisation via an API. // This may be temporary until we experiment with other ways to do on-the-fly contract specialisation via an API.
@ -88,4 +89,4 @@ dependencies {
// RS API: Response type and codes for ApiUtils. // RS API: Response type and codes for ApiUtils.
compile "javax.ws.rs:javax.ws.rs-api:2.0" compile "javax.ws.rs:javax.ws.rs-api:2.0"
} }

View File

@ -5,7 +5,7 @@ package net.corda.core.utilities
*/ */
object Emoji { object Emoji {
// Unfortunately only Apple has a terminal that can do colour emoji AND an emoji font installed by default. // Unfortunately only Apple has a terminal that can do colour emoji AND an emoji font installed by default.
val hasEmojiTerminal by lazy { System.getenv("TERM_PROGRAM") == "Apple_Terminal" } val hasEmojiTerminal by lazy { listOf("Apple_Terminal", "iTerm.app").contains(System.getenv("TERM_PROGRAM")) }
const val CODE_SANTA_CLAUS = "\ud83c\udf85" const val CODE_SANTA_CLAUS = "\ud83c\udf85"
const val CODE_DIAMOND = "\ud83d\udd37" const val CODE_DIAMOND = "\ud83d\udd37"

View File

@ -98,4 +98,4 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
'permissions' : ["StartFlow.net.corda.flows.CashFlow"]] 'permissions' : ["StartFlow.net.corda.flows.CashFlow"]]
] ]
} }
} }

View File

@ -28,6 +28,6 @@ dependencies {
compile project(':core') compile project(':core')
compile project(':finance') compile project(':finance')
testCompile 'junit:junit:4.12' testCompile "junit:junit:$junit_version"
testCompile project(':test-utils') testCompile project(':test-utils')
} }

View File

@ -22,10 +22,10 @@ dependencies {
compile "org.ow2.asm:asm-commons:$asm_version" compile "org.ow2.asm:asm-commons:$asm_version"
// JOptSimple: command line option parsing // JOptSimple: command line option parsing
compile "net.sf.jopt-simple:jopt-simple:5.0.1" compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
// Simple Logging Facade: makes the code independent of the chosen logging framework. // Simple Logging Facade: makes the code independent of the chosen logging framework.
compile "org.slf4j:slf4j-api:1.7.21" compile "org.slf4j:slf4j-api:1.7.21"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
} }

View File

@ -21,7 +21,7 @@ dependencies {
compile project(':core') compile project(':core')
testCompile project(':test-utils') testCompile project(':test-utils')
testCompile 'junit:junit:4.12' testCompile "junit:junit:$junit_version"
} }
sourceSets { sourceSets {
@ -30,4 +30,4 @@ sourceSets {
srcDir "../config/test" srcDir "../config/test"
} }
} }
} }

View File

@ -16,7 +16,7 @@ buildscript {
dependencies { dependencies {
classpath "net.corda.plugins:publish-utils:$gradle_plugins_version" classpath "net.corda.plugins:publish-utils:$gradle_plugins_version"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
} }
} }
@ -48,4 +48,4 @@ bintrayConfig {
name = 'R3' name = 'R3'
email = 'dev@corda.net' email = 'dev@corda.net'
} }
} }

View File

@ -11,6 +11,7 @@ dependencies {
compile gradleApi() compile gradleApi()
compile localGroovy() compile localGroovy()
compile "com.typesafe:config:1.3.0" // TypeSafe Config: for simple and human friendly config files.
compile "com.typesafe:config:$typesafe_config_version"
} }

View File

@ -11,4 +11,4 @@ repositories {
dependencies { dependencies {
compile gradleApi() compile gradleApi()
compile localGroovy() compile localGroovy()
} }

View File

@ -66,10 +66,10 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
compile "com.google.guava:guava:19.0" compile "com.google.guava:guava:$guava_version"
// JOpt: for command line flags. // JOpt: for command line flags.
compile "net.sf.jopt-simple:jopt-simple:5.0.2" compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
// Artemis: for reliable p2p message queues. // Artemis: for reliable p2p message queues.
compile "org.apache.activemq:artemis-server:${artemis_version}" compile "org.apache.activemq:artemis-server:${artemis_version}"
@ -77,7 +77,7 @@ dependencies {
runtime "org.apache.activemq:artemis-amqp-protocol:${artemis_version}" runtime "org.apache.activemq:artemis-amqp-protocol:${artemis_version}"
// JAnsi: for drawing things to the terminal in nicely coloured ways. // JAnsi: for drawing things to the terminal in nicely coloured ways.
compile "org.fusesource.jansi:jansi:1.13" compile "org.fusesource.jansi:jansi:$jansi_version"
// GraphStream: For visualisation // GraphStream: For visualisation
testCompile "org.graphstream:gs-core:1.3" testCompile "org.graphstream:gs-core:1.3"
@ -95,7 +95,7 @@ dependencies {
compile "org.eclipse.jetty:jetty-servlet:${jetty_version}" compile "org.eclipse.jetty:jetty-servlet:${jetty_version}"
compile "org.eclipse.jetty:jetty-webapp:${jetty_version}" compile "org.eclipse.jetty:jetty-webapp:${jetty_version}"
compile "javax.servlet:javax.servlet-api:3.1.0" compile "javax.servlet:javax.servlet-api:3.1.0"
compile "org.jolokia:jolokia-agent-war:2.0.0-M1" compile "org.jolokia:jolokia-agent-war:$jolokia_version"
compile "commons-fileupload:commons-fileupload:1.3.2" compile "commons-fileupload:commons-fileupload:1.3.2"
// Jersey for JAX-RS implementation for use in Jetty // Jersey for JAX-RS implementation for use in Jetty
@ -121,26 +121,27 @@ dependencies {
compile "com.google.jimfs:jimfs:1.1" compile "com.google.jimfs:jimfs:1.1"
// TypeSafe Config: for simple and human friendly config files. // TypeSafe Config: for simple and human friendly config files.
compile "com.typesafe:config:1.3.0" compile "com.typesafe:config:$typesafe_config_version"
// Unit testing helpers. // Unit testing helpers.
testCompile 'junit:junit:4.12' testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}" testCompile "org.assertj:assertj-core:${assertj_version}"
testCompile 'com.pholser:junit-quickcheck-core:0.6' testCompile "com.pholser:junit-quickcheck-core:$quickcheck_version"
// For H2 database support in persistence // For H2 database support in persistence
compile "com.h2database:h2:1.4.192" compile "com.h2database:h2:1.4.193"
// Exposed: Kotlin SQL library - under evaluation // Exposed: Kotlin SQL library - under evaluation
// TODO: Upgrade to Exposed 0.7 (has API changes)
compile "org.jetbrains.exposed:exposed:0.5.0" compile "org.jetbrains.exposed:exposed:0.5.0"
// SQL connection pooling library // SQL connection pooling library
compile "com.zaxxer:HikariCP:2.4.7" compile "com.zaxxer:HikariCP:2.5.1"
// Hibernate: an object relational mapper for writing state objects to the database automatically. // Hibernate: an object relational mapper for writing state objects to the database automatically.
compile "org.hibernate:hibernate-core:5.2.2.Final" compile "org.hibernate:hibernate-core:$hibernate_version"
compile "org.hibernate:hibernate-java8:5.2.2.Final" compile "org.hibernate:hibernate-java8:$hibernate_version"
// Capsule is a library for building independently executable fat JARs. // Capsule is a library for building independently executable fat JARs.
compile 'co.paralleluniverse:capsule:1.0.3' compile 'co.paralleluniverse:capsule:1.0.3'
@ -151,12 +152,12 @@ dependencies {
compile 'io.atomix.catalyst:catalyst-netty:1.1.1' compile 'io.atomix.catalyst:catalyst-netty:1.1.1'
// Integration test helpers // Integration test helpers
integrationTestCompile 'junit:junit:4.12' integrationTestCompile "junit:junit:$junit_version"
testCompile "com.nhaarman:mockito-kotlin:0.6.1" testCompile "com.nhaarman:mockito-kotlin:1.1.0"
} }
task integrationTest(type: Test) { task integrationTest(type: Test) {
testClassesDir = sourceSets.integrationTest.output.classesDir testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath classpath = sourceSets.integrationTest.runtimeClasspath
} }

View File

@ -80,4 +80,4 @@ artifacts {
publish { publish {
name = 'corda' name = 'corda'
disableDefaultJar = true disableDefaultJar = true
} }

View File

@ -25,49 +25,53 @@ import java.time.LocalDateTime
* the java.time API, some core types, and Kotlin data classes. * the java.time API, some core types, and Kotlin data classes.
*/ */
object JsonSupport { object JsonSupport {
val javaTimeModule : Module by lazy {
fun createDefaultMapper(identities: IdentityService): ObjectMapper { SimpleModule("java.time").apply {
val mapper = ServiceHubObjectMapper(identities) addSerializer(LocalDate::class.java, ToStringSerializer)
mapper.enable(SerializationFeature.INDENT_OUTPUT) addDeserializer(LocalDate::class.java, LocalDateDeserializer)
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) addKeyDeserializer(LocalDate::class.java, LocalDateKeyDeserializer)
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) addSerializer(LocalDateTime::class.java, ToStringSerializer)
}
val timeModule = SimpleModule("java.time")
timeModule.addSerializer(LocalDate::class.java, ToStringSerializer)
timeModule.addDeserializer(LocalDate::class.java, LocalDateDeserializer)
timeModule.addKeyDeserializer(LocalDate::class.java, LocalDateKeyDeserializer)
timeModule.addSerializer(LocalDateTime::class.java, ToStringSerializer)
val cordaModule = SimpleModule("core")
cordaModule.addSerializer(Party::class.java, PartySerializer)
cordaModule.addDeserializer(Party::class.java, PartyDeserializer)
cordaModule.addSerializer(BigDecimal::class.java, ToStringSerializer)
cordaModule.addDeserializer(BigDecimal::class.java, NumberDeserializers.BigDecimalDeserializer())
cordaModule.addSerializer(SecureHash::class.java, SecureHashSerializer)
// It's slightly remarkable, but apparently Jackson works out that this is the only possibility
// for a SecureHash at the moment and tries to use SHA256 directly even though we only give it SecureHash
cordaModule.addDeserializer(SecureHash.SHA256::class.java, SecureHashDeserializer())
cordaModule.addDeserializer(BusinessCalendar::class.java, CalendarDeserializer)
// For ed25519 pubkeys
cordaModule.addSerializer(EdDSAPublicKey::class.java, PublicKeySerializer)
cordaModule.addDeserializer(EdDSAPublicKey::class.java, PublicKeyDeserializer)
// For composite keys
cordaModule.addSerializer(CompositeKey::class.java, CompositeKeySerializer)
cordaModule.addDeserializer(CompositeKey::class.java, CompositeKeyDeserializer)
// For NodeInfo
// TODO this tunnels the Kryo representation as a Base58 encoded string. Replace when RPC supports this.
cordaModule.addSerializer(NodeInfo::class.java, NodeInfoSerializer)
cordaModule.addDeserializer(NodeInfo::class.java, NodeInfoDeserializer)
mapper.registerModule(timeModule)
mapper.registerModule(cordaModule)
mapper.registerModule(KotlinModule())
return mapper
} }
val cordaModule : Module by lazy {
SimpleModule("core").apply {
addSerializer(Party::class.java, PartySerializer)
addDeserializer(Party::class.java, PartyDeserializer)
addSerializer(BigDecimal::class.java, ToStringSerializer)
addDeserializer(BigDecimal::class.java, NumberDeserializers.BigDecimalDeserializer())
addSerializer(SecureHash::class.java, SecureHashSerializer)
// It's slightly remarkable, but apparently Jackson works out that this is the only possibility
// for a SecureHash at the moment and tries to use SHA256 directly even though we only give it SecureHash
addDeserializer(SecureHash.SHA256::class.java, SecureHashDeserializer())
addDeserializer(BusinessCalendar::class.java, CalendarDeserializer)
// For ed25519 pubkeys
addSerializer(EdDSAPublicKey::class.java, PublicKeySerializer)
addDeserializer(EdDSAPublicKey::class.java, PublicKeyDeserializer)
// For composite keys
addSerializer(CompositeKey::class.java, CompositeKeySerializer)
addDeserializer(CompositeKey::class.java, CompositeKeyDeserializer)
// For NodeInfo
// TODO this tunnels the Kryo representation as a Base58 encoded string. Replace when RPC supports this.
addSerializer(NodeInfo::class.java, NodeInfoSerializer)
addDeserializer(NodeInfo::class.java, NodeInfoDeserializer)
}
}
fun createDefaultMapper(identities: IdentityService): ObjectMapper =
ServiceHubObjectMapper(identities).apply {
enable(SerializationFeature.INDENT_OUTPUT)
enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
registerModule(javaTimeModule)
registerModule(cordaModule)
registerModule(KotlinModule())
}
class ServiceHubObjectMapper(val identities: IdentityService) : ObjectMapper() class ServiceHubObjectMapper(val identities: IdentityService) : ObjectMapper()
object ToStringSerializer : JsonSerializer<Any>() { object ToStringSerializer : JsonSerializer<Any>() {

View File

@ -42,7 +42,7 @@ configurations {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -127,4 +127,4 @@ task runRecipient(type: JavaExec) {
main = 'net.corda.attachmentdemo.AttachmentDemoKt' main = 'net.corda.attachmentdemo.AttachmentDemoKt'
args '--role' args '--role'
args 'RECIPIENT' args 'RECIPIENT'
} }

View File

@ -42,7 +42,7 @@ configurations {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -146,4 +146,4 @@ task runWebCashIssue(type: JavaExec) {
args 30000 args 30000
args '--currency' args '--currency'
args 'GBP' args 'GBP'
} }

View File

@ -45,7 +45,7 @@ configurations {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -58,7 +58,7 @@ dependencies {
// Cordapp dependencies // Cordapp dependencies
// Specify your cordapp's dependencies below, including dependent cordapps // Specify your cordapp's dependencies below, including dependent cordapps
compile 'com.squareup.okhttp3:okhttp:3.3.1' compile "com.squareup.okhttp3:okhttp:$okhttp_version"
} }
task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) { task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
@ -129,4 +129,4 @@ publishing {
artifact javadocJar artifact javadocJar
} }
} }
} }

View File

@ -32,7 +32,7 @@ class IRSDemoTest: IntegrationTestCategory {
private fun runDateChange(nodeAddr: HostAndPort) { private fun runDateChange(nodeAddr: HostAndPort) {
val url = URL("http://$nodeAddr/api/irs/demodate") val url = URL("http://$nodeAddr/api/irs/demodate")
assert(putJson(url, "\"2017-01-02\"")) assert(putJson(url, "\"2017-06-05\""))
} }
private fun runTrade(nodeAddr: HostAndPort) { private fun runTrade(nodeAddr: HostAndPort) {

View File

@ -18,7 +18,7 @@ dependencies {
compile project(':samples:irs-demo') compile project(':samples:irs-demo')
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -52,4 +52,4 @@ task deployVisualiser(type: FatCapsule) {
minJavaVersion = '1.8.0' minJavaVersion = '1.8.0'
javaAgents = [configurations.quasar.singleFile.name] javaAgents = [configurations.quasar.singleFile.name]
} }
} }

View File

@ -42,7 +42,7 @@ configurations {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')

View File

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.strata_version = '1.0.0' ext.strata_version = '1.1.2'
} }
apply plugin: 'java' apply plugin: 'java'
@ -34,11 +34,23 @@ sourceSets {
srcDir "../../config/test" srcDir "../../config/test"
} }
} }
integrationTest {
kotlin {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
}
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
} }
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -105,6 +117,10 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['build']) {
} }
} }
task integrationTest(type: Test, dependsOn: []) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
task npmInstall(type: Exec) { task npmInstall(type: Exec) {
workingDir 'src/main/web' workingDir 'src/main/web'

View File

@ -0,0 +1,78 @@
package net.corda.vega
import com.opengamma.strata.product.common.BuySell
import net.corda.core.getOrThrow
import net.corda.core.node.services.ServiceInfo
import net.corda.node.driver.NodeHandle
import net.corda.node.driver.driver
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.testing.IntegrationTestCategory
import net.corda.testing.getHostAndPort
import net.corda.testing.http.HttpApi
import net.corda.vega.api.PortfolioApi
import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.api.SwapDataView
import net.corda.vega.portfolio.Portfolio
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
import java.util.*
import java.util.concurrent.Future
class SimmValuationTest: IntegrationTestCategory {
private companion object {
// SIMM demo can only currently handle one valuation date due to a lack of market data or a market data source.
val valuationDate = LocalDate.parse("2016-06-06")
val nodeALegalName = "Bank A"
val nodeBLegalName = "Bank B"
val testTradeId = "trade1"
}
@Test fun `runs SIMM valuation demo`() {
driver(isDebug = true) {
startNode("Controller", setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
val nodeA = getSimmNodeApi(startNode(nodeALegalName))
val nodeB = getSimmNodeApi(startNode(nodeBLegalName))
val nodeBParty = getPartyWithName(nodeA, nodeBLegalName)
val nodeAParty = getPartyWithName(nodeB, nodeALegalName)
assert(createTradeBetween(nodeA, nodeBParty, testTradeId))
assert(tradeExists(nodeB, nodeAParty, testTradeId))
assert(runValuationsBetween(nodeA, nodeBParty))
assert(valuationExists(nodeB, nodeAParty))
}
}
private fun getSimmNodeApi(futureNode: Future<NodeHandle>): HttpApi {
val nodeAddr = futureNode.getOrThrow().config.getHostAndPort("webAddress")
return HttpApi.fromHostAndPort(nodeAddr, "api/simmvaluationdemo")
}
private fun getPartyWithName(partyApi: HttpApi, countryparty: String): PortfolioApi.ApiParty =
getAvailablePartiesFor(partyApi).counterparties.single { it.text == countryparty }
private fun getAvailablePartiesFor(partyApi: HttpApi): PortfolioApi.AvailableParties {
return partyApi.getJson<PortfolioApi.AvailableParties>("whoami")
}
private fun createTradeBetween(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String): Boolean {
val trade = SwapDataModel(tradeId, "desc", valuationDate, "EUR_FIXED_1Y_EURIBOR_3M",
valuationDate, LocalDate.parse("2020-01-02"), BuySell.BUY, BigDecimal.valueOf(1000), BigDecimal.valueOf(0.1))
return partyApi.putJson("${counterparty.id}/trades", trade)
}
private fun tradeExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String): Boolean {
val trades = partyApi.getJson<Array<SwapDataView>>("${counterparty.id}/trades")
return (trades.find { it.id == tradeId } != null)
}
private fun runValuationsBetween(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
return partyApi.postJson("${counterparty.id}/portfolio/valuations/calculate", PortfolioApi.ValuationCreationParams(valuationDate))
}
private fun valuationExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
val valuations = partyApi.getJson<PortfolioApiUtils.ValuationsView>("${counterparty.id}/portfolio/valuations")
return (valuations.initialMargin.call["total"] != 0.0)
}
}

View File

@ -1,20 +0,0 @@
package net.corda.vega.api
/**
* A small JSON DSL to create structures for APIs on the fly that mimic JSON in structure.
* Use: json { obj("a" to 100, "b" to "hello", "c" to arr(1, 2, "c")) }
*/
class JsonBuilder {
fun obj(vararg objs: Pair<String, Any>): Map<String, Any> {
return objs.toMap()
}
fun arr(vararg objs: Any): List<Any> {
return objs.toList()
}
}
fun json(body: JsonBuilder.() -> Map<String, Any>): Map<String, Any> {
val jsonWrapper = JsonBuilder()
return jsonWrapper.body()
}

View File

@ -98,11 +98,9 @@ class PortfolioApi(val rpc: CordaRPCOps) {
@Path("business-date") @Path("business-date")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
fun getBusinessDate(): Any { fun getBusinessDate(): Any {
return json { return mapOf(
obj( "business-date" to LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate()
"business-date" to LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate() )
)
}
} }
/** /**
@ -195,12 +193,10 @@ class PortfolioApi(val rpc: CordaRPCOps) {
return withParty(partyName) { party -> return withParty(partyName) { party ->
val trades = getTradesWith(party) val trades = getTradesWith(party)
val portfolio = Portfolio(trades) val portfolio = Portfolio(trades)
val summary = json { val summary = mapOf(
obj( "trades" to portfolio.trades.size,
"trades" to portfolio.trades.size, "notional" to portfolio.getNotionalForParty(ownParty).toDouble()
"notional" to portfolio.getNotionalForParty(ownParty).toDouble() )
)
}
Response.ok().entity(summary).build() Response.ok().entity(summary).build()
} }
} }
@ -239,28 +235,23 @@ class PortfolioApi(val rpc: CordaRPCOps) {
} }
} }
data class ApiParty(val id: String, val text: String)
data class AvailableParties(val self: ApiParty, val counterparties: List<ApiParty>)
/** /**
* Returns the identity of the current node as well as a list of other counterparties that it is aware of. * Returns the identity of the current node as well as a list of other counterparties that it is aware of.
*/ */
@GET @GET
@Path("whoami") @Path("whoami")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
fun getWhoAmI(): Any { fun getWhoAmI(): AvailableParties {
val counterParties = rpc.networkMapUpdates().first.filter { it.legalIdentity.name != "NetworkMapService" && it.legalIdentity.name != "Notary" && it.legalIdentity.name != ownParty.name } val counterParties = rpc.networkMapUpdates().first.filter {
return json { it.legalIdentity.name != "NetworkMapService" && it.legalIdentity.name != "Notary" && it.legalIdentity.name != ownParty.name
obj(
"self" to obj(
"id" to ownParty.owningKey.toBase58String(),
"text" to ownParty.name
),
"counterparties" to counterParties.map {
obj(
"id" to it.legalIdentity.owningKey.toBase58String(),
"text" to it.legalIdentity.name
)
}
)
} }
return AvailableParties(
self = ApiParty(ownParty.owningKey.toBase58String(), ownParty.name),
counterparties = counterParties.map { ApiParty(it.legalIdentity.owningKey.toBase58String(), it.legalIdentity.name) })
} }
data class ValuationCreationParams(val valuationDate: LocalDate) data class ValuationCreationParams(val valuationDate: LocalDate)

View File

@ -15,7 +15,16 @@ import java.time.LocalDate
* API JSON generation functions for larger JSON outputs. * API JSON generation functions for larger JSON outputs.
*/ */
class PortfolioApiUtils(private val ownParty: Party) { class PortfolioApiUtils(private val ownParty: Party) {
fun createValuations(state: PortfolioState, portfolio: Portfolio): Any { data class InitialMarginView(val baseCurrency: String, val post: Map<String, Double>, val call: Map<String, Double>, val agreed: Boolean)
data class ValuationsView(
val businessDate: LocalDate,
val portfolio: Map<String, Any>,
val marketData: Map<String, Any>,
val sensitivities: Map<String, Any>,
val initialMargin: InitialMarginView,
val confirmation: Map<String, Any>)
fun createValuations(state: PortfolioState, portfolio: Portfolio): ValuationsView {
val valuation = state.valuation!! val valuation = state.valuation!!
val currency = if (portfolio.trades.isNotEmpty()) { val currency = if (portfolio.trades.isNotEmpty()) {
@ -32,141 +41,137 @@ class PortfolioApiUtils(private val ownParty: Party) {
val completeSubgroups = subgroups.mapValues { it.value.mapValues { it.value[0].third.toDouble() }.toSortedMap() } val completeSubgroups = subgroups.mapValues { it.value.mapValues { it.value[0].third.toDouble() }.toSortedMap() }
val yieldCurves = json { val yieldCurves = mapOf(
obj( "name" to "EUR",
"name" to "EUR", "values" to completeSubgroups.get("EUR")!!.filter { !it.key.contains("Fixing") }.map {
"values" to completeSubgroups.get("EUR")!!.filter { !it.key.contains("Fixing") }.map { mapOf(
json { "tenor" to it.key,
obj( "rate" to it.value
"tenor" to it.key, )
"rate" to it.value }
) )
}
} val fixings = mapOf(
) "name" to "EUR",
} "values" to completeSubgroups.get("EUR")!!.filter { it.key.contains("Fixing") }.map {
val fixings = json { mapOf(
obj( "tenor" to it.key,
"name" to "EUR", "rate" to it.value
"values" to completeSubgroups.get("EUR")!!.filter { it.key.contains("Fixing") }.map { )
json { }
obj( )
"tenor" to it.key,
"rate" to it.value
)
}
}
)
}
val processedSensitivities = valuation.totalSensivities.sensitivities.map { it.marketDataName to it.parameterMetadata.map { it.label }.zip(it.sensitivity.toList()).toMap() }.toMap() val processedSensitivities = valuation.totalSensivities.sensitivities.map { it.marketDataName to it.parameterMetadata.map { it.label }.zip(it.sensitivity.toList()).toMap() }.toMap()
return json { val initialMarginView = InitialMarginView(
obj( baseCurrency = currency,
"businessDate" to LocalDate.now(), post = mapOf(
"portfolio" to obj( "IRFX" to valuation.margin.first,
"trades" to tradeCount, "commodity" to 0.0,
"baseCurrency" to currency, "equity" to 0.0,
"IRFX" to tradeCount, "credit" to 0.0,
"commodity" to 0, "total" to valuation.margin.first
"equity" to 0, ),
"credit" to 0, call = mapOf(
"total" to tradeCount, "IRFX" to valuation.margin.first,
"agreed" to true "commodity" to 0.0,
), "equity" to 0.0,
"marketData" to obj( "credit" to 0.0,
"yieldCurves" to yieldCurves, "total" to valuation.margin.first
"fixings" to fixings, ),
"agreed" to true agreed = true)
),
"sensitivities" to obj("curves" to processedSensitivities, return ValuationsView(
"currency" to valuation.currencySensitivies.amounts.toList().map { businessDate = LocalDate.now(),
obj( portfolio = mapOf(
"currency" to it.currency.code, "trades" to tradeCount,
"amount" to it.amount "baseCurrency" to currency,
) "IRFX" to tradeCount,
}, "commodity" to 0,
"agreed" to true "equity" to 0,
), "credit" to 0,
"initialMargin" to obj( "total" to tradeCount,
"baseCurrency" to currency, "agreed" to true
"post" to obj( ),
"IRFX" to valuation.margin.first, marketData = mapOf(
"commodity" to 0, "yieldCurves" to yieldCurves,
"equity" to 0, "fixings" to fixings,
"credit" to 0, "agreed" to true
"total" to valuation.margin.first ),
), sensitivities = mapOf("curves" to processedSensitivities,
"call" to obj( "currency" to valuation.currencySensitivies.amounts.toList().map {
"IRFX" to valuation.margin.first, mapOf(
"commodity" to 0, "currency" to it.currency.code,
"equity" to 0, "amount" to it.amount
"credit" to 0, )
"total" to valuation.margin.first },
), "agreed" to true
"agreed" to true ),
), initialMargin = initialMarginView,
"confirmation" to obj( confirmation = mapOf(
"hash" to state.hash().toString(), "hash" to state.hash().toString(),
"agreed" to true "agreed" to true
) )
) )
}
} }
fun createTradeView(state: IRSState): Any { data class TradeView(
val fixedLeg: Map<String, Any>,
val floatingLeg: Map<String, Any>,
val common: Map<String, Any>,
val ref: String)
fun createTradeView(state: IRSState): TradeView {
val trade = if (state.buyer.name == ownParty.name) state.swap.toFloatingLeg() else state.swap.toFloatingLeg() val trade = if (state.buyer.name == ownParty.name) state.swap.toFloatingLeg() else state.swap.toFloatingLeg()
val fixedLeg = trade.product.legs.first { it.type == SwapLegType.FIXED } as RateCalculationSwapLeg val fixedLeg = trade.product.legs.first { it.type == SwapLegType.FIXED } as RateCalculationSwapLeg
val floatingLeg = trade.product.legs.first { it.type != SwapLegType.FIXED } as RateCalculationSwapLeg val floatingLeg = trade.product.legs.first { it.type != SwapLegType.FIXED } as RateCalculationSwapLeg
val fixedRate = fixedLeg.calculation as FixedRateCalculation val fixedRate = fixedLeg.calculation as FixedRateCalculation
val floatingRate = floatingLeg.calculation as IborRateCalculation val floatingRate = floatingLeg.calculation as IborRateCalculation
return json { return TradeView(
obj( fixedLeg = mapOf(
"fixedLeg" to obj( "fixedRatePayer" to state.buyer.name,
"fixedRatePayer" to state.buyer.name, "notional" to mapOf(
"notional" to obj( "token" to fixedLeg.currency.code,
"token" to fixedLeg.currency.code, "quantity" to fixedLeg.notionalSchedule.amount.initialValue
"quantity" to fixedLeg.notionalSchedule.amount.initialValue ),
), "paymentFrequency" to fixedLeg.paymentSchedule.paymentFrequency.toString(),
"paymentFrequency" to fixedLeg.paymentSchedule.paymentFrequency.toString(), "effectiveDate" to fixedLeg.startDate.unadjusted,
"effectiveDate" to fixedLeg.startDate.unadjusted, "terminationDate" to fixedLeg.endDate.unadjusted,
"terminationDate" to fixedLeg.endDate.unadjusted, "fixedRate" to mapOf(
"fixedRate" to obj( "value" to fixedRate.rate.initialValue
"value" to fixedRate.rate.initialValue ),
), "paymentRule" to fixedLeg.paymentSchedule.paymentRelativeTo.name,
"paymentRule" to fixedLeg.paymentSchedule.paymentRelativeTo.name, "calendar" to listOf("TODO"),
"calendar" to arr("TODO"), "paymentCalendar" to mapOf<String, Any>() // TODO
"paymentCalendar" to obj() // TODO ),
), floatingLeg = mapOf(
"floatingLeg" to obj( "floatingRatePayer" to state.seller.name,
"floatingRatePayer" to state.seller.name, "notional" to mapOf(
"notional" to obj( "token" to floatingLeg.currency.code,
"token" to floatingLeg.currency.code, "quantity" to floatingLeg.notionalSchedule.amount.initialValue
"quantity" to floatingLeg.notionalSchedule.amount.initialValue ),
), "paymentFrequency" to floatingLeg.paymentSchedule.paymentFrequency.toString(),
"paymentFrequency" to floatingLeg.paymentSchedule.paymentFrequency.toString(), "effectiveDate" to floatingLeg.startDate.unadjusted,
"effectiveDate" to floatingLeg.startDate.unadjusted, "terminationDate" to floatingLeg.endDate.unadjusted,
"terminationDate" to floatingLeg.endDate.unadjusted, "index" to floatingRate.index.name,
"index" to floatingRate.index.name, "paymentRule" to floatingLeg.paymentSchedule.paymentRelativeTo,
"paymentRule" to floatingLeg.paymentSchedule.paymentRelativeTo, "calendar" to listOf("TODO"),
"calendar" to arr("TODO"), "paymentCalendar" to listOf("TODO"),
"paymentCalendar" to arr("TODO"), "fixingCalendar" to mapOf<String, Any>() // TODO
"fixingCalendar" to obj() // TODO ),
), common = mapOf(
"common" to obj( "valuationDate" to trade.product.startDate.unadjusted,
"valuationDate" to trade.product.startDate.unadjusted, "hashLegalDocs" to state.contract.legalContractReference.toString(),
"hashLegalDocs" to state.contract.legalContractReference.toString(), "interestRate" to mapOf(
"interestRate" to obj( "name" to "TODO",
"name" to "TODO", "oracle" to "TODO",
"oracle" to "TODO", "tenor" to mapOf(
"tenor" to obj( "name" to "TODO"
"name" to "TODO" )
) )
) ),
), ref = trade.info.id.get().value
"ref" to trade.info.id.get().value )
)
}
} }
} }

View File

@ -42,7 +42,7 @@ configurations {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// Corda integration dependencies // Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts') runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -145,4 +145,4 @@ task runSeller(type: JavaExec) {
main = 'net.corda.traderdemo.TraderDemoKt' main = 'net.corda.traderdemo.TraderDemoKt'
args '--role' args '--role'
args 'SELLER' args 'SELLER'
} }

View File

@ -35,17 +35,17 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
compile "com.google.guava:guava:19.0" compile "com.google.guava:guava:$guava_version"
// Force commons logging to version 1.2 to override Artemis, which pulls in 1.1.3 (ARTEMIS-424) // Force commons logging to version 1.2 to override Artemis, which pulls in 1.1.3 (ARTEMIS-424)
compile "commons-logging:commons-logging:1.2" compile "commons-logging:commons-logging:1.2"
// Unit testing helpers. // Unit testing helpers.
compile 'junit:junit:4.12' compile "junit:junit:$junit_version"
// Guava: Google test library (collections test suite) // Guava: Google test library (collections test suite)
compile "com.google.guava:guava-testlib:19.0" compile "com.google.guava:guava-testlib:19.0"
// OkHTTP: Simple HTTP library. // OkHTTP: Simple HTTP library.
compile 'com.squareup.okhttp3:okhttp:3.3.1' compile "com.squareup.okhttp3:okhttp:$okhttp_version"
} }

View File

@ -18,7 +18,12 @@ class HttpApi(val root: URL) {
*/ */
fun postJson(path: String, data: Any = Unit) = HttpUtils.postJson(URL(root, path), toJson(data)) fun postJson(path: String, data: Any = Unit) = HttpUtils.postJson(URL(root, path), toJson(data))
private fun toJson(any: Any) = if (any is String) any else ObjectMapper().writeValueAsString(any) /**
* Send a GET request to the path on the API specified.
*/
inline fun<reified T: Any> getJson(path: String, params: Map<String, String> = mapOf()) = HttpUtils.getJson<T>(URL(root, path), params)
private fun toJson(any: Any) = any as? String ?: HttpUtils.defaultMapper.writeValueAsString(any)
companion object { companion object {
fun fromHostAndPort(hostAndPort: HostAndPort, base: String, protocol: String = "http"): HttpApi fun fromHostAndPort(hostAndPort: HostAndPort, base: String, protocol: String = "http"): HttpApi

View File

@ -1,6 +1,9 @@
package net.corda.testing.http package net.corda.testing.http
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.utilities.JsonSupport
import okhttp3.* import okhttp3.*
import java.net.URL import java.net.URL
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -15,6 +18,9 @@ object HttpUtils {
.connectTimeout(5, TimeUnit.SECONDS) .connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS).build() .readTimeout(60, TimeUnit.SECONDS).build()
} }
val defaultMapper: ObjectMapper by lazy {
ObjectMapper().registerModule(JsonSupport.javaTimeModule).registerModule(KotlinModule())
}
fun putJson(url: URL, data: String) : Boolean { fun putJson(url: URL, data: String) : Boolean {
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data) val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), data)
@ -26,12 +32,19 @@ object HttpUtils {
return makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").post(body).build()) return makeRequest(Request.Builder().url(url).header("Content-Type", "application/json").post(body).build())
} }
inline fun<reified T: Any> getJson(url: URL, params: Map<String, String> = mapOf()) : T {
val paramString = if(params.isEmpty()) "" else "?" + params.map { "${it.key}=${it.value}" }.joinToString("&")
val parameterisedUrl = URL(url.toExternalForm() + paramString)
return defaultMapper.readValue(parameterisedUrl, T::class.java)
}
private fun makeRequest(request: Request): Boolean { private fun makeRequest(request: Request): Boolean {
val response = client.newCall(request).execute() val response = client.newCall(request).execute()
if (!response.isSuccessful) { if (!response.isSuccessful) {
logger.error("Could not fulfill HTTP request of type ${request.method()} to ${request.url()}. Status Code: ${response.code()}. Message: ${response.body().string()}") logger.error("Could not fulfill HTTP request of type ${request.method()} to ${request.url()}. Status Code: ${response.code()}. Message: ${response.body().string()}")
} }
return response.isSuccessful return response.isSuccessful
} }
} }

View File

@ -45,10 +45,10 @@ repositories {
dependencies { dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11' testCompile "junit:junit:$junit_version"
// TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's. // TornadoFX: A lightweight Kotlin framework for working with JavaFX UI's.
compile 'no.tornado:tornadofx:1.5.7' compile 'no.tornado:tornadofx:1.5.9'
// Corda Core: Data structures and basic types needed to work with Corda. // Corda Core: Data structures and basic types needed to work with Corda.
compile project(':core') compile project(':core')
@ -57,7 +57,7 @@ dependencies {
compile project(':finance') compile project(':finance')
// FontAwesomeFX: The "FontAwesome" icon library. // FontAwesomeFX: The "FontAwesome" icon library.
compile 'de.jensd:fontawesomefx-fontawesome:4.6.1-2' compile 'de.jensd:fontawesomefx-fontawesome:4.7.0'
// ReactFX: Functional reactive UI programming. // ReactFX: Functional reactive UI programming.
compile 'org.reactfx:reactfx:2.0-M5' compile 'org.reactfx:reactfx:2.0-M5'
@ -86,4 +86,4 @@ task(runSimulationNodes, dependsOn: 'classes', type: JavaExec) {
main = 'net.corda.explorer.MainKt' main = 'net.corda.explorer.MainKt'
classpath = sourceSets.main.runtimeClasspath classpath = sourceSets.main.runtimeClasspath
args '-S' args '-S'
} }

View File

@ -35,7 +35,8 @@ dependencies {
// https://mvnrepository.com/artifact/de.danielbechler/java-object-diff // https://mvnrepository.com/artifact/de.danielbechler/java-object-diff
compile group: 'de.danielbechler', name: 'java-object-diff', version: '0.10.2' compile group: 'de.danielbechler', name: 'java-object-diff', version: '0.10.2'
compile "com.typesafe:config:1.3.0" // TypeSafe Config: for simple and human friendly config files.
compile "com.typesafe:config:$typesafe_config_version"
} }
run { run {