mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
Remove finance dependencies
Re-enable code now DealState PR is in. Add plugable JSON serialisation Add docs for new plugin api. Move parseCurrency back to core to prevent dependency issues with crash shell parsing. Use :finance module as a proper CorDapp Move parseCurrency back onto Amount companion. Fix smoke tests Fixup after merge.
This commit is contained in:
parent
4278bce5c8
commit
8ec33d67e4
@ -5,7 +5,6 @@ apply plugin: 'com.jfrog.artifactory'
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':finance')
|
||||
testCompile project(':test-utils')
|
||||
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
@ -5,11 +5,9 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.core.*
|
||||
import com.fasterxml.jackson.databind.*
|
||||
import com.fasterxml.jackson.databind.deser.std.NumberDeserializers
|
||||
import com.fasterxml.jackson.databind.deser.std.StringArrayDeserializer
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import net.corda.contracts.BusinessCalendar
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.StateRef
|
||||
@ -29,12 +27,10 @@ import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.finance.parseCurrency
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.math.BigDecimal
|
||||
import java.security.PublicKey
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -84,8 +80,6 @@ object JacksonSupport {
|
||||
addSerializer(SecureHash.SHA256::class.java, SecureHashSerializer)
|
||||
addDeserializer(SecureHash::class.java, SecureHashDeserializer())
|
||||
addDeserializer(SecureHash.SHA256::class.java, SecureHashDeserializer())
|
||||
addSerializer(BusinessCalendar::class.java, CalendarSerializer)
|
||||
addDeserializer(BusinessCalendar::class.java, CalendarDeserializer)
|
||||
|
||||
// For ed25519 pubkeys
|
||||
addSerializer(EdDSAPublicKey::class.java, PublicKeySerializer)
|
||||
@ -277,36 +271,6 @@ object JacksonSupport {
|
||||
}
|
||||
}
|
||||
|
||||
data class BusinessCalendarWrapper(val holidayDates: List<LocalDate>) {
|
||||
fun toCalendar() = BusinessCalendar(holidayDates)
|
||||
}
|
||||
|
||||
object CalendarSerializer : JsonSerializer<BusinessCalendar>() {
|
||||
override fun serialize(obj: BusinessCalendar, generator: JsonGenerator, context: SerializerProvider) {
|
||||
val calendarName = BusinessCalendar.calendars.find { BusinessCalendar.getInstance(it) == obj }
|
||||
if (calendarName != null) {
|
||||
generator.writeString(calendarName)
|
||||
} else {
|
||||
generator.writeObject(BusinessCalendarWrapper(obj.holidayDates))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object CalendarDeserializer : JsonDeserializer<BusinessCalendar>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext): BusinessCalendar {
|
||||
return try {
|
||||
try {
|
||||
val array = StringArrayDeserializer.instance.deserialize(parser, context)
|
||||
BusinessCalendar.getInstance(*array)
|
||||
} catch (e: Exception) {
|
||||
parser.readValueAs(BusinessCalendarWrapper::class.java).toCalendar()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw JsonParseException(parser, "Invalid calendar(s) ${parser.text}: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object PublicKeySerializer : JsonSerializer<EdDSAPublicKey>() {
|
||||
override fun serialize(obj: EdDSAPublicKey, generator: JsonGenerator, provider: SerializerProvider) {
|
||||
check(obj.params == Crypto.EDDSA_ED25519_SHA512.algSpec)
|
||||
@ -349,7 +313,7 @@ object JacksonSupport {
|
||||
object AmountDeserializer : JsonDeserializer<Amount<*>>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext): Amount<*> {
|
||||
try {
|
||||
return parseCurrency(parser.text)
|
||||
return Amount.parseCurrency(parser.text)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
val tree = parser.readValueAsTree<JsonNode>()
|
||||
|
@ -8,7 +8,6 @@ import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.finance.parseCurrency
|
||||
import net.corda.testing.ALICE_PUBKEY
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.MINI_CORP
|
||||
@ -53,7 +52,7 @@ class JacksonSupportTest : TestDependencyInjectionBase() {
|
||||
@Test
|
||||
fun writeAmount() {
|
||||
val writer = mapper.writer().without(SerializationFeature.INDENT_OUTPUT)
|
||||
assertEquals("""{"notional":"25000000.00 USD"}""", writer.writeValueAsString(Dummy(parseCurrency("$25000000"))))
|
||||
assertEquals("""{"notional":"25000000.00 USD"}""", writer.writeValueAsString(Dummy(Amount.parseCurrency("$25000000"))))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,6 +50,9 @@ processSmokeTestResources {
|
||||
from(project(':node:capsule').tasks['buildCordaJAR']) {
|
||||
rename 'corda-(.*)', 'corda.jar'
|
||||
}
|
||||
from(project(':finance').tasks['jar']) {
|
||||
rename 'finance-(.*)', 'finance.jar'
|
||||
}
|
||||
}
|
||||
|
||||
// To find potential version conflicts, run "gradle htmlDependencyReport" and then look in
|
||||
|
@ -18,11 +18,17 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static kotlin.test.AssertionsKt.assertEquals;
|
||||
import static kotlin.test.AssertionsKt.fail;
|
||||
import static net.corda.contracts.GetBalances.getCashBalance;
|
||||
|
||||
public class StandaloneCordaRPCJavaClientTest {
|
||||
@ -32,6 +38,7 @@ public class StandaloneCordaRPCJavaClientTest {
|
||||
|
||||
private AtomicInteger port = new AtomicInteger(15000);
|
||||
|
||||
private NodeProcess.Factory factory;
|
||||
private NodeProcess notary;
|
||||
private CordaRPCOps rpcProxy;
|
||||
private CordaRPCConnection connection;
|
||||
@ -49,7 +56,9 @@ public class StandaloneCordaRPCJavaClientTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
notary = new NodeProcess.Factory().create(notaryConfig);
|
||||
factory = new NodeProcess.Factory();
|
||||
copyFinanceCordapp();
|
||||
notary = factory.create(notaryConfig);
|
||||
connection = notary.connect();
|
||||
rpcProxy = connection.getProxy();
|
||||
notaryNode = fetchNotaryIdentity();
|
||||
@ -64,6 +73,28 @@ public class StandaloneCordaRPCJavaClientTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFinanceCordapp() {
|
||||
Path pluginsDir = (factory.baseDirectory(notaryConfig).resolve("plugins"));
|
||||
try {
|
||||
Files.createDirectories(pluginsDir);
|
||||
} catch (IOException ex) {
|
||||
fail("Failed to create directories");
|
||||
}
|
||||
try (Stream<Path> paths = Files.walk(Paths.get("build", "resources", "smokeTest"))) {
|
||||
paths.forEach(file -> {
|
||||
if (file.toString().contains("corda-finance")) {
|
||||
try {
|
||||
Files.copy(file, pluginsDir.resolve(file.getFileName()));
|
||||
} catch (IOException ex) {
|
||||
fail("Failed to copy finance jar");
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
fail("Failed to walk files");
|
||||
}
|
||||
}
|
||||
|
||||
private NodeInfo fetchNotaryIdentity() {
|
||||
List<NodeInfo> nodeDataSnapshot = rpcProxy.networkMapSnapshot();
|
||||
return nodeDataSnapshot.get(0);
|
||||
|
@ -7,7 +7,7 @@ import net.corda.contracts.asset.Cash
|
||||
import net.corda.contracts.getCashBalance
|
||||
import net.corda.contracts.getCashBalances
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.InputStreamAndHash
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.node.services.Vault
|
||||
@ -32,8 +32,10 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.FilterInputStream
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.streams.toList
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotEquals
|
||||
@ -43,11 +45,12 @@ class StandaloneCordaRPClientTest {
|
||||
private companion object {
|
||||
val log = loggerFor<StandaloneCordaRPClientTest>()
|
||||
val user = User("user1", "test", permissions = setOf("ALL"))
|
||||
val port = AtomicInteger(15000)
|
||||
val port = AtomicInteger(15200)
|
||||
const val attachmentSize = 2116
|
||||
val timeout = 60.seconds
|
||||
}
|
||||
|
||||
private lateinit var factory: NodeProcess.Factory
|
||||
private lateinit var notary: NodeProcess
|
||||
private lateinit var rpcProxy: CordaRPCOps
|
||||
private lateinit var connection: CordaRPCConnection
|
||||
@ -64,7 +67,9 @@ class StandaloneCordaRPClientTest {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
notary = NodeProcess.Factory().create(notaryConfig)
|
||||
factory = NodeProcess.Factory()
|
||||
copyFinanceCordapp()
|
||||
notary = factory.create(notaryConfig)
|
||||
connection = notary.connect()
|
||||
rpcProxy = connection.proxy
|
||||
notaryNode = fetchNotaryIdentity()
|
||||
@ -79,6 +84,15 @@ class StandaloneCordaRPClientTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFinanceCordapp() {
|
||||
val pluginsDir = (factory.baseDirectory(notaryConfig) / "plugins").createDirectories()
|
||||
// Find the finance jar file for the smoke tests of this module
|
||||
val financeJar = Paths.get("build", "resources", "smokeTest").list {
|
||||
it.filter { "corda-finance" in it.toString() }.toList().single()
|
||||
}
|
||||
financeJar.copyToDirectory(pluginsDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test attachments`() {
|
||||
val attachment = InputStreamAndHash.createInMemoryTestZip(attachmentSize, 1)
|
||||
@ -189,6 +203,7 @@ class StandaloneCordaRPClientTest {
|
||||
@Test
|
||||
fun `test cash balances`() {
|
||||
val startCash = rpcProxy.getCashBalances()
|
||||
println(startCash)
|
||||
assertTrue(startCash.isEmpty(), "Should not start with any cash")
|
||||
|
||||
val flowHandle = rpcProxy.startFlow(::CashIssueFlow, 629.DOLLARS, OpaqueBytes.of(0), notaryNode.legalIdentity)
|
||||
|
@ -107,6 +107,70 @@ data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal,
|
||||
*/
|
||||
@JvmStatic
|
||||
fun <T : Any> Iterable<Amount<T>>.sumOrZero(token: T) = if (iterator().hasNext()) sumOrThrow() else Amount.zero(token)
|
||||
|
||||
private val currencySymbols: Map<String, Currency> = mapOf(
|
||||
"$" to Currency.getInstance("USD"),
|
||||
"£" to Currency.getInstance("GBP"),
|
||||
"€" to Currency.getInstance("EUR"),
|
||||
"¥" to Currency.getInstance("JPY"),
|
||||
"₽" to Currency.getInstance("RUB")
|
||||
)
|
||||
|
||||
private val currencyCodes: Map<String, Currency> by lazy {
|
||||
Currency.getAvailableCurrencies().associateBy { it.currencyCode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an amount that is equal to the given currency amount in text. Examples of what is supported:
|
||||
*
|
||||
* - 12 USD
|
||||
* - 14.50 USD
|
||||
* - 10 USD
|
||||
* - 30 CHF
|
||||
* - $10.24
|
||||
* - £13
|
||||
* - €5000
|
||||
*
|
||||
* Note this method does NOT respect internationalisation rules: it ignores commas and uses . as the
|
||||
* decimal point separator, always. It also ignores the users locale:
|
||||
*
|
||||
* - $ is always USD,
|
||||
* - £ is always GBP
|
||||
* - € is always the Euro
|
||||
* - ¥ is always Japanese Yen.
|
||||
* - ₽ is always the Russian ruble.
|
||||
*
|
||||
* Thus an input of $12 expecting some other countries dollar will not work. Do your own parsing if
|
||||
* you need correct handling of currency amounts with locale-sensitive handling.
|
||||
*
|
||||
* @throws IllegalArgumentException if the input string was not understood.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parseCurrency(input: String): Amount<Currency> {
|
||||
val i = input.filter { it != ',' }
|
||||
try {
|
||||
// First check the symbols at the front.
|
||||
for ((symbol, currency) in currencySymbols) {
|
||||
if (i.startsWith(symbol)) {
|
||||
val rest = i.substring(symbol.length)
|
||||
return Amount.fromDecimal(BigDecimal(rest), currency)
|
||||
}
|
||||
}
|
||||
// Now check the codes at the end.
|
||||
val split = i.split(' ')
|
||||
if (split.size == 2) {
|
||||
val (rest, code) = split
|
||||
for ((cc, currency) in currencyCodes) {
|
||||
if (cc == code) {
|
||||
return Amount.fromDecimal(BigDecimal(rest), currency)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
throw IllegalArgumentException("Could not parse $input as a currency", e)
|
||||
}
|
||||
throw IllegalArgumentException("Did not recognise the currency in $input or could not parse")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -51,6 +51,11 @@ UNRELEASED
|
||||
no longer auto-suggests these extension functions in completion unless you add import lines for them yourself
|
||||
(this is Kotlin IDE bug KT-15286).
|
||||
|
||||
* ``:finance`` module now acting as a CorDapp with regard to flow registration, schemas and serializable types.
|
||||
|
||||
* ``WebServerPluginRegistry`` now has a ``customizeJSONSerialization`` which can be overridden to extend the REST JSON
|
||||
serializers. In particular the IRS demos must now register the ``BusinessCalendar`` serializers.
|
||||
|
||||
Milestone 14
|
||||
------------
|
||||
|
||||
|
@ -92,6 +92,8 @@ The ``WebServerPluginRegistry`` class defines the following:
|
||||
be distributed within the CorDapp jars. This static content will not be available if the bundled web server is not
|
||||
started
|
||||
|
||||
* ``customizeJSONSerialization``, which can be overridden to register custom JSON serializers if required by the REST api.
|
||||
|
||||
* The static web content itself should be placed inside the ``src/main/resources`` directory
|
||||
|
||||
To learn about how to use gradle to build your cordapp against Corda and generate an artifact please read
|
||||
|
@ -5,13 +5,16 @@ apply plugin: 'kotlin-jpa'
|
||||
apply plugin: CanonicalizerPlugin
|
||||
apply plugin: 'net.corda.plugins.publish-utils'
|
||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||
apply plugin: 'net.corda.plugins.cordformation'
|
||||
apply plugin: 'com.jfrog.artifactory'
|
||||
|
||||
description 'Corda finance modules'
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':node-schemas')
|
||||
// Note the :finance module is a CorDapp in its own right
|
||||
// and CorDapps using :finance features should use 'cordapp' not 'compile' linkage.
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':node-schemas')
|
||||
|
||||
testCompile project(':test-utils')
|
||||
testCompile project(path: ':core', configuration: 'testArtifacts')
|
||||
|
@ -31,66 +31,3 @@ infix fun Currency.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
|
||||
infix fun Amount<Currency>.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
|
||||
infix fun Currency.issuedBy(deposit: PartyAndReference) = Issued(deposit, this)
|
||||
infix fun Amount<Currency>.issuedBy(deposit: PartyAndReference) = Amount(quantity, displayTokenSize, token.issuedBy(deposit))
|
||||
|
||||
private val currencySymbols: Map<String, Currency> = mapOf(
|
||||
"$" to USD,
|
||||
"£" to GBP,
|
||||
"€" to EUR,
|
||||
"¥" to JPY,
|
||||
"₽" to RUB
|
||||
)
|
||||
|
||||
private val currencyCodes: Map<String, Currency> by lazy {
|
||||
Currency.getAvailableCurrencies().associateBy { it.currencyCode }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an amount that is equal to the given currency amount in text. Examples of what is supported:
|
||||
*
|
||||
* - 12 USD
|
||||
* - 14.50 USD
|
||||
* - 10 USD
|
||||
* - 30 CHF
|
||||
* - $10.24
|
||||
* - £13
|
||||
* - €5000
|
||||
*
|
||||
* Note this method does NOT respect internationalisation rules: it ignores commas and uses . as the
|
||||
* decimal point separator, always. It also ignores the users locale:
|
||||
*
|
||||
* - $ is always USD,
|
||||
* - £ is always GBP
|
||||
* - € is always the Euro
|
||||
* - ¥ is always Japanese Yen.
|
||||
* - ₽ is always the Russian ruble.
|
||||
*
|
||||
* Thus an input of $12 expecting some other countries dollar will not work. Do your own parsing if
|
||||
* you need correct handling of currency amounts with locale-sensitive handling.
|
||||
*
|
||||
* @throws IllegalArgumentException if the input string was not understood.
|
||||
*/
|
||||
fun parseCurrency(input: String): Amount<Currency> {
|
||||
val i = input.filter { it != ',' }
|
||||
try {
|
||||
// First check the symbols at the front.
|
||||
for ((symbol, currency) in currencySymbols) {
|
||||
if (i.startsWith(symbol)) {
|
||||
val rest = i.substring(symbol.length)
|
||||
return Amount.fromDecimal(BigDecimal(rest), currency)
|
||||
}
|
||||
}
|
||||
// Now check the codes at the end.
|
||||
val split = i.split(' ')
|
||||
if (split.size == 2) {
|
||||
val (rest, code) = split
|
||||
for ((cc, currency) in currencyCodes) {
|
||||
if (cc == code) {
|
||||
return Amount.fromDecimal(BigDecimal(rest), currency)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
throw IllegalArgumentException("Could not parse $input as a currency", e)
|
||||
}
|
||||
throw IllegalArgumentException("Did not recognise the currency in $input or could not parse")
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
@file:JvmName("FinanceJSONSupport")
|
||||
|
||||
package net.corda.plugin
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.*
|
||||
import com.fasterxml.jackson.databind.deser.std.StringArrayDeserializer
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule
|
||||
import net.corda.contracts.BusinessCalendar
|
||||
import java.time.LocalDate
|
||||
|
||||
fun registerFinanceJSONMappers(objectMapper: ObjectMapper): Unit {
|
||||
val financeModule = SimpleModule("finance").apply {
|
||||
addSerializer(BusinessCalendar::class.java, CalendarSerializer)
|
||||
addDeserializer(BusinessCalendar::class.java, CalendarDeserializer)
|
||||
}
|
||||
objectMapper.registerModule(financeModule)
|
||||
}
|
||||
|
||||
data class BusinessCalendarWrapper(val holidayDates: List<LocalDate>) {
|
||||
fun toCalendar() = BusinessCalendar(holidayDates)
|
||||
}
|
||||
|
||||
object CalendarSerializer : JsonSerializer<BusinessCalendar>() {
|
||||
override fun serialize(obj: BusinessCalendar, generator: JsonGenerator, context: SerializerProvider) {
|
||||
val calendarName = BusinessCalendar.calendars.find { BusinessCalendar.getInstance(it) == obj }
|
||||
if (calendarName != null) {
|
||||
generator.writeString(calendarName)
|
||||
} else {
|
||||
generator.writeObject(BusinessCalendarWrapper(obj.holidayDates))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object CalendarDeserializer : JsonDeserializer<BusinessCalendar>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext): BusinessCalendar {
|
||||
return try {
|
||||
try {
|
||||
val array = StringArrayDeserializer.instance.deserialize(parser, context)
|
||||
BusinessCalendar.getInstance(*array)
|
||||
} catch (e: Exception) {
|
||||
parser.readValueAs(BusinessCalendarWrapper::class.java).toCalendar()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw JsonParseException(parser, "Invalid calendar(s) ${parser.text}: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.corda.plugin
|
||||
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.schemas.CashSchemaV1
|
||||
|
||||
class FinancePluginRegistry : CordaPluginRegistry() {
|
||||
override val requiredSchemas: Set<MappedSchema> = setOf(
|
||||
CashSchemaV1
|
||||
)
|
||||
}
|
@ -0,0 +1 @@
|
||||
net.corda.plugin.FinancePluginRegistry
|
@ -14,17 +14,17 @@ class CurrencyUtilsTest {
|
||||
|
||||
@Test
|
||||
fun parseCurrency() {
|
||||
assertEquals(Amount(1234L, GBP), parseCurrency("£12.34"))
|
||||
assertEquals(Amount(1200L, GBP), parseCurrency("£12"))
|
||||
assertEquals(Amount(1000L, USD), parseCurrency("$10"))
|
||||
assertEquals(Amount(5000L, JPY), parseCurrency("¥5000"))
|
||||
assertEquals(Amount(500000L, RUB), parseCurrency("₽5000"))
|
||||
assertEquals(Amount(1500000000L, CHF), parseCurrency("15,000,000 CHF"))
|
||||
assertEquals(Amount(1234L, GBP), Amount.parseCurrency("£12.34"))
|
||||
assertEquals(Amount(1200L, GBP), Amount.parseCurrency("£12"))
|
||||
assertEquals(Amount(1000L, USD), Amount.parseCurrency("$10"))
|
||||
assertEquals(Amount(5000L, JPY), Amount.parseCurrency("¥5000"))
|
||||
assertEquals(Amount(500000L, RUB), Amount.parseCurrency("₽5000"))
|
||||
assertEquals(Amount(1500000000L, CHF), Amount.parseCurrency("15,000,000 CHF"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rendering() {
|
||||
assertEquals("5000 JPY", parseCurrency("¥5000").toString())
|
||||
assertEquals("50.12 USD", parseCurrency("$50.12").toString())
|
||||
assertEquals("5000 JPY", Amount.parseCurrency("¥5000").toString())
|
||||
assertEquals("50.12 USD", Amount.parseCurrency("$50.12").toString())
|
||||
}
|
||||
}
|
@ -27,9 +27,6 @@ import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.debug
|
||||
import net.corda.core.utilities.toNonEmptySet
|
||||
import net.corda.flows.CashExitFlow
|
||||
import net.corda.flows.CashIssueFlow
|
||||
import net.corda.flows.CashPaymentFlow
|
||||
import net.corda.node.services.ContractUpgradeHandler
|
||||
import net.corda.node.services.NotaryChangeHandler
|
||||
import net.corda.node.services.NotifyTransactionHandler
|
||||
@ -383,11 +380,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
.filter { it.isUserInvokable() } +
|
||||
// Add any core flows here
|
||||
listOf(
|
||||
ContractUpgradeFlow::class.java,
|
||||
// TODO Remove all Cash flows from default list once they are split into separate CorDapp.
|
||||
CashIssueFlow::class.java,
|
||||
CashExitFlow::class.java,
|
||||
CashPaymentFlow::class.java)
|
||||
ContractUpgradeFlow::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,6 @@ import net.corda.node.services.persistence.DBTransactionMappingStorage
|
||||
import net.corda.node.services.persistence.DBTransactionStorage
|
||||
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||
import net.corda.node.services.vault.VaultSchemaV1
|
||||
import net.corda.schemas.CashSchemaV1
|
||||
|
||||
/**
|
||||
* Most basic implementation of [SchemaService].
|
||||
@ -43,8 +42,7 @@ class NodeSchemaService(customSchemas: Set<MappedSchema> = emptySet()) : SchemaS
|
||||
// Required schemas are those used by internal Corda services
|
||||
// For example, cash is used by the vault for coin selection (but will be extracted as a standalone CorDapp in future)
|
||||
val requiredSchemas: Map<MappedSchema, SchemaService.SchemaOptions> =
|
||||
mapOf(Pair(CashSchemaV1, SchemaService.SchemaOptions()),
|
||||
Pair(CommonSchemaV1, SchemaService.SchemaOptions()),
|
||||
mapOf(Pair(CommonSchemaV1, SchemaService.SchemaOptions()),
|
||||
Pair(VaultSchemaV1, SchemaService.SchemaOptions()),
|
||||
Pair(NodeServicesV1, SchemaService.SchemaOptions()))
|
||||
|
||||
|
@ -3,16 +3,21 @@ package net.corda.node.services.vault;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import kotlin.Pair;
|
||||
import net.corda.contracts.DealState;
|
||||
import net.corda.contracts.asset.*;
|
||||
import net.corda.contracts.asset.Cash;
|
||||
import net.corda.contracts.asset.CashUtilities;
|
||||
import net.corda.core.contracts.*;
|
||||
import net.corda.core.crypto.EncodingUtils;
|
||||
import net.corda.core.identity.AbstractParty;
|
||||
import net.corda.core.messaging.DataFeed;
|
||||
import net.corda.core.node.services.*;
|
||||
import net.corda.core.node.services.IdentityService;
|
||||
import net.corda.core.node.services.Vault;
|
||||
import net.corda.core.node.services.VaultQueryException;
|
||||
import net.corda.core.node.services.VaultQueryService;
|
||||
import net.corda.core.node.services.vault.*;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.LinearStateQueryCriteria;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultCustomQueryCriteria;
|
||||
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria;
|
||||
import net.corda.core.schemas.MappedSchema;
|
||||
import net.corda.core.utilities.OpaqueBytes;
|
||||
import net.corda.node.utilities.CordaPersistence;
|
||||
import net.corda.schemas.CashSchemaV1;
|
||||
@ -34,12 +39,14 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static net.corda.contracts.asset.CashUtilities.getDUMMY_CASH_ISSUER;
|
||||
import static net.corda.contracts.asset.CashUtilities.getDUMMY_CASH_ISSUER_KEY;
|
||||
import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
|
||||
import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
|
||||
import static net.corda.core.utilities.ByteArrays.toHexString;
|
||||
import static net.corda.testing.CoreTestUtils.*;
|
||||
import static net.corda.testing.TestConstants.*;
|
||||
import static net.corda.contracts.asset.CashUtilities.*;
|
||||
import static net.corda.testing.TestConstants.getDUMMY_NOTARY;
|
||||
import static net.corda.testing.TestConstants.getDUMMY_NOTARY_KEY;
|
||||
import static net.corda.testing.node.MockServicesKt.makeTestDatabaseAndMockServices;
|
||||
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -56,8 +63,10 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
ArrayList<KeyPair> keys = new ArrayList<>();
|
||||
keys.add(getMEGA_CORP_KEY());
|
||||
keys.add(getDUMMY_NOTARY_KEY());
|
||||
Set<MappedSchema> requiredSchemas = new HashSet<>();
|
||||
requiredSchemas.add(CashSchemaV1.INSTANCE);
|
||||
IdentityService identitySvc = makeTestIdentityService();
|
||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(Collections.EMPTY_SET, keys, () -> identitySvc);
|
||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(requiredSchemas, keys, () -> identitySvc);
|
||||
issuerServices = new MockServices(getDUMMY_CASH_ISSUER_KEY(), getBOC_KEY());
|
||||
database = databaseAndServices.getFirst();
|
||||
services = databaseAndServices.getSecond();
|
||||
@ -74,7 +83,7 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static queryBy() tests
|
||||
* Static queryBy() tests
|
||||
*/
|
||||
|
||||
@Test
|
||||
@ -125,15 +134,15 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
Amount<Currency> amount = new Amount<>(100, Currency.getInstance("USD"));
|
||||
|
||||
VaultFiller.fillWithSomeTestCash(services,
|
||||
new Amount<Currency>(100, Currency.getInstance("USD")),
|
||||
new Amount<Currency>(100, Currency.getInstance("USD")),
|
||||
issuerServices,
|
||||
TestConstants.getDUMMY_NOTARY(),
|
||||
3,
|
||||
3,
|
||||
new Random(),
|
||||
new OpaqueBytes("1".getBytes()),
|
||||
null,
|
||||
CashUtilities.getDUMMY_CASH_ISSUER());
|
||||
TestConstants.getDUMMY_NOTARY(),
|
||||
3,
|
||||
3,
|
||||
new Random(),
|
||||
new OpaqueBytes("1".getBytes()),
|
||||
null,
|
||||
CashUtilities.getDUMMY_CASH_ISSUER());
|
||||
|
||||
VaultFiller.consumeCash(services, amount, getDUMMY_NOTARY());
|
||||
|
||||
@ -177,7 +186,7 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
QueryCriteria compositeCriteria1 = dealCriteriaAll.or(linearCriteriaAll);
|
||||
QueryCriteria compositeCriteria2 = vaultCriteria.and(compositeCriteria1);
|
||||
|
||||
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
|
||||
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
|
||||
Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
|
||||
Sort sorting = new Sort(ImmutableSet.of(sortByUid));
|
||||
Vault.Page<LinearState> results = vaultQuerySvc.queryBy(LinearState.class, compositeCriteria2, pageSpec, sorting);
|
||||
@ -226,12 +235,12 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tx;
|
||||
return tx;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic trackBy() tests
|
||||
* Dynamic trackBy() tests
|
||||
*/
|
||||
|
||||
@Test
|
||||
@ -287,7 +296,7 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
QueryCriteria dealOrLinearIdCriteria = dealCriteria.or(linearCriteria);
|
||||
QueryCriteria compositeCriteria = dealOrLinearIdCriteria.and(vaultCriteria);
|
||||
|
||||
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
|
||||
PageSpecification pageSpec = new PageSpecification(DEFAULT_PAGE_NUM, MAX_PAGE_SIZE);
|
||||
Sort.SortColumn sortByUid = new Sort.SortColumn(new SortAttribute.Standard(Sort.LinearStateAttribute.UUID), Sort.Direction.DESC);
|
||||
Sort sorting = new Sort(ImmutableSet.of(sortByUid));
|
||||
DataFeed<Vault.Page<ContractState>, Vault.Update<ContractState>> results = vaultQuerySvc.trackBy(ContractState.class, compositeCriteria, pageSpec, sorting);
|
||||
@ -302,7 +311,7 @@ public class VaultQueryJavaTests extends TestDependencyInjectionBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregation Functions
|
||||
* Aggregation Functions
|
||||
*/
|
||||
|
||||
@Test
|
||||
|
@ -24,13 +24,15 @@ configurations {
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
||||
// The bank of corda CorDapp depends upon Cash CorDapp features
|
||||
cordapp project(':finance')
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaCompile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':client:jfx')
|
||||
cordaCompile project(':client:rpc')
|
||||
cordaCompile project(':finance')
|
||||
cordaCompile project(':webserver')
|
||||
cordaCompile project(':test-utils')
|
||||
|
||||
@ -54,7 +56,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
node {
|
||||
name "CN=BankOfCorda,O=R3,L=New York,C=US"
|
||||
@ -62,7 +64,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
rpcUsers = [
|
||||
['username' : "bankUser",
|
||||
'password' : "test",
|
||||
@ -77,7 +79,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
rpcUsers = [
|
||||
['username' : "bigCorpUser",
|
||||
'password' : "test",
|
||||
|
@ -27,11 +27,13 @@ configurations {
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
||||
// The irs demo CorDapp depends upon Cash CorDapp features
|
||||
cordapp project(':finance')
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaCompile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':finance')
|
||||
cordaCompile project(':webserver')
|
||||
|
||||
// Javax is required for webapis
|
||||
@ -55,7 +57,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
p2pPort 10002
|
||||
rpcPort 10003
|
||||
webPort 10004
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
useTestClock true
|
||||
}
|
||||
node {
|
||||
@ -64,7 +66,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
useTestClock true
|
||||
}
|
||||
node {
|
||||
@ -73,7 +75,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
webPort 10010
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
useTestClock true
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package net.corda.irs
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.internal.concurrent.transpose
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
import net.corda.core.node.services.ServiceInfo
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.internal.concurrent.transpose
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.loggerFor
|
||||
@ -15,6 +15,7 @@ import net.corda.irs.utilities.uploadFile
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.transactions.SimpleNotaryService
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.plugin.registerFinanceJSONMappers
|
||||
import net.corda.testing.DUMMY_BANK_A
|
||||
import net.corda.testing.DUMMY_BANK_B
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
@ -61,6 +62,7 @@ class IRSDemoTest : IntegrationTestCategory {
|
||||
|
||||
val (_, nodeAApi, nodeBApi) = listOf(controller, nodeA, nodeB).zip(listOf(controllerAddr, nodeAAddr, nodeBAddr)).map {
|
||||
val mapper = net.corda.jackson.JacksonSupport.createDefaultMapper(it.first.rpc)
|
||||
registerFinanceJSONMappers(mapper)
|
||||
HttpApi.fromHostAndPort(it.second, "api/irs", mapper = mapper)
|
||||
}
|
||||
val nextFixingDates = getFixingDateObservable(nodeA.configuration)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.corda.irs.plugin
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.irs.api.InterestRateSwapAPI
|
||||
import net.corda.plugin.registerFinanceJSONMappers
|
||||
import net.corda.webserver.services.WebServerPluginRegistry
|
||||
import java.util.function.Function
|
||||
|
||||
@ -9,4 +11,6 @@ class IRSPlugin : WebServerPluginRegistry {
|
||||
override val staticServeDirs: Map<String, String> = mapOf(
|
||||
"irsdemo" to javaClass.classLoader.getResource("irsweb").toExternalForm()
|
||||
)
|
||||
|
||||
override fun customizeJSONSerialization(om: ObjectMapper): Unit = registerFinanceJSONMappers(om)
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.InitiatingFlow
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.concurrent.*
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.internal.concurrent.*
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.toFuture
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -21,6 +21,7 @@ import net.corda.irs.contract.InterestRateSwap
|
||||
import net.corda.irs.flows.FixingFlow
|
||||
import net.corda.jackson.JacksonSupport
|
||||
import net.corda.node.services.identity.InMemoryIdentityService
|
||||
import net.corda.plugin.registerFinanceJSONMappers
|
||||
import net.corda.testing.DUMMY_CA
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import rx.Observable
|
||||
@ -44,6 +45,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
|
||||
override fun startMainSimulation(): CordaFuture<Unit> {
|
||||
val future = openFuture<Unit>()
|
||||
om = JacksonSupport.createInMemoryMapper(InMemoryIdentityService((banks + regulators + networkMap).map { it.info.legalIdentityAndCert }, trustRoot = DUMMY_CA.certificate))
|
||||
registerFinanceJSONMappers(om)
|
||||
|
||||
startIRSDealBetween(0, 1).thenMatch({
|
||||
// Next iteration is a pause.
|
||||
|
@ -30,11 +30,13 @@ configurations {
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
||||
// The SIMM demo CorDapp depends upon Cash CorDapp features
|
||||
cordapp project(':finance')
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaCompile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':finance')
|
||||
cordaCompile project(':webserver')
|
||||
|
||||
// Javax is required for webapis
|
||||
@ -66,28 +68,28 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
name "CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
p2pPort 10002
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
node {
|
||||
name "CN=Bank A,O=Bank A,L=London,C=GB"
|
||||
advertisedServices = []
|
||||
p2pPort 10004
|
||||
webPort 10005
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
node {
|
||||
name "CN=Bank B,O=Bank B,L=New York,C=US"
|
||||
advertisedServices = []
|
||||
p2pPort 10006
|
||||
webPort 10007
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
node {
|
||||
name "CN=Bank C,O=Bank C,L=Tokyo,C=Japan"
|
||||
advertisedServices = []
|
||||
p2pPort 10008
|
||||
webPort 10009
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.corda.vega.plugin
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.core.node.CordaPluginRegistry
|
||||
import net.corda.plugin.registerFinanceJSONMappers
|
||||
import net.corda.vega.api.PortfolioApi
|
||||
import net.corda.webserver.services.WebServerPluginRegistry
|
||||
import java.util.function.Function
|
||||
@ -14,4 +16,5 @@ import java.util.function.Function
|
||||
class SimmPlugin : WebServerPluginRegistry {
|
||||
override val webApis = listOf(Function(::PortfolioApi))
|
||||
override val staticServeDirs: Map<String, String> = mapOf("simmvaluationdemo" to javaClass.classLoader.getResource("simmvaluationweb").toExternalForm())
|
||||
override fun customizeJSONSerialization(om: ObjectMapper): Unit = registerFinanceJSONMappers(om)
|
||||
}
|
@ -24,11 +24,13 @@ configurations {
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
|
||||
// The trader demo CorDapp depends upon Cash CorDapp features
|
||||
cordapp project(':finance')
|
||||
|
||||
// Corda integration dependencies
|
||||
cordaCompile project(path: ":node:capsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts')
|
||||
cordaCompile project(':core')
|
||||
cordaCompile project(':finance')
|
||||
|
||||
// Corda Plugins: dependent flows and services
|
||||
cordapp project(':samples:bank-of-corda-demo')
|
||||
@ -53,14 +55,14 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
name "CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"
|
||||
advertisedServices = ["corda.notary.validating"]
|
||||
p2pPort 10002
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
}
|
||||
node {
|
||||
name "CN=Bank A,O=Bank A,L=London,C=GB"
|
||||
advertisedServices = []
|
||||
p2pPort 10005
|
||||
rpcPort 10006
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
node {
|
||||
@ -68,7 +70,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
advertisedServices = []
|
||||
p2pPort 10008
|
||||
rpcPort 10009
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
node {
|
||||
@ -76,7 +78,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
|
||||
advertisedServices = []
|
||||
p2pPort 10011
|
||||
rpcPort 10012
|
||||
cordapps = []
|
||||
cordapps = ["net.corda:finance:$corda_release_version"]
|
||||
rpcUsers = ext.rpcUsers
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ processTestResources {
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':finance')
|
||||
compile project(':client:rpc')
|
||||
compile project(':client:jackson')
|
||||
|
||||
|
@ -4,6 +4,7 @@ import com.google.common.html.HtmlEscapers.htmlEscaper
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.jackson.JacksonSupport
|
||||
import net.corda.nodeapi.ArtemisMessagingComponent
|
||||
import net.corda.webserver.WebServerConfig
|
||||
import net.corda.webserver.services.WebServerPluginRegistry
|
||||
@ -127,8 +128,13 @@ class NodeWebServer(val config: WebServerConfig) {
|
||||
addServlet(DataUploadServlet::class.java, "/upload/*")
|
||||
addServlet(AttachmentDownloadServlet::class.java, "/attachments/*")
|
||||
|
||||
val rpcObjectMapper = pluginRegistries.fold(JacksonSupport.createDefaultMapper(localRpc)) { om, plugin ->
|
||||
plugin.customizeJSONSerialization(om)
|
||||
om
|
||||
}
|
||||
|
||||
val resourceConfig = ResourceConfig()
|
||||
.register(ObjectMapperConfig(localRpc))
|
||||
.register(ObjectMapperConfig(rpcObjectMapper))
|
||||
.register(ResponseFilter())
|
||||
.register(APIServerImpl(localRpc))
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.webserver.services
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import java.util.function.Function
|
||||
|
||||
@ -21,4 +22,10 @@ interface WebServerPluginRegistry {
|
||||
*/
|
||||
val staticServeDirs: Map<String, String> get() = emptyMap()
|
||||
|
||||
/**
|
||||
* Optionally register extra JSON serializers to the default ObjectMapper provider
|
||||
* @param om The [ObjectMapper] to register custom types against.
|
||||
*/
|
||||
fun customizeJSONSerialization(om: ObjectMapper): Unit {}
|
||||
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
package net.corda.webserver.servlets
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.jackson.JacksonSupport
|
||||
import javax.ws.rs.ext.ContextResolver
|
||||
import javax.ws.rs.ext.Provider
|
||||
|
||||
@ -11,7 +9,6 @@ import javax.ws.rs.ext.Provider
|
||||
* and to organise serializers / deserializers for java.time.* classes as necessary.
|
||||
*/
|
||||
@Provider
|
||||
class ObjectMapperConfig(rpc: CordaRPCOps) : ContextResolver<ObjectMapper> {
|
||||
val defaultObjectMapper = JacksonSupport.createDefaultMapper(rpc)
|
||||
class ObjectMapperConfig(val defaultObjectMapper: ObjectMapper) : ContextResolver<ObjectMapper> {
|
||||
override fun getContext(type: Class<*>) = defaultObjectMapper
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user