Skip to content

Instantly share code, notes, and snippets.

@ayinot
Created May 20, 2018 05:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayinot/47eca9402e7d7b66f2521ff000278d0f to your computer and use it in GitHub Desktop.
Save ayinot/47eca9402e7d7b66f2521ff000278d0f to your computer and use it in GitHub Desktop.
package com.example.api
import com.example.flow.LoanRequestFlow.Initiator
import com.example.state.LoanState
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startTrackedFlow
import net.corda.core.messaging.vaultQueryBy
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import org.slf4j.Logger
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
import javax.ws.rs.core.Response.Status.BAD_REQUEST
import javax.ws.rs.core.Response.Status.CREATED
val SERVICE_NAMES = listOf("Notary", "Network Map Service")
// This API is accessible from /api/loan. All paths specified below are relative to it.
@Path("loan")
class ExampleApi(private val rpcOps: CordaRPCOps) {
private val myLegalName: CordaX500Name = rpcOps.nodeInfo().legalIdentities.first().name
companion object {
private val logger: Logger = loggerFor<ExampleApi>()
}
/**
* Returns the node's name.
*/
@GET
@Path("me")
@Produces(MediaType.APPLICATION_JSON)
fun whoami() = mapOf("me" to myLegalName)
/**
* Returns all parties registered with the [NetworkMapService]. These names can be used to look up identities
* using the [IdentityService].
*/
@GET
@Path("peers")
@Produces(MediaType.APPLICATION_JSON)
fun getPeers(): Map<String, List<CordaX500Name>> {
val nodeInfo = rpcOps.networkMapSnapshot()
return mapOf("peers" to nodeInfo
.map { it.legalIdentities.first().name }
//filter out myself, notary and eventual network map started by driver
.filter { it.organisation !in (SERVICE_NAMES + myLegalName.organisation) })
}
/**
* Displays all LoanRequest states that exist in the node's vault.
*/
@GET
@Path("loanRequests")
@Produces(MediaType.APPLICATION_JSON)
fun getLoanrequests() = rpcOps.vaultQueryBy<LoanState>().states
/**
* Initiates a flow to requestLoan and send it to all parties.
*
* Once the flow finishes it will have written the loan to ledger. The borrower and all the lenders will be able to
* see it when calling /api/loan/loan_request on their respective nodes.
*
* This end-point takes loanAmount, interestRate and lenders as parameters
* Lenders parameter are the other parties in the node. If the serving node can't find the other party
* in its network map cache, it will return an HTTP bad request.
*
* The flow is invoked asynchronously. It returns a future when the flow's call() method returns.
*/
@PUT
@Path("create-loan_request")
fun createIOU(@QueryParam("loanAmount") loanAmount: Int, @QueryParam("interest") interestRate: Int,
@QueryParam("lenders") lenders: List<String>): Response {
if (loanAmount <= 0 ) {
return Response.status(BAD_REQUEST).entity("Query parameter 'iouValue' must be non-negative.\n").build()
}
val lenderList = ArrayList<Party>()
/**Here in this for loop we iterate through the list of lenders and check whether they are valid.
*If its valid, it adds the valid lender name in the list and initiates the flow
*/
for(i in lenders.indices) {
if(lenders[i].equals("PartyA")) {
println("Inside PartyA ")
val lenderName = rpcOps.wellKnownPartyFromX500Name(CordaX500Name("PartyA", "London", "GB")) ?:
return Response.status(BAD_REQUEST).entity("Party named $lenders[i] cannot be found.\n").build()
lenderList.add(lenderName)
}else if(lenders[i].equals("PartyB")) {
println("Inside PartyB ")
val lenderName = rpcOps.wellKnownPartyFromX500Name(CordaX500Name("PartyB", "New York", "US")) ?:
return Response.status(BAD_REQUEST).entity("Party named $lenders[i] cannot be found.\n").build()
lenderList.add(lenderName)
}else if(lenders[i].equals("PartyC")) {
println("Inside PartyC ")
val lenderName = rpcOps.wellKnownPartyFromX500Name(CordaX500Name("PartyC", "Paris", "FR")) ?:
return Response.status(BAD_REQUEST).entity("Party named $lenders[i] cannot be found.\n").build()
lenderList.add(lenderName)
}else {
return Response.status(BAD_REQUEST).entity("Party named $lenders[i] cannot be found.\n").build()
}
}
return try {
val signedTx = rpcOps.startTrackedFlow(::Initiator, loanAmount, interestRate, lenderList).returnValue.getOrThrow()
Response.status(CREATED).entity("Transaction id ${signedTx.id} committed to ledger.\n").build()
} catch (ex: Throwable) {
logger.error(ex.message, ex)
Response.status(BAD_REQUEST).entity(ex.message!!).build()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment