Created
May 20, 2018 05:51
-
-
Save ayinot/47eca9402e7d7b66f2521ff000278d0f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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