Skip to content

Commit 62a27d5

Browse files
committed
added REST client
1 parent c2fff0c commit 62a27d5

17 files changed

Lines changed: 775 additions & 4 deletions

File tree

Accounts/supplychain/README.md

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,89 @@ flow start SendCargo pickupFrom: SellerInventory, shipTo: BuyerWarehouse, cargo:
100100

101101
## Now, the entire business chain is completed.
102102

103-
104-
105-
103+
# REST API Overview
104+
105+
A single web endpoint exposes REST APIs for operations on 3 Nodes: `Buyer`, `Seller` and `ShippingCo`.
106+
107+
## Operations
108+
109+
* Create an account on any of the three nodes
110+
* **Method**: `POST`
111+
* **URL**: `/api/createAcct`
112+
* **Body**: `Account`
113+
* **Response**: `Status`
114+
* Share account on any of the three nodes
115+
* **Method**: `POST`
116+
* **URL**: `/api/shareAcct`
117+
* **Body**: `AccountShare`
118+
* **Response**: `Status`
119+
* Send Invoice on `Seller`
120+
* **Method**: `POST`
121+
* **URL**: `/api/sendInvoice`
122+
* **Body**: `Invoice`
123+
* **Response**: `Status`
124+
* **Note**: the flow operation is delegated to `Seller`
125+
* Send internal messages on any of the three nodes
126+
* **Method**: `POST`
127+
* **URL**: `/api/sendInternalMessage`
128+
* **Body**: `InternalMessage`
129+
* **Response**: `Status`
130+
* Send payment on `Buyer`
131+
* **Method**: `POST`
132+
* **URL**: `/api/sendPayment`
133+
* **Body**: `Payment`
134+
* **Response**: `Status`
135+
* **Note**: the flow operation is delegated to `Buyer`
136+
* Send shipping request on `Seller`
137+
* **Method**: `POST`
138+
* **URL**: `/api/sendShippingRequest`
139+
* **Body**: `ShippingRequest`
140+
* **Response**: `Status`
141+
* **Note**: the flow operation is delegated to `Buyer`
142+
* Send cargo on `ShippingCo`
143+
* **Method**: `POST`
144+
* **URL**: `/api/sendCargo`
145+
* **Body**: `Cargo`
146+
* **Response**: `Status`
147+
* **Note**: the flow operation is delegated to `ShippingCo`
148+
* Additionally, for monitoring, view inbox on any of the three nodes for their accounts
149+
* **Method**: `GET`
150+
* **URL**: `/api/inbox?node=$node&acctName=$acctName`
151+
* **Response**: `Inbox`
152+
153+
## Required Abstract Data Model
154+
155+
* Account
156+
* onNode: String
157+
* acctName: String
158+
* AccountShare
159+
* senderNode: String
160+
* receiverNode: String
161+
* acctName: String
162+
* Invoice
163+
* whoAmI : String
164+
* whereTo : String
165+
* amount : int32
166+
* InternalMessage
167+
* onNode: String
168+
* whoAmI : String
169+
* whereTo : String
170+
* message : String
171+
* Payment
172+
* whoAmI: String
173+
* whereTo: String
174+
* amount: int32
175+
* ShippingRequest
176+
* whoAmI: String
177+
* whereTo: String
178+
* cargo: String
179+
* Cargo
180+
* pickUpFrom: String
181+
* whereTo: String
182+
* cargo: String
183+
* Inbox
184+
* fromNode: String
185+
* ofAcct: String
186+
* messages: List<String>
187+
* Status
188+
* success: boolean

