Example cordapp works on a corda cluster. Added getter methods for Data transfer objects, added default constructors.

This commit is contained in:
Chris Barratt 2022-10-13 17:50:50 +01:00
parent a15efd43a1
commit 69f578a147
7 changed files with 50 additions and 16 deletions

View File

@ -45,6 +45,7 @@ cordapp {
} }
} }
/*
// Declare the set of Kotlin compiler options we need to build a CorDapp. // Declare the set of Kotlin compiler options we need to build a CorDapp.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions { kotlinOptions {
@ -72,6 +73,19 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
} }
} }
*/
// Declare the set of Kotlin compiler options we need to build a CorDapp.
tasks.withType(JavaCompile) {
// -parameters - Needed for reflection and serialization to work correctly.
options.compilerArgs += [
"-parameters"
]
}
repositories { repositories {
// All dependencies are held in Maven Central // All dependencies are held in Maven Central
mavenCentral() mavenCentral()
@ -134,7 +148,7 @@ test {
publishing { publishing {
publications { publications {
maven(MavenPublication) { maven(MavenPublication) {
artifactId "corda-CSDE-kotlin-sample" artifactId "corda-CSDE-java-sample"
groupId project.group groupId project.group
artifact jar artifact jar
} }

View File

@ -2,7 +2,6 @@ import com.r3.csde.CsdeRpcInterface
plugins { plugins {
id 'java-library' id 'java-library'
id 'checkstyle'
id 'groovy' id 'groovy'
id 'java' id 'java'
} }
@ -37,7 +36,7 @@ def cordaJDBCDir = cordaBinDir + "/jdbcDrivers"
def signingCertAlias="gradle-plugin-default-key" def signingCertAlias="gradle-plugin-default-key"
// Get error if this is not a autotyped object // Get error if this is not a autotyped object
// def signingCertFName = "$rootDir/config/gradle-plugin-default-key.pem" // def signingCertFName = "$rootDir/config/gradle-plugin-default-key.pem"
def signingCertFName = rootDir.toString() + "/csde-config/gradle-plugin-default-key.pem" def signingCertFName = rootDir.toString() + "/config/gradle-plugin-default-key.pem"
def keystoreAlias = "my-signing-key" def keystoreAlias = "my-signing-key"
def keystoreFName = devEnvWorkspace + "/signingkeys.pfx" def keystoreFName = devEnvWorkspace + "/signingkeys.pfx"
def keystoreCertFName = devEnvWorkspace + "/signingkey1.pem" def keystoreCertFName = devEnvWorkspace + "/signingkey1.pem"
@ -82,7 +81,7 @@ tasks.register("createGroupPolicy") {
doLast { doLast {
def groupPolicyFName = new String("${devEnvWorkspace}/GroupPolicy.json") def groupPolicyFName = new String("${devEnvWorkspace}/GroupPolicy.json")
def devnetFName = new String("$rootDir/csde-config/dev-net.json") def devnetFName = new String("$rootDir/config/dev-net.json")
File groupPolicyFile = new File(groupPolicyFName) File groupPolicyFile = new File(groupPolicyFName)
File devnetFile = new File(devnetFName) File devnetFile = new File(devnetFName)
if (!groupPolicyFile.exists() || groupPolicyFile.lastModified() < devnetFile.lastModified()) { if (!groupPolicyFile.exists() || groupPolicyFile.lastModified() < devnetFile.lastModified()) {
@ -128,7 +127,7 @@ tasks.register('createKeystore') {
if(!keystoreFile.exists()) { if(!keystoreFile.exists()) {
println('createKeystore: Create a keystore') println('createKeystore: Create a keystore')
exec { exec {
commandLine "keytool", "-genkeypair", commandLine "${System.getProperty("java.home")}/bin/keytool", "-genkeypair",
"-alias", keystoreAlias, "-alias", keystoreAlias,
"-keystore", keystoreFName, "-keystore", keystoreFName,
"-storepass", "keystore password", "-storepass", "keystore password",
@ -139,7 +138,7 @@ tasks.register('createKeystore') {
} }
// Need to add the default signing key to the keystore // Need to add the default signing key to the keystore
exec { exec {
commandLine "keytool", "-importcert", commandLine "${System.getProperty("java.home")}/bin/keytool", "-importcert",
"-keystore", keystoreFName, "-keystore", keystoreFName,
"-storepass", "keystore password", "-storepass", "keystore password",
"-noprompt", "-noprompt",
@ -148,7 +147,7 @@ tasks.register('createKeystore') {
} }
// keytool -exportcert -rfc -alias "signing key 1" -keystore signingkeys.pfx -storepass "keystore password" -file signingkey1.pem // keytool -exportcert -rfc -alias "signing key 1" -keystore signingkeys.pfx -storepass "keystore password" -file signingkey1.pem
exec { exec {
commandLine "keytool", commandLine "${System.getProperty("java.home")}/bin/keytool",
"-exportcert", "-rfc", "-alias", keystoreAlias, "-exportcert", "-rfc", "-alias", keystoreAlias,
"-keystore", keystoreFName, "-keystore", keystoreFName,
"-storepass", "keystore password", "-storepass", "keystore password",

View File

@ -7,10 +7,19 @@ import net.corda.v5.base.types.MemberX500Name;
//// to be able to send from one virtual node to another. //// to be able to send from one virtual node to another.
@CordaSerializable @CordaSerializable
public class Message { public class Message {
Message(MemberX500Name _sender, String _message) { // public Message() {}
sender = _sender; public Message(MemberX500Name sender, String message) {
message = _message; this.sender = sender;
this.message = message;
} }
public MemberX500Name getSender() {
return sender;
}
public String getMessage() {
return message;
}
public MemberX500Name sender; public MemberX500Name sender;
public String message; public String message;
} }

View File

@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory;
// to link the two sides of the flow together they need to have the same protocol. // to link the two sides of the flow together they need to have the same protocol.
@InitiatingFlow(protocol = "another-flow") @InitiatingFlow(protocol = "another-flow")
// MyFirstFlow should inherit from RPCStartableFlow, which tells Corda it can be started via an RPC call // MyFirstFlow should inherit from RPCStartableFlow, which tells Corda it can be started via an RPC call
class MyFirstFlow implements RPCStartableFlow { public class MyFirstFlow implements RPCStartableFlow {
// It is useful to be able to log messages from the flows for debugging. // It is useful to be able to log messages from the flows for debugging.
private final Logger log = LoggerFactory.getLogger(MyFirstFlow.class); private final Logger log = LoggerFactory.getLogger(MyFirstFlow.class);
@ -43,6 +43,7 @@ class MyFirstFlow implements RPCStartableFlow {
// When a flow is invoked it's call() method is called. // When a flow is invoked it's call() method is called.
// call() methods must be marked as @Suspendable, this allows Corda to pause mid-execution to wait // call() methods must be marked as @Suspendable, this allows Corda to pause mid-execution to wait
// for a response from the other flows and services // for a response from the other flows and services
@NotNull
@Suspendable @Suspendable
@Override @Override
public String call(@NotNull RPCRequestData requestBody) { public String call(@NotNull RPCRequestData requestBody) {
@ -57,7 +58,7 @@ class MyFirstFlow implements RPCStartableFlow {
MyFirstFlowStartArgs flowArgs = requestBody.getRequestBodyAs(jsonMarshallingService, MyFirstFlowStartArgs.class); MyFirstFlowStartArgs flowArgs = requestBody.getRequestBodyAs(jsonMarshallingService, MyFirstFlowStartArgs.class);
// Obtain the MemberX500Name of counterparty // Obtain the MemberX500Name of counterparty
MemberX500Name otherMember = flowArgs.othermember; MemberX500Name otherMember = flowArgs.otherMember;
// Get our identity from the MemberLookup service. // Get our identity from the MemberLookup service.
MemberX500Name ourIdentity = memberLookup.myInfo().getName(); MemberX500Name ourIdentity = memberLookup.myInfo().getName();

View File

@ -15,7 +15,7 @@ import org.slf4j.LoggerFactory;
// to link the two sides of the flow together they need to have the same protocol. // to link the two sides of the flow together they need to have the same protocol.
@InitiatedBy(protocol = "another-flow") @InitiatedBy(protocol = "another-flow")
// Responder flows must inherit from ResponderFlow // Responder flows must inherit from ResponderFlow
class MyFirstFlowResponder implements ResponderFlow { public class MyFirstFlowResponder implements ResponderFlow {
// It is useful to be able to log messages from the flows for debugging. // It is useful to be able to log messages from the flows for debugging.
private final Logger log = LoggerFactory.getLogger(MyFirstFlowResponder.class); private final Logger log = LoggerFactory.getLogger(MyFirstFlowResponder.class);

View File

@ -5,9 +5,17 @@ import net.corda.v5.base.types.MemberX500Name;
// // A class to hold the arguments required to start the flow // // A class to hold the arguments required to start the flow
//class MyFirstFlowStartArgs(val otherMember: MemberX500Name) //class MyFirstFlowStartArgs(val otherMember: MemberX500Name)
public class MyFirstFlowStartArgs { public class MyFirstFlowStartArgs {
public MemberX500Name othermember; public MemberX500Name otherMember;
public MyFirstFlowStartArgs(MemberX500Name othermember) { public MemberX500Name getOtherMember() {
this.othermember = othermember; return otherMember;
} }
public MyFirstFlowStartArgs(MemberX500Name otherMember) {
this.otherMember = otherMember;
}
// Without the following we get
// "Cannot construct instance of `com.r3.developers.csdetemplate.MyFirstFlowStartArgs` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: (String)\"{\"otherMember\":\"CN=Bob, OU=Test Dept, O=R3, L=London, C=GB\"}\"; line: 1, column: 2]"
public MyFirstFlowStartArgs() {}
} }

View File

@ -1,5 +1,6 @@
package com.r3.developers.csdetemplate; package com.r3.developers.csdetemplate;
import net.corda.simulator.HoldingIdentity; import net.corda.simulator.HoldingIdentity;
import net.corda.simulator.RequestData; import net.corda.simulator.RequestData;
import net.corda.simulator.SimulatedVirtualNode; import net.corda.simulator.SimulatedVirtualNode;
@ -7,6 +8,7 @@ import net.corda.simulator.Simulator;
import net.corda.v5.base.types.MemberX500Name; import net.corda.v5.base.types.MemberX500Name;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class MyFirstFlowTest { class MyFirstFlowTest {
// Names picked to match the corda network in config/dev-net.json // Names picked to match the corda network in config/dev-net.json
@ -45,3 +47,4 @@ class MyFirstFlowTest {
assert(flowResponse.equals("Hello Alice, best wishes from Bob")); assert(flowResponse.equals("Hello Alice, best wishes from Bob"));
} }
} }