Skip to content

Commit

Permalink
feat(corda-connector): list flows endpoint #624
Browse files Browse the repository at this point in the history
Adds an endpoint that responds with the Corda RPC
proxies similarly named method's return value (e.g. the list of flows)

As an example return value, please observe this JSON array:

```json
[
    "net.corda.core.flows.ContractUpgradeFlow$Authorise",
    "net.corda.core.flows.ContractUpgradeFlow$Deauthorise",
    "net.corda.core.flows.ContractUpgradeFlow$Initiate",
    "net.corda.finance.flows.CashExitFlow",
    "net.corda.finance.flows.CashIssueAndPaymentFlow",
    "net.corda.finance.flows.CashIssueFlow",
    "net.corda.finance.flows.CashPaymentFlow",
    "net.corda.finance.internal.CashConfigDataFlow",
    "net.corda.samples.obligation.flows.IOUIssueFlow",
    "net.corda.samples.obligation.flows.IOUSettleFlow",
    "net.corda.samples.obligation.flows.IOUTransferFlow",
    "net.corda.samples.obligation.flows.SelfIssueCashFlow"
]
```

Fixes #624

Signed-off-by: Peter Somogyvari <peter.somogyvari@accenture.com>
  • Loading branch information
petermetz committed Mar 11, 2021
1 parent 28e24b1 commit 438dcda
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/mode
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/JvmObject.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/JvmType.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/JvmTypeKind.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/ListFlowsV1Request.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/ListFlowsV1Response.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/NetworkHostAndPort.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/NodeInfo.kt
src/main/kotlin/org/hyperledger/cactus/plugin/ledger/connector/corda/server/model/Party.kt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.DeployC
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.DeployContractJarsV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.InvokeContractV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.InvokeContractV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.ListFlowsV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.ListFlowsV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.NodeInfo
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
Expand Down Expand Up @@ -55,6 +57,17 @@ class ApiPluginLedgerConnectorCordaController(@Autowired(required = true) val se
}


@PostMapping(
value = ["/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/list-flows"],
produces = ["application/json"],
consumes = ["application/json"]
)
fun listFlowsV1( @Valid @RequestBody(required = false) listFlowsV1Request: ListFlowsV1Request?
): ResponseEntity<ListFlowsV1Response> {
return ResponseEntity(service.listFlowsV1(listFlowsV1Request), HttpStatus.valueOf(200))
}