Accounts/supplychain/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ buildscript {
3434
classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
3535
classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
3636
classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
37+
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.3.2.RELEASE")
38+
3739
}
3840
}
3941

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
plugins {
2+
id 'org.springframework.boot'
3+
id 'io.spring.dependency-management'
4+
id 'application'
5+
id 'net.corda.plugins.cordapp'
6+
}
7+
8+
group 'net.corda'
9+
version '1.0'
10+
11+
mainClassName="net.corda.samples.supplychain.clients.Starter"
12+
13+
repositories {
14+
mavenCentral()
15+
}
16+
17+
dependencies {
18+
// Corda dependencies.
19+
compile "$corda_core_release_group:corda-core:$corda_core_release_version"
20+
compile "$corda_core_release_group:corda-rpc:$corda_core_release_version"
21+
cordaRuntime "$corda_release_group:corda:$corda_release_version"
22+
testCompile "$corda_release_group:corda-node-driver:$corda_release_version"
23+
24+
//Account dependencies
25+
cordaCompile "$confidential_id_release_group:ci-workflows:$confidential_id_release_version"
26+
cordaCompile "$accounts_release_group:accounts-workflows:$accounts_release_version"
27+
28+
// CorDapp dependencies.
29+
compile project(":contracts")
30+
compile project(":workflows")
31+
32+
compileOnly("org.springframework.boot:spring-boot-devtools")
33+
implementation 'org.springframework.boot:spring-boot-starter-web'
34+
testImplementation 'org.springframework.boot:spring-boot-starter-test'
35+
}
36+
37+
test {
38+
useJUnitPlatform()
39+
}
40+
41+
task runServer(type: JavaExec){
42+
description = "Deploying Server"
43+
classpath = sourceSets.main.runtimeClasspath
44+
main = "net.corda.samples.supplychain.clients.Starter"
45+
}
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
package net.corda.samples.supplychain.clients;
2+
3+
import net.corda.core.messaging.CordaRPCOps;
4+
import net.corda.samples.supplychain.accountUtilities.CreateNewAccount;
5+
import net.corda.samples.supplychain.accountUtilities.ShareAccountTo;
6+
import net.corda.samples.supplychain.accountUtilities.ViewInboxByAccount;
7+
import net.corda.samples.supplychain.clients.models.*;
8+
import net.corda.samples.supplychain.flows.SendCargo;
9+
import net.corda.samples.supplychain.flows.SendInvoice;
10+
import net.corda.samples.supplychain.flows.SendPayment;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
import org.springframework.beans.BeansException;
14+
import org.springframework.context.ApplicationContext;
15+
import org.springframework.context.ApplicationContextAware;
16+
import org.springframework.web.bind.annotation.*;
17+
18+
import java.util.List;
19+
import java.util.concurrent.ExecutionException;
20+
21+
@RestController
22+
@RequestMapping("/api")
23+
public class Controller implements ApplicationContextAware {
24+
private CordaRPCOps buyerProxy;
25+
private CordaRPCOps sellerProxy;
26+
private CordaRPCOps shipperProxy;
27+
Logger logger = LoggerFactory.getLogger(Controller.class);
28+
29+
@PostMapping("createAcct")
30+
public Status createAcct(@RequestBody Account account){
31+
String onNode = account.getOnNode();
32+
Status status = new Status(true);
33+
34+
logger.info("createAcct(Account) " + account.toString());
35+
36+
switch (onNode) {
37+
case "buyer":
38+
buyerProxy.startFlowDynamic(CreateNewAccount.class, account.getAcctName());
39+
break;
40+
case "seller":
41+
sellerProxy.startFlowDynamic(CreateNewAccount.class, account.getAcctName());
42+
break;
43+
case "shipper":
44+
shipperProxy.startFlowDynamic(CreateNewAccount.class, account.getAcctName());
45+
break;
46+
default:
47+
status.setSuccess(false);
48+
logger.info("createAcct(Account) received unrecognizable node: " + onNode);
49+
break;
50+
}
51+
52+
return status;
53+
}
54+
55+
@PostMapping("shareAcct")
56+
public Status shareAcct(@RequestBody AccountShare accountShare){
57+
Status status = new Status(true);
58+
String receiver = accountShare.getReceiverNode();
59+
String sender = accountShare.getSenderNode();
60+
String acct = accountShare.getAcctName();
61+
62+
CordaRPCOps senderNode = null, receiverNode = null;
63+
64+
logger.info("shareAcct(AccountShare) " + accountShare.toString());
65+
66+
switch (sender) {
67+
case "buyer":
68+
senderNode = this.buyerProxy;
69+
break;
70+
case "seller":
71+
senderNode = this.sellerProxy;
72+
break;
73+
case "shipper":
74+
senderNode = this.shipperProxy;
75+
break;
76+
default:
77+
status.setSuccess(false);
78+
logger.info("createAcct(Account) received unrecognizable node: " + sender);
79+
break;
80+
}
81+
82+
switch (receiver) {
83+
case "buyer":
84+
receiverNode = this.buyerProxy;
85+
break;
86+
case "seller":
87+
receiverNode = this.sellerProxy;
88+
break;
89+
case "shipper":
90+
receiverNode = this.shipperProxy;
91+
break;
92+
default:
93+
status.setSuccess(false);
94+
logger.info("createAcct(Account) received unrecognizable node: " + receiver);
95+
break;
96+
}
97+
98+
if (senderNode != null && receiverNode != null){
99+
String ret = null;
100+
try {
101+
ret = senderNode.startFlowDynamic(ShareAccountTo.class, acct, receiverNode.nodeInfo().getLegalIdentities().get(0)).getReturnValue().get();
102+
} catch (InterruptedException | ExecutionException e) {
103+
logger.info(e.getMessage());
104+
}
105+
logger.info(ret);
106+
}
107+
108+
return status;
109+
}
110+
111+
@PostMapping("/sendInvoice")
112+
public Status sendInvoice(@RequestBody Invoice invoice){
113+
Status status = new Status(true);
114+
115+
try{
116+
sellerProxy.startFlowDynamic(SendInvoice.class, invoice.getWhoAmI(), invoice.getWhereTo(), invoice.getAmount());
117+
}catch(Exception e){
118+
logger.info(e.getMessage());
119+
status.setSuccess(false);
120+
}
121+
122+
return status;
123+
}
124+
125+
@PostMapping("/sendInternalMessage")
126+
public Status sendInternalMessage(@RequestBody InternalMessage message){
127+
Status status = new Status(true);
128+
129+
CordaRPCOps node = findRPCOps(message.getOnNode());
130+
if (node == null) {
131+
status.setSuccess(false);
132+
return status;
133+
}
134+
135+
try{
136+
String ret = node.startFlowDynamic(net.corda.samples.supplychain.flows.InternalMessage.class, message.getWhoAmI(), message.getWhereTo(), message.getMessage()).getReturnValue().get();
137+
}catch (Exception e){
138+
logger.info(e.getMessage());
139+
status.setSuccess(false);
140+
}
141+
142+
return status;
143+
}
144+
145+
@PostMapping("/sendPayment")
146+
public Status sendPayment(@RequestBody Payment payment){
147+
Status status = new Status(true);
148+
149+
try{
150+
buyerProxy.startFlowDynamic(SendPayment.class, payment.getWhoAmI(), payment.getWhereTo(), payment.getAmount());
151+
}catch(Exception e){
152+
logger.info(e.getMessage());
153+
status.setSuccess(false);
154+
}
155+
156+
return status;
157+
}
158+
159+
@PostMapping("/sendShippingRequest")
160+
public Status sendShippingRequest(@RequestBody ShippingRequest shippingRequest){
161+
Status status = new Status(true);
162+
163+
try{
164+
sellerProxy.startFlowDynamic(SendPayment.class, shippingRequest.getWhoAmI(), shippingRequest.getWhereTo(), shipperProxy.nodeInfo().getLegalIdentities().get(0), shippingRequest.getCargo());
165+
}catch(Exception e){
166+
logger.info(e.getMessage());
167+
status.setSuccess(false);
168+
}
169+
170+
return status;
171+
}
172+
173+
@PostMapping("/sendCargo")
174+
public Status sendCargo(@RequestBody Cargo cargo){
175+
Status status = new Status(true);
176+
177+
try{
178+
String ret = shipperProxy.startFlowDynamic(SendCargo.class, cargo.getPickUpFrom(), cargo.getWhereTo(), cargo.getCargo()).getReturnValue().get();
179+
logger.info(ret);
180+
}catch(Exception e){
181+
logger.info(e.getMessage());
182+
status.setSuccess(false);
183+
}
184+
185+
return status;
186+
}
187+
188+
@GetMapping("/inbox")
189+
public Inbox getInbox(@RequestParam("node") String onNode, @RequestParam("acctName") String acctName){
190+
CordaRPCOps proxy = findRPCOps(onNode);
191+
if (proxy == null) return null;
192+
193+
Inbox inbox = new Inbox();
194+
try{
195+
List<String> ret = proxy.startFlowDynamic(ViewInboxByAccount.class, acctName).getReturnValue().get();
196+
inbox.setMessage(ret);
197+
inbox.setFromNode(onNode);
198+
inbox.setOfAcct(acctName);
199+
}catch(Exception e){
200+
logger.info(e.getMessage());
201+
return null;
202+
}
203+
204+
return inbox;
205+
}
206+
207+
@Override
208+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
209+
this.buyerProxy = applicationContext.getBean("buyerProxy", CordaRPCOps.class);
210+
this.sellerProxy = applicationContext.getBean("sellerProxy", CordaRPCOps.class);
211+
this.shipperProxy = applicationContext.getBean("shipperProxy", CordaRPCOps.class);
212+
}
213+
214+
private CordaRPCOps findRPCOps(String nodeName){
215+
CordaRPCOps ret = null;
216+
217+
switch (nodeName) {
218+
case "buyer":
219+
ret = this.buyerProxy;
220+
break;
221+
case "seller":
222+
ret = this.sellerProxy;
223+
break;
224+
case "shipper":
225+
ret = this.shipperProxy;
226+
break;
227+
default:
228+
logger.info("Unrecognizable node: " + nodeName);
229+
break;
230+
}
231+
232+
return ret;
233+
}
234+
}

0 commit comments

Comments
 (0)