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.
ext.corda_version = "0.7-SNAPSHOT"
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.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.artemis_version = '1.4.0'
ext.jackson_version = '2.8.0.rc2'
ext.artemis_version = '1.5.1'
ext.jackson_version = '2.8.5'
ext.jetty_version = '9.3.9.v20160517'
ext.jersey_version = '2.23.1'
ext.jolokia_version = '2.0.0-M1'
ext.assertj_version = '3.5.1'
ext.log4j_version = '2.6.2'
ext.bouncycastle_version = '1.54'
ext.jersey_version = '2.25'
ext.jolokia_version = '2.0.0-M3'
ext.assertj_version = '3.6.1'
ext.log4j_version = '2.7'
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 {
mavenLocal()
@ -33,9 +45,7 @@ buildscript {
classpath "net.corda.plugins:publish-utils:$gradle_plugins_version"
classpath "net.corda.plugins:quasar-utils:$gradle_plugins_version"
classpath "net.corda.plugins:cordformation:$gradle_plugins_version"
// Can run 'gradle dependencyUpdates' to find new versions of things.
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0'
}
}
@ -95,7 +105,7 @@ repositories {
// Required for building out the fat JAR.
dependencies {
compile project(':node')
compile "com.google.guava:guava:19.0"
compile "com.google.guava:guava:$guava_version"
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
}
@ -177,4 +187,4 @@ bintrayConfig {
name = 'R3'
email = 'dev@corda.net'
}
}
}

View File

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

View File

@ -31,11 +31,11 @@ sourceSets {
}
dependencies {
testCompile 'junit:junit:4.12'
testCompile "junit:junit:$junit_version"
testCompile "commons-fileupload:commons-fileupload:1.3.2"
// 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.
testCompile project(":node")
@ -43,7 +43,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$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"
// Thread safety annotations
@ -56,18 +56,19 @@ dependencies {
// AssertJ: for fluent assertions for testing
testCompile "org.assertj:assertj-core:${assertj_version}"
compile 'com.pholser:junit-quickcheck-core:0.6'
compile 'com.pholser:junit-quickcheck-generators:0.6'
compile "com.pholser:junit-quickcheck-core:$quickcheck_version"
compile "com.pholser:junit-quickcheck-generators:$quickcheck_version"
// Guava: Google utilities library.
compile "com.google.guava:guava:19.0"
compile "com.google.guava:guava:$guava_version"
// 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"
// Kryo: object graph serialization.
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.
// 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.
compile "javax.ws.rs:javax.ws.rs-api:2.0"
}
}

View File

@ -5,7 +5,7 @@ package net.corda.core.utilities
*/
object Emoji {
// 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_DIAMOND = "\ud83d\udd37"

View File

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

View File

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

View File

@ -22,10 +22,10 @@ dependencies {
compile "org.ow2.asm:asm-commons:$asm_version"
// 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.
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')
testCompile project(':test-utils')
testCompile 'junit:junit:4.12'
testCompile "junit:junit:$junit_version"
}
sourceSets {
@ -30,4 +30,4 @@ sourceSets {
srcDir "../config/test"
}
}
}
}

View File

@ -16,7 +16,7 @@ buildscript {
dependencies {
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'
email = 'dev@corda.net'
}
}
}

View File

@ -11,6 +11,7 @@ dependencies {
compile gradleApi()
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 {
compile gradleApi()
compile localGroovy()
}
}

View File

