Explorer advertising service fix (#1576)

* WIP
added a helper method to convert ObservableValue<List> to ObservableList

(cherry picked from commit 75306aa)

* Fix for cash explorer after advertising service removal

(cherry picked from commit 59d0278)

* remove unused changes

* address PR issues

* fixup after rebase

* fix CashState name rendering issue
added flow permission to gradle config
This commit is contained in:
Patrick Kuo 2017-09-21 13:27:05 +01:00 committed by josecoll
parent 33421bdd44
commit 80b3411fa5
13 changed files with 97 additions and 58 deletions

View File

@ -5,19 +5,20 @@ import com.google.common.cache.CacheLoader
import javafx.beans.value.ObservableValue import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections import javafx.collections.FXCollections
import javafx.collections.ObservableList import javafx.collections.ObservableList
import net.corda.client.jfx.utils.filterNotNull
import net.corda.client.jfx.utils.fold import net.corda.client.jfx.utils.fold
import net.corda.client.jfx.utils.map import net.corda.client.jfx.utils.map
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache.MapChange import net.corda.core.node.services.NetworkMapCache.MapChange
import net.corda.nodeapi.ServiceType
import java.security.PublicKey import java.security.PublicKey
class NetworkIdentityModel { class NetworkIdentityModel {
private val networkIdentityObservable by observable(NodeMonitorModel::networkMap) private val networkIdentityObservable by observable(NodeMonitorModel::networkMap)
val networkIdentities: ObservableList<NodeInfo> = private val networkIdentities: ObservableList<NodeInfo> =
networkIdentityObservable.fold(FXCollections.observableArrayList()) { list, update -> networkIdentityObservable.fold(FXCollections.observableArrayList()) { list, update ->
list.removeIf { list.removeIf {
when (update) { when (update) {
@ -32,13 +33,15 @@ class NetworkIdentityModel {
private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable) private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable)
private val identityCache = CacheBuilder.newBuilder() private val identityCache = CacheBuilder.newBuilder()
.build<PublicKey, ObservableValue<NodeInfo?>>(CacheLoader.from { .build<PublicKey, ObservableValue<NodeInfo?>>(CacheLoader.from { publicKey ->
publicKey ->
publicKey?.let { rpcProxy.map { it?.nodeInfoFromParty(AnonymousParty(publicKey)) } } publicKey?.let { rpcProxy.map { it?.nodeInfoFromParty(AnonymousParty(publicKey)) } }
}) })
val notaries: ObservableList<Party> = FXCollections.observableList(rpcProxy.value?.notaryIdentities()) val notaries: ObservableList<Party> = networkIdentities.map {
val notaryNodes: ObservableList<NodeInfo> = FXCollections.observableList(notaries.map { rpcProxy.value?.nodeInfoFromParty(it) }) it.legalIdentitiesAndCerts.find { it.name.commonName?.let { ServiceType.parse(it).isNotary() } ?: false }
}.map { it?.party }.filterNotNull()
val notaryNodes: ObservableList<NodeInfo> = notaries.map { rpcProxy.value?.nodeInfoFromParty(it) }.filterNotNull()
val parties: ObservableList<NodeInfo> = networkIdentities.filtered { it.legalIdentities.all { it !in notaries } } val parties: ObservableList<NodeInfo> = networkIdentities.filtered { it.legalIdentities.all { it !in notaries } }
val myIdentity = rpcProxy.map { it?.nodeInfo()?.legalIdentitiesAndCerts?.first()?.party } val myIdentity = rpcProxy.map { it?.nodeInfo()?.legalIdentitiesAndCerts?.first()?.party }

View File

@ -353,4 +353,4 @@ fun <T : ContractState> DataFeed<Vault.Page<T>, Vault.Update<T>>.toFXListOfState
*/ */
fun <T : ContractState> DataFeed<Vault.Page<T>, Vault.Update<T>>.toFXListOfStates(): ObservableList<T> { fun <T : ContractState> DataFeed<Vault.Page<T>, Vault.Update<T>>.toFXListOfStates(): ObservableList<T> {
return toFXListOfStateRefs().map { it.state.data } return toFXListOfStateRefs().map { it.state.data }
} }

View File

@ -0,0 +1,40 @@
package net.corda.finance.flows
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.flows.FlowException
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC
import net.corda.core.serialization.CordaSerializable
import net.corda.finance.CHF
import net.corda.finance.EUR
import net.corda.finance.GBP
import net.corda.finance.USD
import java.util.*
/**
* Flow to obtain cash cordapp app configuration.
*/
@StartableByRPC
class CashConfigDataFlow : FlowLogic<CashConfiguration>() {
companion object {
private val supportedCurrencies = listOf(USD, GBP, CHF, EUR)
}
@Suspendable
override fun call(): CashConfiguration {
val issuableCurrencies = supportedCurrencies.mapNotNull {
try {
// Currently it uses checkFlowPermission to determine the list of issuable currency as a temporary hack.
// TODO: get the config from proper configuration source.
checkFlowPermission("corda.issuer.$it", emptyMap())
it
} catch (e: FlowException) {
null
}
}
return CashConfiguration(issuableCurrencies, supportedCurrencies)
}
}
@CordaSerializable
data class CashConfiguration(val issuableCurrencies: List<Currency>, val supportedCurrencies: List<Currency>)

View File

@ -23,6 +23,7 @@ import net.corda.core.utilities.*
import net.corda.node.services.api.FlowAppAuditEvent import net.corda.node.services.api.FlowAppAuditEvent
import net.corda.node.services.api.FlowPermissionAuditEvent import net.corda.node.services.api.FlowPermissionAuditEvent
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.statemachine.FlowSessionState.Initiating import net.corda.node.services.statemachine.FlowSessionState.Initiating
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.DatabaseTransaction import net.corda.node.utilities.DatabaseTransaction
@ -260,7 +261,10 @@ class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
// TODO Dummy implementation of access to application specific permission controls and audit logging // TODO Dummy implementation of access to application specific permission controls and audit logging
override fun checkFlowPermission(permissionName: String, extraAuditData: Map<String, String>) { override fun checkFlowPermission(permissionName: String, extraAuditData: Map<String, String>) {
val permissionGranted = true // TODO define permission control service on ServiceHubInternal and actually check authorization. // This is a hack to allow cash app access list of permitted issuer currency.
// TODO: replace this with cordapp configuration.
val config = serviceHub.configuration as? FullNodeConfiguration
val permissionGranted = config?.extraAdvertisedServiceIds?.contains(permissionName) ?: true
val checkPermissionEvent = FlowPermissionAuditEvent( val checkPermissionEvent = FlowPermissionAuditEvent(
serviceHub.clock.instant(), serviceHub.clock.instant(),
flowInitiator, flowInitiator,

View File

@ -69,6 +69,7 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
['username' : "bankUser", ['username' : "bankUser",
'password' : "test", 'password' : "test",
'permissions': ["StartFlow.net.corda.finance.flows.CashPaymentFlow", 'permissions': ["StartFlow.net.corda.finance.flows.CashPaymentFlow",
"StartFlow.net.corda.finance.flows.CashConfigDataFlow",
"StartFlow.net.corda.finance.flows.CashExitFlow", "StartFlow.net.corda.finance.flows.CashExitFlow",
"StartFlow.net.corda.finance.flows.CashIssueAndPaymentFlow"]] "StartFlow.net.corda.finance.flows.CashIssueAndPaymentFlow"]]
] ]

View File

@ -17,16 +17,13 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.GBP import net.corda.finance.GBP
import net.corda.finance.USD import net.corda.finance.USD
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.AbstractCashFlow import net.corda.finance.flows.*
import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashExitFlow.ExitRequest import net.corda.finance.flows.CashExitFlow.ExitRequest
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.FlowPermissions.Companion.startFlowPermission import net.corda.node.services.FlowPermissions.Companion.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.ServiceInfo import net.corda.nodeapi.ServiceInfo
import net.corda.nodeapi.ServiceType import net.corda.nodeapi.ServiceType
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.testing.ALICE import net.corda.testing.ALICE
import net.corda.testing.BOB import net.corda.testing.BOB
@ -39,12 +36,14 @@ import java.util.*
class ExplorerSimulation(val options: OptionSet) { class ExplorerSimulation(val options: OptionSet) {
private val user = User("user1", "test", permissions = setOf( private val user = User("user1", "test", permissions = setOf(
startFlowPermission<CashPaymentFlow>() startFlowPermission<CashPaymentFlow>(),
startFlowPermission<CashConfigDataFlow>()
)) ))
private val manager = User("manager", "test", permissions = setOf( private val manager = User("manager", "test", permissions = setOf(
startFlowPermission<CashIssueAndPaymentFlow>(), startFlowPermission<CashIssueAndPaymentFlow>(),
startFlowPermission<CashPaymentFlow>(), startFlowPermission<CashPaymentFlow>(),
startFlowPermission<CashExitFlow>()) startFlowPermission<CashExitFlow>(),
startFlowPermission<CashConfigDataFlow>())
) )
private lateinit var notaryNode: NodeHandle private lateinit var notaryNode: NodeHandle
@ -122,7 +121,7 @@ class ExplorerSimulation(val options: OptionSet) {
val issuerRPCGBP = issuerGBPConnection.proxy val issuerRPCGBP = issuerGBPConnection.proxy
val issuerClientUSD = issuerNodeUSD.rpcClientToNode() val issuerClientUSD = issuerNodeUSD.rpcClientToNode()
val issuerUSDConnection =issuerClientUSD.start(manager.username, manager.password) val issuerUSDConnection = issuerClientUSD.start(manager.username, manager.password)
val issuerRPCUSD = issuerUSDConnection.proxy val issuerRPCUSD = issuerUSDConnection.proxy
RPCConnections.addAll(listOf(aliceConnection, bobConnection, issuerGBPConnection, issuerUSDConnection)) RPCConnections.addAll(listOf(aliceConnection, bobConnection, issuerGBPConnection, issuerUSDConnection))

View File

@ -1,34 +1,25 @@
package net.corda.explorer.model package net.corda.explorer.model
import javafx.collections.FXCollections import javafx.collections.FXCollections
import javafx.collections.ObservableList import net.corda.client.jfx.model.NodeMonitorModel
import net.corda.client.jfx.model.NetworkIdentityModel
import net.corda.client.jfx.model.observableList
import net.corda.client.jfx.model.observableValue import net.corda.client.jfx.model.observableValue
import net.corda.client.jfx.utils.ChosenList import net.corda.client.jfx.utils.ChosenList
import net.corda.client.jfx.utils.map import net.corda.client.jfx.utils.map
import net.corda.core.identity.Party import net.corda.core.messaging.startFlow
import net.corda.core.node.NodeInfo import net.corda.core.utilities.getOrThrow
import net.corda.finance.flows.CashConfigDataFlow
import tornadofx.* import tornadofx.*
val ISSUER_SERVICE_TYPE = Regex("corda.issuer.(USD|GBP|CHF|EUR)")
class IssuerModel { class IssuerModel {
// TODO Explorer will be fixed as separate PR. private val proxy by observableValue(NodeMonitorModel::proxyObservable)
private val networkIdentities by observableList(NetworkIdentityModel::networkIdentities) private val cashAppConfiguration = proxy.map { it?.startFlow(::CashConfigDataFlow)?.returnValue?.getOrThrow() }
private val myIdentity by observableValue(NetworkIdentityModel::myIdentity) val supportedCurrencies = ChosenList(cashAppConfiguration.map { it?.supportedCurrencies?.observable() ?: FXCollections.emptyObservableList() })
private val supportedCurrencies by observableList(ReportingCurrencyModel::supportedCurrencies) val currencyTypes = ChosenList(cashAppConfiguration.map { it?.issuableCurrencies?.observable() ?: FXCollections.emptyObservableList() })
val issuers: ObservableList<NodeInfo> = FXCollections.observableList(networkIdentities) val transactionTypes = ChosenList(cashAppConfiguration.map {
if (it?.issuableCurrencies?.isNotEmpty() == true)
val currencyTypes = ChosenList(myIdentity.map { supportedCurrencies })
val transactionTypes = ChosenList(myIdentity.map {
if (it?.isIssuerNode() ?: false)
CashTransaction.values().asList().observable() CashTransaction.values().asList().observable()
else else
listOf(CashTransaction.Pay).observable() listOf(CashTransaction.Pay).observable()
}) })
private fun Party.isIssuerNode() = true
} }

View File

@ -16,8 +16,7 @@ import java.util.*
class ReportingCurrencyModel { class ReportingCurrencyModel {
private val exchangeRate: ObservableValue<ExchangeRate> by observableValue(ExchangeRateModel::exchangeRate) private val exchangeRate: ObservableValue<ExchangeRate> by observableValue(ExchangeRateModel::exchangeRate)
val reportingCurrency by observableValue(SettingsModel::reportingCurrencyProperty) private val reportingCurrency by observableValue(SettingsModel::reportingCurrencyProperty)
val supportedCurrencies = setOf(USD, GBP, CHF, EUR).toList().observable()
/** /**
* This stream provides a stream of exchange() functions that updates when either the reporting currency or the * This stream provides a stream of exchange() functions that updates when either the reporting currency or the

View File

@ -9,6 +9,7 @@ import javafx.beans.property.SimpleObjectProperty
import javafx.beans.value.ObservableValue import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections import javafx.collections.FXCollections
import javafx.geometry.Bounds import javafx.geometry.Bounds
import javafx.geometry.Insets
import javafx.geometry.Point2D import javafx.geometry.Point2D
import javafx.scene.Parent import javafx.scene.Parent
import javafx.scene.control.Button import javafx.scene.control.Button
@ -35,6 +36,7 @@ import net.corda.explorer.model.CordaView
import net.corda.finance.utils.CityDatabase import net.corda.finance.utils.CityDatabase
import net.corda.finance.utils.ScreenCoordinate import net.corda.finance.utils.ScreenCoordinate
import net.corda.finance.utils.WorldMapLocation import net.corda.finance.utils.WorldMapLocation
import net.corda.nodeapi.ServiceType
import tornadofx.* import tornadofx.*
class Network : CordaView() { class Network : CordaView() {
@ -91,15 +93,19 @@ class Network : CordaView() {
val node = this val node = this
val identities = node.legalIdentitiesAndCerts.sortedBy { it.owningKey.toBase58String() } val identities = node.legalIdentitiesAndCerts.sortedBy { it.owningKey.toBase58String() }
return button { return button {
minWidth = 300.0
padding = Insets(10.0)
useMaxWidth = true useMaxWidth = true
graphic = vbox { graphic = vbox {
label(PartyNameFormatter.short.format(identities[0].name)) { font = Font.font(font.family, FontWeight.BOLD, 15.0) } label(PartyNameFormatter.short.format(identities[0].name)) { font = Font.font(font.family, FontWeight.BOLD, 15.0) }
gridpane { // TODO We lose node's main identity for display. gridpane {
// TODO We lose node's main identity for display.
hgap = 5.0 hgap = 5.0
vgap = 5.0 vgap = 5.0
for (identity in identities) { for (identity in identities) {
row(PartyNameFormatter.short.format(identity.name)) { val isNotary = identity.name.commonName?.let { ServiceType.parse(it).isNotary() } ?: false
copyableLabel(SimpleObjectProperty(identity.owningKey.toBase58String())).apply { minWidth = 400.0 } row("${if (isNotary) "Notary " else ""}Public Key :") {
copyableLabel(SimpleObjectProperty(identity.owningKey.toBase58String()))
} }
} }
node.getWorldMapLocation()?.apply { row("Location :") { label(this@apply.description) } } node.getWorldMapLocation()?.apply { row("Location :") { label(this@apply.description) } }
@ -114,7 +120,7 @@ class Network : CordaView() {
private fun NodeInfo.render(): MapViewComponents { private fun NodeInfo.render(): MapViewComponents {
val node = this val node = this
val identities = node.legalIdentitiesAndCerts.sortedBy { it.owningKey.toBase58String() } val identities = node.legalIdentitiesAndCerts.sortedBy { it.owningKey.toBase58String() }
val mapLabel = label(PartyNameFormatter.short.format(identities[0].name)) // We choose the first one for the name of the node on the map. val mapLabel = label(PartyNameFormatter.short.format(identities.first().name)) // We choose the first one for the name of the node on the map.
mapPane.add(mapLabel) mapPane.add(mapLabel)
// applyCss: This method does not normally need to be invoked directly but may be used in conjunction with Parent.layout() // applyCss: This method does not normally need to be invoked directly but may be used in conjunction with Parent.layout()
// to size a Node before the next pulse, or if the Scene is not in a Stage. // to size a Node before the next pulse, or if the Scene is not in a Stage.

View File

@ -12,6 +12,7 @@ import net.corda.client.jfx.model.objectProperty
import net.corda.client.jfx.model.observableList import net.corda.client.jfx.model.observableList
import net.corda.client.jfx.utils.map import net.corda.client.jfx.utils.map
import net.corda.explorer.model.CordaView import net.corda.explorer.model.CordaView
import net.corda.explorer.model.IssuerModel
import net.corda.explorer.model.ReportingCurrencyModel import net.corda.explorer.model.ReportingCurrencyModel
import net.corda.explorer.model.SettingsModel import net.corda.explorer.model.SettingsModel
import java.util.* import java.util.*
@ -22,7 +23,7 @@ class Settings : CordaView() {
override val icon = FontAwesomeIcon.COGS override val icon = FontAwesomeIcon.COGS
// Inject Data. // Inject Data.
private val currencies by observableList(ReportingCurrencyModel::supportedCurrencies) private val currencies by observableList(IssuerModel::supportedCurrencies)
private val reportingCurrencies by objectProperty(SettingsModel::reportingCurrencyProperty) private val reportingCurrencies by objectProperty(SettingsModel::reportingCurrencyProperty)
private val rememberMe by objectProperty(SettingsModel::rememberMeProperty) private val rememberMe by objectProperty(SettingsModel::rememberMeProperty)
private val fullscreen by objectProperty(SettingsModel::fullscreenProperty) private val fullscreen by objectProperty(SettingsModel::fullscreenProperty)

View File

@ -26,7 +26,6 @@ import net.corda.core.crypto.toStringShort
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.toBase58String import net.corda.core.utilities.toBase58String
import net.corda.explorer.AmountDiff import net.corda.explorer.AmountDiff
import net.corda.explorer.formatters.AmountFormatter import net.corda.explorer.formatters.AmountFormatter
@ -37,6 +36,7 @@ import net.corda.explorer.identicon.identiconToolTip
import net.corda.explorer.model.CordaView import net.corda.explorer.model.CordaView
import net.corda.explorer.model.CordaWidget import net.corda.explorer.model.CordaWidget
import net.corda.explorer.model.ReportingCurrencyModel import net.corda.explorer.model.ReportingCurrencyModel
import net.corda.explorer.model.SettingsModel
import net.corda.explorer.sign import net.corda.explorer.sign
import net.corda.explorer.ui.setCustomCellFactory import net.corda.explorer.ui.setCustomCellFactory
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
@ -52,7 +52,7 @@ class TransactionViewer : CordaView("Transactions") {
// Inject data // Inject data
private val transactions by observableListReadOnly(TransactionDataModel::partiallyResolvedTransactions) private val transactions by observableListReadOnly(TransactionDataModel::partiallyResolvedTransactions)
private val reportingExchange by observableValue(ReportingCurrencyModel::reportingExchange) private val reportingExchange by observableValue(ReportingCurrencyModel::reportingExchange)
private val reportingCurrency by observableValue(ReportingCurrencyModel::reportingCurrency) private val reportingCurrency by observableValue(SettingsModel::reportingCurrencyProperty)
private val myIdentity by observableValue(NetworkIdentityModel::myIdentity) private val myIdentity by observableValue(NetworkIdentityModel::myIdentity)
override val widgets = listOf(CordaWidget(title, TransactionWidget(), icon)).observable() override val widgets = listOf(CordaWidget(title, TransactionWidget(), icon)).observable()
@ -260,7 +260,7 @@ class TransactionViewer : CordaView("Transactions") {
vgap = 10.0 vgap = 10.0
hgap = 10.0 hgap = 10.0
row { row {
label("${contractState.contract().javaClass.simpleName} (${contractState.ref.toString().substring(0, 16)}...)[${contractState.ref.index}]") { label("${contractState.contract()} (${contractState.ref.toString().substring(0, 16)}...)[${contractState.ref.index}]") {
graphic = identicon(contractState.ref.txhash, 30.0) graphic = identicon(contractState.ref.txhash, 30.0)
tooltip = identiconToolTip(contractState.ref.txhash) tooltip = identiconToolTip(contractState.ref.txhash)
gridpaneConstraints { columnSpan = 2 } gridpaneConstraints { columnSpan = 2 }
@ -298,8 +298,7 @@ class TransactionViewer : CordaView("Transactions") {
} }
} }
private fun StateAndRef<ContractState>.contract() = this.state.contract private fun StateAndRef<ContractState>.contract() = this.state.contract.split(".").last()
} }
/** /**

View File

@ -13,10 +13,7 @@ import javafx.scene.text.Font
import javafx.scene.text.FontWeight import javafx.scene.text.FontWeight
import javafx.stage.Window import javafx.stage.Window
import net.corda.client.jfx.model.* import net.corda.client.jfx.model.*
import net.corda.client.jfx.utils.ChosenList import net.corda.client.jfx.utils.*
import net.corda.client.jfx.utils.isNotNull
import net.corda.client.jfx.utils.map
import net.corda.client.jfx.utils.unique
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.contracts.Amount.Companion.sumOrNull import net.corda.core.contracts.Amount.Companion.sumOrNull
import net.corda.core.contracts.withoutIssuer import net.corda.core.contracts.withoutIssuer
@ -31,10 +28,10 @@ import net.corda.core.utilities.getOrThrow
import net.corda.explorer.formatters.PartyNameFormatter import net.corda.explorer.formatters.PartyNameFormatter
import net.corda.explorer.model.CashTransaction import net.corda.explorer.model.CashTransaction
import net.corda.explorer.model.IssuerModel import net.corda.explorer.model.IssuerModel
import net.corda.explorer.model.ReportingCurrencyModel
import net.corda.explorer.views.bigDecimalFormatter import net.corda.explorer.views.bigDecimalFormatter
import net.corda.explorer.views.byteFormatter import net.corda.explorer.views.byteFormatter
import net.corda.explorer.views.stringConverter import net.corda.explorer.views.stringConverter
import net.corda.explorer.views.toKnownParty
import net.corda.finance.flows.AbstractCashFlow import net.corda.finance.flows.AbstractCashFlow
import net.corda.finance.flows.CashExitFlow import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashExitFlow.ExitRequest import net.corda.finance.flows.CashExitFlow.ExitRequest
@ -42,7 +39,6 @@ import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest import net.corda.finance.flows.CashIssueAndPaymentFlow.IssueAndPaymentRequest
import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.finance.flows.CashPaymentFlow.PaymentRequest import net.corda.finance.flows.CashPaymentFlow.PaymentRequest
import net.corda.testing.chooseIdentity
import net.corda.testing.chooseIdentityAndCert import net.corda.testing.chooseIdentityAndCert
import org.controlsfx.dialog.ExceptionDialog import org.controlsfx.dialog.ExceptionDialog
import tornadofx.* import tornadofx.*
@ -71,15 +67,15 @@ class NewTransaction : Fragment() {
private val issueRef = SimpleObjectProperty<Byte>() private val issueRef = SimpleObjectProperty<Byte>()
// Inject data // Inject data
private val parties by observableList(NetworkIdentityModel::parties) private val parties by observableList(NetworkIdentityModel::parties)
private val issuers by observableList(IssuerModel::issuers)
private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable) private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable)
private val myIdentity by observableValue(NetworkIdentityModel::myIdentity) private val myIdentity by observableValue(NetworkIdentityModel::myIdentity)
private val notaries by observableList(NetworkIdentityModel::notaries) private val notaries by observableList(NetworkIdentityModel::notaries)
private val cash by observableList(ContractStateModel::cash) private val cash by observableList(ContractStateModel::cash)
private val executeButton = ButtonType("Execute", ButtonBar.ButtonData.APPLY) private val executeButton = ButtonType("Execute", ButtonBar.ButtonData.APPLY)
private val currencyTypes by observableList(IssuerModel::currencyTypes) private val currencyTypes by observableList(IssuerModel::currencyTypes)
private val supportedCurrencies by observableList(ReportingCurrencyModel::supportedCurrencies) private val supportedCurrencies by observableList(IssuerModel::supportedCurrencies)
private val transactionTypes by observableList(IssuerModel::transactionTypes) private val transactionTypes by observableList(IssuerModel::transactionTypes)
private val issuers = cash.map { it.token.issuer }
private val currencyItems = ChosenList(transactionTypeCB.valueProperty().map { private val currencyItems = ChosenList(transactionTypeCB.valueProperty().map {
when (it) { when (it) {
@ -156,7 +152,7 @@ class NewTransaction : Fragment() {
val issueRef = if (issueRef.value != null) OpaqueBytes.of(issueRef.value) else defaultRef val issueRef = if (issueRef.value != null) OpaqueBytes.of(issueRef.value) else defaultRef
when (it) { when (it) {
executeButton -> when (transactionTypeCB.value) { executeButton -> when (transactionTypeCB.value) {
CashTransaction.Issue -> IssueAndPaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.party, notaries.first(), anonymous) CashTransaction.Issue -> IssueAndPaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef, partyBChoiceBox.value.party, notaries.first().value!!, anonymous)
CashTransaction.Pay -> PaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), partyBChoiceBox.value.party, anonymous = anonymous) CashTransaction.Pay -> PaymentRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), partyBChoiceBox.value.party, anonymous = anonymous)
CashTransaction.Exit -> ExitRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef) CashTransaction.Exit -> ExitRequest(Amount.fromDecimal(amount.value, currencyChoiceBox.value), issueRef)
else -> null else -> null
@ -192,7 +188,7 @@ class NewTransaction : Fragment() {
issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull) issuerLabel.visibleProperty().bind(transactionTypeCB.valueProperty().isNotNull)
// TODO This concept should burn (after services removal...) // TODO This concept should burn (after services removal...)
issuerChoiceBox.apply { issuerChoiceBox.apply {
items = issuers.map { it.chooseIdentity() }.unique().sorted() items = issuers.map { it.party.owningKey.toKnownParty().value }.filterNotNull().unique().sorted()
converter = stringConverter { PartyNameFormatter.short.format(it.name) } converter = stringConverter { PartyNameFormatter.short.format(it.name) }
visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay }) visibleProperty().bind(transactionTypeCB.valueProperty().map { it == CashTransaction.Pay })
} }

View File

@ -19,7 +19,7 @@
<Insets bottom="25" left="5" right="5" top="5"/> <Insets bottom="25" left="5" right="5" top="5"/>
</StackPane.margin> </StackPane.margin>
<TitledPane styleClass="networkTile" text="My Identity"> <TitledPane styleClass="networkTile" text="My Identity">
<BorderPane fx:id="myIdentityPane" minHeight="150"/> <BorderPane fx:id="myIdentityPane"/>
</TitledPane> </TitledPane>
<TitledPane styleClass="networkTile" text="Notaries"> <TitledPane styleClass="networkTile" text="Notaries">
<BorderPane minHeight="150"> <BorderPane minHeight="150">