mirror of
https://github.com/corda/corda.git
synced 2025-02-20 17:33:15 +00:00
Merge pull request #1265 from corda/mnesbit-nofinance-jacksonapi
Remove finance dependencies in node and client/jackson and make finance a CorDapp.
This commit is contained in:
commit
82173bc1a7
@ -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…
x
Reference in New Issue
Block a user