@ -66,10 +66,10 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$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.
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.
compile "org.apache.activemq:artemis-server:${artemis_version}"
@ -77,7 +77,7 @@ dependencies {
runtime "org.apache.activemq:artemis-amqp-protocol:${artemis_version}"
// 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
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-webapp:${jetty_version}"
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"
// Jersey for JAX-RS implementation for use in Jetty
@ -121,26 +121,27 @@ dependencies {
compile "com.google.jimfs:jimfs:1.1"
// 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.
testCompile 'junit:junit:4.12'
testCompile "junit:junit:$junit_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
compile "com.h2database:h2:1.4.192"
compile "com.h2database:h2:1.4.193"
// Exposed: Kotlin SQL library - under evaluation
// TODO: Upgrade to Exposed 0.7 (has API changes)
compile "org.jetbrains.exposed:exposed:0.5.0"
// 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.
compile "org.hibernate:hibernate-core:5.2.2.Final"
compile "org.hibernate:hibernate-java8:5.2.2.Final"
compile "org.hibernate:hibernate-core:$hibernate_version"
compile "org.hibernate:hibernate-java8:$hibernate_version"
// Capsule is a library for building independently executable fat JARs.
compile 'co.paralleluniverse:capsule:1.0.3'
@ -151,12 +152,12 @@ dependencies {
compile 'io.atomix.catalyst:catalyst-netty:1.1.1'
// 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) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
}

View File

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

View File

@ -25,49 +25,53 @@ import java.time.LocalDateTime
* the java.time API, some core types, and Kotlin data classes.
*/
object JsonSupport {
fun createDefaultMapper(identities: IdentityService): ObjectMapper {
val mapper = ServiceHubObjectMapper(identities)
mapper.enable(SerializationFeature.INDENT_OUTPUT)
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
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 javaTimeModule : Module by lazy {
SimpleModule("java.time").apply {
addSerializer(LocalDate::class.java, ToStringSerializer)
addDeserializer(LocalDate::class.java, LocalDateDeserializer)
addKeyDeserializer(LocalDate::class.java, LocalDateKeyDeserializer)
addSerializer(LocalDateTime::class.java, ToStringSerializer)
}
}
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()
object ToStringSerializer : JsonSerializer<Any>() {

View File

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

View File

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

View File

@ -45,7 +45,7 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile "junit:junit:$junit_version"
// Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')
@ -58,7 +58,7 @@ dependencies {
// Cordapp dependencies
// 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']) {
@ -129,4 +129,4 @@ publishing {
artifact javadocJar
}
}
}
}

View File

@ -32,7 +32,7 @@ class IRSDemoTest: IntegrationTestCategory {
private fun runDateChange(nodeAddr: HostAndPort) {
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) {

View File

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

View File

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

View File

@ -1,5 +1,5 @@
buildscript {
ext.strata_version = '1.0.0'
ext.strata_version = '1.1.2'
}
apply plugin: 'java'
@ -34,11 +34,23 @@ sourceSets {
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 {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile "junit:junit:$junit_version"
// Corda integration dependencies
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) {
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")
@Produces(MediaType.APPLICATION_JSON)
fun getBusinessDate(): Any {
return json {
obj(
"business-date" to LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate()
)
}
return mapOf(
"business-date" to LocalDateTime.ofInstant(rpc.currentNodeTime(), ZoneId.systemDefault()).toLocalDate()
)
}
/**
@ -195,12 +193,10 @@ class PortfolioApi(val rpc: CordaRPCOps) {
return withParty(partyName) { party ->
val trades = getTradesWith(party)
val portfolio = Portfolio(trades)
val summary = json {
obj(
"trades" to portfolio.trades.size,
"notional" to portfolio.getNotionalForParty(ownParty).toDouble()
)
}
val summary = mapOf(
"trades" to portfolio.trades.size,
"notional" to portfolio.getNotionalForParty(ownParty).toDouble()
)
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.
*/
@GET
@Path("whoami")
@Produces(MediaType.APPLICATION_JSON)
fun getWhoAmI(): Any {
val counterParties = rpc.networkMapUpdates().first.filter { it.legalIdentity.name != "NetworkMapService" && it.legalIdentity.name != "Notary" && it.legalIdentity.name != ownParty.name }
return json {
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
)
}
)
fun getWhoAmI(): AvailableParties {
val counterParties = rpc.networkMapUpdates().first.filter {
it.legalIdentity.name != "NetworkMapService" && it.legalIdentity.name != "Notary" && it.legalIdentity.name != ownParty.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)

View File

@ -15,7 +15,16 @@ import java.time.LocalDate
* API JSON generation functions for larger JSON outputs.
*/
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 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 yieldCurves = json {
obj(
"name" to "EUR",
"values" to completeSubgroups.get("EUR")!!.filter { !it.key.contains("Fixing") }.map {
json {
obj(
"tenor" to it.key,
"rate" to it.value
)
}
}
)
}
val fixings = json {
obj(
"name" to "EUR",
"values" to completeSubgroups.get("EUR")!!.filter { it.key.contains("Fixing") }.map {
json {
obj(
"tenor" to it.key,
"rate" to it.value
)
}
}
)
}
val yieldCurves = mapOf(
"name" to "EUR",
"values" to completeSubgroups.get("EUR")!!.filter { !it.key.contains("Fixing") }.map {
mapOf(
"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 {
mapOf(
"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()
return json {
obj(
"businessDate" to LocalDate.now(),
"portfolio" to obj(
"trades" to tradeCount,
"baseCurrency" to currency,
"IRFX" to tradeCount,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to tradeCount,
"agreed" to true
),
"marketData" to obj(
"yieldCurves" to yieldCurves,
"fixings" to fixings,
"agreed" to true
),
"sensitivities" to obj("curves" to processedSensitivities,
"currency" to valuation.currencySensitivies.amounts.toList().map {
obj(
"currency" to it.currency.code,
"amount" to it.amount
)
},
"agreed" to true
),
"initialMargin" to obj(
"baseCurrency" to currency,
"post" to obj(
"IRFX" to valuation.margin.first,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to valuation.margin.first
),
"call" to obj(
"IRFX" to valuation.margin.first,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to valuation.margin.first
),
"agreed" to true
),
"confirmation" to obj(
"hash" to state.hash().toString(),
"agreed" to true
)
)
}
val initialMarginView = InitialMarginView(
baseCurrency = currency,
post = mapOf(
"IRFX" to valuation.margin.first,
"commodity" to 0.0,
"equity" to 0.0,
"credit" to 0.0,
"total" to valuation.margin.first
),
call = mapOf(
"IRFX" to valuation.margin.first,
"commodity" to 0.0,
"equity" to 0.0,
"credit" to 0.0,
"total" to valuation.margin.first
),
agreed = true)
return ValuationsView(
businessDate = LocalDate.now(),
portfolio = mapOf(
"trades" to tradeCount,
"baseCurrency" to currency,
"IRFX" to tradeCount,
"commodity" to 0,
"equity" to 0,
"credit" to 0,
"total" to tradeCount,
"agreed" to true
),
marketData = mapOf(
"yieldCurves" to yieldCurves,
"fixings" to fixings,
"agreed" to true
),
sensitivities = mapOf("curves" to processedSensitivities,
"currency" to valuation.currencySensitivies.amounts.toList().map {
mapOf(
"currency" to it.currency.code,
"amount" to it.amount
)
},
"agreed" to true
),
initialMargin = initialMarginView,
confirmation = mapOf(
"hash" to state.hash().toString(),
"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 fixedLeg = 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 floatingRate = floatingLeg.calculation as IborRateCalculation
return json {
obj(
"fixedLeg" to obj(
"fixedRatePayer" to state.buyer.name,
"notional" to obj(
"token" to fixedLeg.currency.code,
"quantity" to fixedLeg.notionalSchedule.amount.initialValue
),
"paymentFrequency" to fixedLeg.paymentSchedule.paymentFrequency.toString(),
"effectiveDate" to fixedLeg.startDate.unadjusted,
"terminationDate" to fixedLeg.endDate.unadjusted,
"fixedRate" to obj(
"value" to fixedRate.rate.initialValue
),
"paymentRule" to fixedLeg.paymentSchedule.paymentRelativeTo.name,
"calendar" to arr("TODO"),
"paymentCalendar" to obj() // TODO
),
"floatingLeg" to obj(
"floatingRatePayer" to state.seller.name,
"notional" to obj(
"token" to floatingLeg.currency.code,
"quantity" to floatingLeg.notionalSchedule.amount.initialValue
),
"paymentFrequency" to floatingLeg.paymentSchedule.paymentFrequency.toString(),
"effectiveDate" to floatingLeg.startDate.unadjusted,
"terminationDate" to floatingLeg.endDate.unadjusted,
"index" to floatingRate.index.name,
"paymentRule" to floatingLeg.paymentSchedule.paymentRelativeTo,
"calendar" to arr("TODO"),
"paymentCalendar" to arr("TODO"),
"fixingCalendar" to obj() // TODO
),
"common" to obj(
"valuationDate" to trade.product.startDate.unadjusted,
"hashLegalDocs" to state.contract.legalContractReference.toString(),
"interestRate" to obj(
"name" to "TODO",
"oracle" to "TODO",
"tenor" to obj(
"name" to "TODO"
)
)
),
"ref" to trade.info.id.get().value
)
}
return TradeView(
fixedLeg = mapOf(
"fixedRatePayer" to state.buyer.name,
"notional" to mapOf(
"token" to fixedLeg.currency.code,
"quantity" to fixedLeg.notionalSchedule.amount.initialValue
),
"paymentFrequency" to fixedLeg.paymentSchedule.paymentFrequency.toString(),
"effectiveDate" to fixedLeg.startDate.unadjusted,
"terminationDate" to fixedLeg.endDate.unadjusted,
"fixedRate" to mapOf(
"value" to fixedRate.rate.initialValue
),
"paymentRule" to fixedLeg.paymentSchedule.paymentRelativeTo.name,
"calendar" to listOf("TODO"),
"paymentCalendar" to mapOf<String, Any>() // TODO
),
floatingLeg = mapOf(
"floatingRatePayer" to state.seller.name,
"notional" to mapOf(
"token" to floatingLeg.currency.code,
"quantity" to floatingLeg.notionalSchedule.amount.initialValue
),
"paymentFrequency" to floatingLeg.paymentSchedule.paymentFrequency.toString(),
"effectiveDate" to floatingLeg.startDate.unadjusted,
"terminationDate" to floatingLeg.endDate.unadjusted,
"index" to floatingRate.index.name,
"paymentRule" to floatingLeg.paymentSchedule.paymentRelativeTo,
"calendar" to listOf("TODO"),
"paymentCalendar" to listOf("TODO"),
"fixingCalendar" to mapOf<String, Any>() // TODO
),
common = mapOf(
"valuationDate" to trade.product.startDate.unadjusted,
"hashLegalDocs" to state.contract.legalContractReference.toString(),
"interestRate" to mapOf(
"name" to "TODO",
"oracle" to "TODO",
"tenor" to mapOf(
"name" to "TODO"
)
)
),
ref = trade.info.id.get().value
)
}
}

View File

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

View File

@ -35,17 +35,17 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$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)
compile "commons-logging:commons-logging:1.2"
// Unit testing helpers.
compile 'junit:junit:4.12'
compile "junit:junit:$junit_version"
// Guava: Google test library (collections test suite)
compile "com.google.guava:guava-testlib:19.0"
// 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))
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 {
fun fromHostAndPort(hostAndPort: HostAndPort, base: String, protocol: String = "http"): HttpApi

View File

@ -1,6 +1,9 @@
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.node.utilities.JsonSupport
import okhttp3.*
import java.net.URL
import java.util.concurrent.TimeUnit
@ -15,6 +18,9 @@ object HttpUtils {
.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS).build()
}
val defaultMapper: ObjectMapper by lazy {
ObjectMapper().registerModule(JsonSupport.javaTimeModule).registerModule(KotlinModule())
}
fun putJson(url: URL, data: String) : Boolean {
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())
}
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 {
val response = client.newCall(request).execute()
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()}")
}
return response.isSuccessful
}
}

View File

@ -45,10 +45,10 @@ repositories {
dependencies {
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.
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.
compile project(':core')
@ -57,7 +57,7 @@ dependencies {
compile project(':finance')
// 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.
compile 'org.reactfx:reactfx:2.0-M5'
@ -86,4 +86,4 @@ task(runSimulationNodes, dependsOn: 'classes', type: JavaExec) {
main = 'net.corda.explorer.MainKt'
classpath = sourceSets.main.runtimeClasspath
args '-S'
}
}

View File

@ -35,7 +35,8 @@ dependencies {
// https://mvnrepository.com/artifact/de.danielbechler/java-object-diff
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 {