Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persistence sample #23

Merged
merged 2 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions java-samples/persistence-carinsurance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ There are two flow in this CorDapp:
### Running the app

In Corda 5, flows will be triggered via `POST /flow/{holdingidentityshorthash}` and flow result will need to be view at `GET /flow/{holdingidentityshorthash}/{clientrequestid}`
* holdingidentityshorthash: the id of the network participants, ie SanctionBody, Bob, Charlie and DodgyParty. You can view all the short hashes of the network member with another gradle task called `ListVNodes`
* holdingidentityshorthash: the id of the network participants, ie InsuranceCompany, and Charlie. You can view all the short hashes of the network member with another gradle task called `ListVNodes`
* clientrequestid: the id you specify in the flow requestBody when you trigger a flow.


### Running the flows

Pick Bob's VNode identity to issue the sanctions list
Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Bob's hash) and request body:
Pick InsuranceCompany's VNode identity to issue the sanctions list
Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(InsuranceCompany's hash) and request body:

{
"clientRequestId": "issue-1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
{
"x500Name" : "CN=Bob, OU=Test Dept, O=R3, L=London, C=GB",
"x500Name" : "CN=InsuranceCompany, OU=Test Dept, O=R3, L=London, C=GB",
"cpi" : "MyCorDapp"
},
{
Expand Down
103 changes: 103 additions & 0 deletions kotlin-samples/persistence-carinsurance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Car Insurance -- Persistence

This CorDapp demonstrates how Persistence works in Next Gen Corda.
Corda allows developers to create custom schema to store state data separately, so that it can be used for other functionality
like reporting etc.

Unlike Corda 4, Next Gen Corda doesn't have the QueryableState functionality, however it exposes the Persistence Service which
can be used to achieve similar result.

In this CorDapp we would use an Insurance state and persist its properties in a custom table in the database.
The Insurance state among other fields also contains an VehicleDetail object, which is the asset being insured.
We have used this VehicleDetail to demonstrate One-to-One relationship.
Similarly, we also have a list of Claim objects in the Insurance state which represents claims made against the insurance.
We use them to demonstrate One-to-Many relationship.

### Entities
The entities for the custom tables are defined in the `contracts` module in the package `com.r3.developers.samples.persistence.schema`.
The corresponding liquibase scripts can be found in the `workflows` module under `resources/migration`.

### Flows

There are two flow in this CorDapp:

1. `IssueInsuranceFlow`: It creates the insurance state with the associated vehicle information.

2. `InsuranceClaimFlow`: It creates the claims against the insurance.


## Usage

### Setting up

1. We will begin our test deployment with clicking the `startCorda`. This task will load up the combined Corda workers in docker.
A successful deployment will allow you to open the REST APIs at: https://localhost:8888/api/v1/swagger#. You can test out some
functions to check connectivity. (GET /cpi function call should return an empty list as for now.)
2. We will now deploy the cordapp with a click of `5-vNodeSetup` task. Upon successful deployment of the CPI, the GET /cpi function call should now return the meta data of the cpi you just upload



### Running the app

In Corda 5, flows will be triggered via `POST /flow/{holdingidentityshorthash}` and flow result will need to be view at `GET /flow/{holdingidentityshorthash}/{clientrequestid}`
* holdingidentityshorthash: the id of the network participants, ie InsuranceCompany, and Charlie. You can view all the short hashes of the network member with another gradle task called `ListVNodes`
* clientrequestid: the id you specify in the flow requestBody when you trigger a flow.


### Running the flows

Pick InsuranceCompany's VNode identity to issue the sanctions list
Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(InsuranceCompany's hash) and request body:

{
"clientRequestId": "issue-1",
"flowClassName": "com.r3.developers.samples.persistence.workflows.IssueInsuranceFlow",
"requestBody": {
"vehicleInfo": {
"registrationNumber": "MH7777",
"chasisNumber": "CH8771",
"make": "Hyundai",
"model": "i20",
"variant": "Asta",
"color": "grey",
"fuelType": "Petrol"
},
"policyNumber" : "P001",
"insuredValue": 500000,
"duration": 2,
"premium": 20000,
"insuree": "CN=Charlie, OU=Test Dept, O=R3, L=London, C=GB"
}
}

This should create the insurance state and the state data should also have been persisted in the custom tables.

Now in order to add claims, Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Charlie's hash) and request body:

{
"clientRequestId": "claim-1",
"flowClassName": "com.r3.developers.samples.persistence.workflows.InsuranceClaimFlow",
"requestBody": {
"policyNumber" : "P001",
"claimNumber": "CM001",
"claimDescription": "Simple Claim",
"claimAmount": 50000
}
}

This should add claims to the insurance and it can be viewed in the custom database tables.

### Connecting to the Database
To connect to the postgres database, you could use any db explorer of your choice.
Below image shows the connection details:
<p align="center">
<img src="./db-details.png" alt="Database URL" width="400">
</p>

The password is `password`.

A schema would have been created for each vNode in the format: `vnode_vault_<identity_short_hash>`. The image
below highlights the custom tables created in the database.
<p align="center">
<img src="./db-tables.png" alt="Database URL" width="400">
</p>
84 changes: 84 additions & 0 deletions kotlin-samples/persistence-carinsurance/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import static org.gradle.api.JavaVersion.VERSION_11

plugins {
id 'org.jetbrains.kotlin.jvm'
id 'net.corda.cordapp.cordapp-configuration'
id 'org.jetbrains.kotlin.plugin.jpa'
id 'java'
id 'maven-publish'
id 'net.corda.plugins.csde'
}

allprojects {
group 'com.r3.developers.samples'
version '1.0-SNAPSHOT'

def javaVersion = VERSION_11

// Configure the CSDE
csde {
cordaClusterURL = "https://localhost:8888"
networkConfigFile = "config/static-network-config.json"
r3RootCertFile = "config/r3-ca-key.pem"
corDappCpiName = "MyCorDapp"
notaryCpiName = "NotaryServer"
cordaRpcUser = "admin"
cordaRpcPasswd ="admin"
workflowsModuleName = workflowsModule
csdeWorkspaceDir = "workspace"
notaryVersion = cordaNotaryPluginsVersion
combinedWorkerVersion = combinedWorkerJarVersion
postgresJdbcVersion = "42.4.3"
cordaDbContainerName = "CSDEpostgresql"
cordaBinDir = "${System.getProperty("user.home")}/.corda/corda5"
cordaCliBinDir = "${System.getProperty("user.home")}/.corda/cli"
}

// Declare the set of Kotlin compiler options we need to build a CorDapp.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
allWarningsAsErrors = false

// Specify the version of Kotlin that we are that we will be developing.
languageVersion = '1.7'
// Specify the Kotlin libraries that code is compatible with
apiVersion = '1.7'
// Note that we Need to use a version of Kotlin that will be compatible with the Corda API.
// Currently that is developed in Kotlin 1.7 so picking the same version ensures compatibility with that.

// Specify the version of Java to target.
jvmTarget = javaVersion

// Needed for reflection to work correctly.
javaParameters = true

// -Xjvm-default determines how Kotlin supports default methods.
// JetBrains currently recommends developers use -Xjvm-default=all
// https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/
freeCompilerArgs += [
"-Xjvm-default=all"
]
}
}

repositories {
// All dependencies are held in Maven Central
mavenLocal()
mavenCentral()
}

tasks.withType(Test).configureEach {
useJUnitPlatform()
}

}

publishing {
publications {
maven(MavenPublication) {
artifactId "corda5-persistence-cordapp"
groupId project.group
artifact jar
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB7zCCAZOgAwIBAgIEFyV7dzAMBggqhkjOPQQDAgUAMFsxCzAJBgNVBAYTAkdC
MQ8wDQYDVQQHDAZMb25kb24xDjAMBgNVBAoMBUNvcmRhMQswCQYDVQQLDAJSMzEe
MBwGA1UEAwwVQ29yZGEgRGV2IENvZGUgU2lnbmVyMB4XDTIwMDYyNTE4NTI1NFoX
DTMwMDYyMzE4NTI1NFowWzELMAkGA1UEBhMCR0IxDzANBgNVBAcTBkxvbmRvbjEO
MAwGA1UEChMFQ29yZGExCzAJBgNVBAsTAlIzMR4wHAYDVQQDExVDb3JkYSBEZXYg
Q29kZSBTaWduZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQDjSJtzQ+ldDFt
pHiqdSJebOGPZcvZbmC/PIJRsZZUF1bl3PfMqyG3EmAe0CeFAfLzPQtf2qTAnmJj
lGTkkQhxo0MwQTATBgNVHSUEDDAKBggrBgEFBQcDAzALBgNVHQ8EBAMCB4AwHQYD
VR0OBBYEFLMkL2nlYRLvgZZq7GIIqbe4df4pMAwGCCqGSM49BAMCBQADSAAwRQIh
ALB0ipx6EplT1fbUKqgc7rjH+pV1RQ4oKF+TkfjPdxnAAiArBdAI15uI70wf+xlL
zU+Rc5yMtcOY4/moZUq36r0Ilg==
-----END CERTIFICATE-----
51 changes: 51 additions & 0 deletions kotlin-samples/persistence-carinsurance/config/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} %X - %msg%n"/>
</Console>

<RollingFile name="App"
fileName="logs/corda.log"
filePattern="logs/corda.%d{MM-dd-yyyy}.%i.log"
ignoreExceptions="false">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} %X - %msg%n"/>
<Policies>
<OnStartupTriggeringPolicy />
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="logs/">
<IfFileName glob="logs/corda.*.log">
<IfAny>
<IfAccumulatedFileSize exceeds="500 MB" />
<IfAccumulatedFileCount exceeds="10" />
</IfAny>
</IfFileName>
<IfLastModified age="7d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<logger name="Console">
<AppenderRef ref="Console" level="info"/>
</logger>

<!-- log warn only for these 3rd party libs -->
<Logger name="com.zaxxer.hikari" level="warn" />
<Logger name="io.javalin.Javalin" level="warn" />
<Logger name="org.apache.aries.spifly" level="warn" />
<Logger name="org.apache.kafka" level="warn" />
<Logger name="org.eclipse.jetty" level="warn" />
<Logger name="org.hibernate" level="warn" />

<!-- default to warn only for OSGi logging -->
<Logger name="net.corda.osgi.framework.OSGiFrameworkWrap" level="warn" />

<root level="debug">
<AppenderRef ref="App" level="info"/>
</root>
</Loggers>
</Configuration>
32 changes: 32 additions & 0 deletions kotlin-samples/persistence-carinsurance/config/r3-ca-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"x500Name" : "CN=InsuranceCompany, OU=Test Dept, O=R3, L=London, C=GB",
"cpi" : "MyCorDapp"
},
{
"x500Name" : "CN=Charlie, OU=Test Dept, O=R3, L=London, C=GB",
"cpi" : "MyCorDapp"
},
{
"x500Name" : "CN=NotaryRep1, OU=Test Dept, O=R3, L=London, C=GB",
"cpi" : "NotaryServer",
"serviceX500Name": "CN=NotaryService, OU=Test Dept, O=R3, L=London, C=GB"
}
]
Loading