@PostMapping(
value = ["/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/network-map"],
produces = ["application/json"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.DeployC
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.DeployContractJarsV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.InvokeContractV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.InvokeContractV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.ListFlowsV1Request
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.ListFlowsV1Response
import org.hyperledger.cactus.plugin.ledger.connector.corda.server.model.NodeInfo
interface ApiPluginLedgerConnectorCordaService {

fun deployContractJarsV1(deployContractJarsV1Request: DeployContractJarsV1Request?): DeployContractJarsSuccessV1Response

fun invokeContractV1(invokeContractV1Request: InvokeContractV1Request?): InvokeContractV1Response

fun listFlowsV1(listFlowsV1Request: ListFlowsV1Request?): ListFlowsV1Response

fun networkMapV1(body: kotlin.Any?): List<NodeInfo>
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ class ApiPluginLedgerConnectorCordaServiceImpl(
return dynamicInvoke(rpc.proxy, invokeContractV1Request!!)
}

override fun listFlowsV1(listFlowsV1Request: ListFlowsV1Request?): ListFlowsV1Response {
val flows = rpc.proxy.registeredFlows()
return ListFlowsV1Response(flows)
}

override fun networkMapV1(body: Any?): List<NodeInfo> {

// FIXME: do not recreate the mapper for every request that we receive...
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.hyperledger.cactus.plugin.ledger.connector.corda.server.model

import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import javax.validation.Valid

/**
*
* @param filter
*/
data class ListFlowsV1Request(

@field:JsonProperty("filter") val filter: kotlin.String? = null
) {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.hyperledger.cactus.plugin.ledger.connector.corda.server.model

import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import javax.validation.Valid

/**
*
* @param flowNames An array of strings storing the names of the flows as returned by the flowList Corda RPC.
*/
data class ListFlowsV1Response(

@get:NotNull
@field:JsonProperty("flowNames") val flowNames: kotlin.collections.List<kotlin.String>
) {

}

Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,46 @@
}
}
},
"ListFlowsV1Request": {
"type": "object",
"properties": {
"filter": {
"type": "string"
}
}
},
"ListFlowsV1Response": {
"type": "object",
"required": [
"flowNames"
],
"properties": {
"flowNames": {
"type": "array",
"description": "An array of strings storing the names of the flows as returned by the flowList Corda RPC.",
"example": [
"net.corda.core.flows.ContractUpgradeFlow$Authorise",
"net.corda.core.flows.ContractUpgradeFlow$Deauthorise",
"net.corda.core.flows.ContractUpgradeFlow$Initiate",
"net.corda.finance.flows.CashExitFlow",
"net.corda.finance.flows.CashIssueAndPaymentFlow",
"net.corda.finance.flows.CashIssueFlow",
"net.corda.finance.flows.CashPaymentFlow",
"net.corda.finance.internal.CashConfigDataFlow",
"net.corda.samples.obligation.flows.IOUIssueFlow",
"net.corda.samples.obligation.flows.IOUSettleFlow",
"net.corda.samples.obligation.flows.IOUTransferFlow",
"net.corda.samples.obligation.flows.SelfIssueCashFlow"
],
"items": {
"type": "string",
"minItems": 0,
"maxItems": 10e6
},
"default": []
}
}
},
"NetworkHostAndPort": {
"type": "object",
"required": [
Expand All @@ -256,17 +296,21 @@
"PublicKey": {
"type": "object",
"description": "An instance of a java.security.PublicKey (which is an interface) implementation such as org.hyperledger.cactus.plugin.ledger.connector.corda.server.impl.PublicKeyImpl",
"required": ["algorithm", "format", "encoded"],
"required": [
"algorithm",
"format",
"encoded"
],
"properties": {
"algorithm" : {
"algorithm": {
"type": "string",
"example": "EdDSA"
},
"format" : {
"format": {
"type": "string",
"example": "X.509"
},
"encoded" : {
"encoded": {
"type": "string",
"example": "MCowBQYDK2VwAyEAac1p4wLsAh70VJOcudQppu7NnKxyoKxVN0DbfTxF+54="
}
Expand Down Expand Up @@ -484,7 +528,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NetworkMapV1Request"
"$ref": "#/components/schemas/NetworkMapV1Request"
}
}
}
Expand All @@ -502,6 +546,40 @@
}
}
}
},
"/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/list-flows": {
"post": {
"operationId": "listFlowsV1",
"x-hyperledger-cactus": {
"http": {
"path": "/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/list-flows",
"verbLowerCase": "post"
}
},
"description": "Responds with a list of the flows on the Corda node.",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ListFlowsV1Request"
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ListFlowsV1Response"
}
}
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,32 @@ export enum JvmTypeKind {
REFERENCE = 'REFERENCE'
}

/**
*
* @export
* @interface ListFlowsV1Request
*/
export interface ListFlowsV1Request {
/**
*
* @type {string}
* @memberof ListFlowsV1Request
*/
filter?: string;
}
/**
*
* @export
* @interface ListFlowsV1Response
*/
export interface ListFlowsV1Response {
/**
* An array of strings storing the names of the flows as returned by the flowList Corda RPC.
* @type {Array<string>}
* @memberof ListFlowsV1Response
*/
flowNames: Array<string>;
}
/**
*
* @export
Expand Down Expand Up @@ -456,6 +482,46 @@ export const DefaultApiAxiosParamCreator = function (configuration?: Configurati
options: localVarRequestOptions,
};
},
/**
* Responds with a list of the flows on the Corda node.
* @param {ListFlowsV1Request} [listFlowsV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listFlowsV1: async (listFlowsV1Request?: ListFlowsV1Request, options: any = {}): Promise<RequestArgs> => {
const localVarPath = `/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-corda/list-flows`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;



localVarHeaderParameter['Content-Type'] = 'application/json';

const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.query) {
query.set(key, options.query[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
const needsSerialization = (typeof listFlowsV1Request !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
localVarRequestOptions.data = needsSerialization ? JSON.stringify(listFlowsV1Request !== undefined ? listFlowsV1Request : {}) : (listFlowsV1Request || "");

return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
* Responds with a snapshot of the network map as provided by the Corda RPC call: net.corda.core.messaging.CordaRPCOps public abstract fun networkMapSnapshot(): List<NodeInfo>
* @param {object} [body]
Expand Down Expand Up @@ -533,6 +599,19 @@ export const DefaultApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
* Responds with a list of the flows on the Corda node.
* @param {ListFlowsV1Request} [listFlowsV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listFlowsV1(listFlowsV1Request?: ListFlowsV1Request, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ListFlowsV1Response>> {
const localVarAxiosArgs = await DefaultApiAxiosParamCreator(configuration).listFlowsV1(listFlowsV1Request, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
* Responds with a snapshot of the network map as provided by the Corda RPC call: net.corda.core.messaging.CordaRPCOps public abstract fun networkMapSnapshot(): List<NodeInfo>
* @param {object} [body]
Expand Down Expand Up @@ -575,6 +654,15 @@ export const DefaultApiFactory = function (configuration?: Configuration, basePa
invokeContractV1(invokeContractV1Request?: InvokeContractV1Request, options?: any): AxiosPromise<InvokeContractV1Response> {
return DefaultApiFp(configuration).invokeContractV1(invokeContractV1Request, options).then((request) => request(axios, basePath));
},
/**
* Responds with a list of the flows on the Corda node.
* @param {ListFlowsV1Request} [listFlowsV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listFlowsV1(listFlowsV1Request?: ListFlowsV1Request, options?: any): AxiosPromise<ListFlowsV1Response> {
return DefaultApiFp(configuration).listFlowsV1(listFlowsV1Request, options).then((request) => request(axios, basePath));
},
/**
* Responds with a snapshot of the network map as provided by the Corda RPC call: net.corda.core.messaging.CordaRPCOps public abstract fun networkMapSnapshot(): List<NodeInfo>
* @param {object} [body]
Expand Down Expand Up @@ -618,6 +706,17 @@ export class DefaultApi extends BaseAPI {
return DefaultApiFp(this.configuration).invokeContractV1(invokeContractV1Request, options).then((request) => request(this.axios, this.basePath));
}

/**
* Responds with a list of the flows on the Corda node.
* @param {ListFlowsV1Request} [listFlowsV1Request]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof DefaultApi
*/
public listFlowsV1(listFlowsV1Request?: ListFlowsV1Request, options?: any) {
return DefaultApiFp(this.configuration).listFlowsV1(listFlowsV1Request, options).then((request) => request(this.axios, this.basePath));
}

/**
* Responds with a snapshot of the network map as provided by the Corda RPC call: net.corda.core.messaging.CordaRPCOps public abstract fun networkMapSnapshot(): List<NodeInfo>
* @param {object} [body]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ test("Tests are passing on the JVM side", async (t: Test) => {
const connector = new CordaConnectorContainer({
logLevel,
imageName: "petermetz/cactus-connector-corda-server",
imageVersion: "2021-03-01-7e07b5b",
imageVersion: "2021-03-10-feat-624",
envVars: [envVarSpringAppJson],
});
t.ok(CordaConnectorContainer, "CordaConnectorContainer instantaited OK");
Expand Down Expand Up @@ -104,6 +104,13 @@ test("Tests are passing on the JVM side", async (t: Test) => {
await connector.logDebugPorts();
const apiUrl = await connector.getApiLocalhostUrl();
const apiClient = new CordaApi({ basePath: apiUrl });

const flowsRes = await apiClient.listFlowsV1();
t.ok(flowsRes.status === 200, "flowsRes.status === 200 OK");
t.ok(flowsRes.data, "flowsRes.data truthy OK");
t.ok(flowsRes.data.flowNames, "flowsRes.data.flowNames truthy OK");
t.comment(`apiClient.listFlowsV1() => ${JSON.stringify(flowsRes.data)}`);

const depRes = await apiClient.deployContractJarsV1({ jarFiles });
t.ok(depRes, "Jar deployment response truthy OK");
t.equal(depRes.status, 200, "Jar deployment status code === 200 OK");
Expand Down

0 comments on commit 438dcda

Please sign in to comment.