diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile
index b7f30723..ef306e71 100644
--- a/.ci/Jenkinsfile
+++ b/.ci/Jenkinsfile
@@ -1,37 +1,11 @@
-#!groovy
-/**
- * Jenkins pipeline to build the kotlin CorDapp template
- */
-
-/**
- * Kill already started job.
- * Assume new commit takes precedence and results from previousunfinished builds are not required.
- * This feature doesn't play well with disableConcurrentBuilds() option
- */
-@Library('corda-shared-build-pipeline-steps')
-import static com.r3.build.BuildControl.killAllExistingBuildsForJob
-killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
-
-pipeline {
- agent {
- label 'eight-cores'
- }
- options {
- ansiColor('xterm')
- timestamps()
- timeout(3*60) // 3 hours
- buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7'))
- }
- stages {
- stage('Build') {
- steps {
- sh './gradlew --no-daemon -s clean build test deployNodes'
- }
- }
- }
- post {
- cleanup {
- deleteDir()
- }
- }
-}
+@Library('corda-shared-build-pipeline-steps@5.2') _
+
+cordaPipeline(
+ publishRepoPrefix: '',
+ slimBuild: true,
+ runUnitTests: false,
+ dedicatedJobForSnykDelta: false,
+ slackChannel: '#corda-corda5-dev-ex-build-notifications',
+ gitHubComments: false,
+ javaVersion: '17'
+ )
diff --git a/.ci/nightly/JenkinsfileSnykScan b/.ci/nightly/JenkinsfileSnykScan
new file mode 100644
index 00000000..80937160
--- /dev/null
+++ b/.ci/nightly/JenkinsfileSnykScan
@@ -0,0 +1,6 @@
+@Library('corda-shared-build-pipeline-steps@5.1') _
+
+cordaSnykScanPipeline (
+ snykTokenId: 'r3-snyk-corda5',
+ snykAdditionalCommands: "--all-sub-projects -d"
+)
diff --git a/.github/workflows/check-pr-title.yaml b/.github/workflows/check-pr-title.yaml
new file mode 100644
index 00000000..7d427b0a
--- /dev/null
+++ b/.github/workflows/check-pr-title.yaml
@@ -0,0 +1,14 @@
+name: 'Check PR Title'
+on:
+ pull_request:
+ types: [opened, edited, reopened]
+
+jobs:
+ check-pr-title:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: morrisoncole/pr-lint-action@v1.6.1
+ with:
+ title-regex: '^((CORDA|EG|ENT|INFRA|CORE|ES)-\d+)(.*)'
+ on-failed-regex-comment: "PR title failed to match regex -> `%regex%`"
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.gitignore b/.gitignore
index fd11989e..d2879c44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,19 +1,25 @@
+
# Eclipse, ctags, Mac metadata, log files
.classpath
.project
+.settings
tags
.DS_Store
*.log
-*.log.gz
*.orig
+# Created by .ignore support plugin (hsz.mobi)
+
.gradle
+local.properties
+.gradletasknamecache
# General build files
**/build/*
-!docs/build/*
-lib/dokka.jar
+lib/quasar.jar
+
+**/logs/*
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
@@ -21,31 +27,21 @@ lib/dokka.jar
*.iml
## Directory-based project format:
-#.idea
-
-# if you remove the above rule, at least ignore the following:
-
-# Specific files to avoid churn
.idea/*.xml
+.idea/.name
.idea/copyright
-.idea/jsLibraryMappings.xml
-
-# User-specific stuff:
-.idea/tasks.xml
+.idea/inspectionProfiles
+.idea/libraries
+.idea/shelf
+.idea/dataSources
+.idea/markdown-navigator
+.idea/runConfigurations
.idea/dictionaries
-# Sensitive or high-churn files:
-.idea/dataSources.ids
-.idea/dataSources.xml
-.idea/sqlDataSources.xml
-.idea/dynamic.xml
-.idea/uiDesigner.xml
-# Gradle:
-.idea/libraries
+# Include the -parameters compiler option by default in IntelliJ required for serialization.
+!.idea/codeStyleSettings.xml
-# Mongo Explorer plugin:
-.idea/mongoSettings.xml
## File-based project format:
*.ipr
@@ -54,24 +50,37 @@ lib/dokka.jar
## Plugin-specific files:
# IntelliJ
-/out/
-workflows/out/
-contracts/out/
-clients/out/
+**/out/
+/classes/
+
+
+
+# vim
+*.swp
+*.swn
+*.swo
+
+
+
+# Directory generated during Resolve and TestOSGi gradle tasks
+bnd/
+
+# Ignore Gradle build output directory
+build
+/.idea/codeStyles/codeStyleConfig.xml
+/.idea/codeStyles/Project.xml
+
+
-# mpeltonen/sbt-idea plugin
-.idea_modules/
+# Ignore Visual studio directory
+bin/
-# JIRA plugin
-atlassian-ide-plugin.xml
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-# docs related
-docs/virtualenv/
+*.cpi
+*.cpb
+*.cpk
+workspace/**
-# if you use the installQuasar task
-lib
+# ingore temporary data files
+*.dat
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..13566b81
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/runConfigurations/Run_Contract_Tests.xml b/.idea/runConfigurations/Run_Contract_Tests.xml
deleted file mode 100644
index 2daa290a..00000000
--- a/.idea/runConfigurations/Run_Contract_Tests.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_Flow_Tests.xml b/.idea/runConfigurations/Run_Flow_Tests.xml
deleted file mode 100644
index 22aa9b5f..00000000
--- a/.idea/runConfigurations/Run_Flow_Tests.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_Integration_Tests.xml b/.idea/runConfigurations/Run_Integration_Tests.xml
deleted file mode 100644
index 987c31f3..00000000
--- a/.idea/runConfigurations/Run_Integration_Tests.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_Template_Client.xml b/.idea/runConfigurations/Run_Template_Client.xml
deleted file mode 100644
index cbe7576c..00000000
--- a/.idea/runConfigurations/Run_Template_Client.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_Template_Server.xml b/.idea/runConfigurations/Run_Template_Server.xml
deleted file mode 100644
index 31ef0a13..00000000
--- a/.idea/runConfigurations/Run_Template_Server.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Unit_tests.xml b/.idea/runConfigurations/Unit_tests.xml
deleted file mode 100644
index 0d8cb29e..00000000
--- a/.idea/runConfigurations/Unit_tests.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Debug_CorDapp.xml b/.run/runConfigurations/DebugCorDapp.run.xml
similarity index 56%
rename from .idea/runConfigurations/Debug_CorDapp.xml
rename to .run/runConfigurations/DebugCorDapp.run.xml
index 99ec0b2d..1d8da821 100644
--- a/.idea/runConfigurations/Debug_CorDapp.xml
+++ b/.run/runConfigurations/DebugCorDapp.run.xml
@@ -1,14 +1,15 @@
-
+
-
+
-
+
+
-
+
-
+
\ No newline at end of file
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index ac86f90c..00000000
--- a/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1 +0,0 @@
-org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
\ No newline at end of file
diff --git a/.snyk b/.snyk
new file mode 100644
index 00000000..c6be1c6c
--- /dev/null
+++ b/.snyk
@@ -0,0 +1,14 @@
+# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
+version: v1.25.0
+# ignores vulnerabilities until expiry date; change duration by modifying expiry date
+ignore:
+ SNYK-JAVA-ORGJETBRAINSKOTLIN-2393744:
+ - '*':
+ reason: >-
+ This vulnerability relates to information exposure via creation of
+ temporary files (via Kotlin functions) with insecure permissions.
+ Corda does not use any of the vulnerable functions so it is not
+ susceptible to this vulnerability
+ expires: 2023-10-19T17:08:41.029Z
+ created: 2023-02-02T17:08:41.032Z
+patch: {}
diff --git a/FlowManagementUI/Dockerfile b/FlowManagementUI/Dockerfile
new file mode 100644
index 00000000..ea0a5480
--- /dev/null
+++ b/FlowManagementUI/Dockerfile
@@ -0,0 +1,5 @@
+FROM python
+WORKDIR /app
+COPY . /app
+RUN pip install -r requirements.txt
+CMD ["python3", "app.py"]
\ No newline at end of file
diff --git a/FlowManagementUI/README.md b/FlowManagementUI/README.md
new file mode 100644
index 00000000..7992e014
--- /dev/null
+++ b/FlowManagementUI/README.md
@@ -0,0 +1,84 @@
+# Corda 5 CorDapp Flow Management Tool
+
+
+This user guide provides step-by-step instructions on using the Corda 5 flow management tool. This article will help you learn how to connect the running corDapp, make flow calls, configure flow queries, and retrieve results.
+
+## Prerequisites
+* Install and run Python and Flask framework. link.
+
+* Prepare your local Corda 5 environment. (By default, the Flow Management Tool is looking to connect to https://localhost:8888/api/v1/swagger#/ with Login: Admin and Password: Admin.)
+
+* Clong the Flow Management Tool repository. FlowManagementUI: main
+
+## Set Up
+
+1. Assuming your local Corda 5 environment is populated and the swagger endpoint is at: https://localhost:8888/api/v1/swagger#/
+
+2. Navigate to where you downloaded the Corda 5 Flow Management Tool
+
+3. To run the framework
+ * Navigate to the file name using cd command.
+ * use the python app.py command to run it.
+ 
+
+ * Later on, click on the IP Address which will open the Interface:
+
+
+
+
+The Flow Management Tool should be automatically connected with the CorDapp running locally from your CSDE. You can test the connection by click on the dropdown list at the Flow Initiator section. You should be able to see the vNodes of your started CorDapp from CSDE.
+
+
+
+## Set Up With Docker
+
+1- Open up Command Prompt
+
+2- Navigate to the application folder using the CD commands
+
+3- Ensure that Docker application is open and build the image using the following command:
+`docker build -t your-image-name .`
+
+Make sure to include the dot at the end of the command
+
+the `your-image-name` at the end of the command can be whatever you like but make sure to use the same name in the next step
+
+4- Run the docker image using the following command:
+`docker run --rm -it --expose 8888 -p 5000:5000 your-image-name`
+
+5- You can access the website by using https://localhost:5000 or https://127.0.0.1:5000
+
+## Using the Flow Management Tool
+
+### Selecting the Flow Initiator
+
+As the first step of using the Flow Management Tool, you would need to select the Flow Initiator. The Flow Initiator indicates which vNode will be triggering the flow. If you wish to have Alice to run a transaction to Bob, select the X500Name of Alice. The selected vNode’s shortHash (Corda 5 Network participant identifier) will also be shown below the dropdown list to signify your selection.
+
+### Function 1: To Make a Flow Call
+
+1. Click on "Flow Call" tab in the application.
+2. Paste the your JSON format request body into the request input box.
+3. Click Post button to trigger the call.
+
+
+
+
+### Function 2: To Configure Flow Query
+
+1. Click on the “Flow Query” tab.
+2. Choose whether to query a single flow or all flows at the selected Flow Initiator.
+3. If you choose to query all of the flows, select “Query All Flows“ then click “Get“.
+
+
+4. If you choose to query a single flow, select “Query Single Flow“, please add the ClientID in specified filed.
+5. Click on “Get” to retrieve the result.
+
+
+
+If you have any suggestions or questions, feel free to give us your feedback through Github for a better experience in the future!
+
+## Conclusion
+In summary, our project introduces a specialized flow management layer on top of Swagger for Corda developers. We understand the challenges developers face in testing Corda applications due to the complexity of commands, our solution focuses on simplifying the process.
+
+Our all-in-one flow management system provides developers with a unified platform, streamlining development and enhancing efficiency. A key feature allows developers to run flows directly from an externally developed website and monitor their status in real-time, offering a user-friendly and practical solution for Corda developers. Overall, our project aims to make Corda development more accessible and tailored to the specific needs of flow management.
+
diff --git a/FlowManagementUI/app.py b/FlowManagementUI/app.py
new file mode 100644
index 00000000..5d3e3f63
--- /dev/null
+++ b/FlowManagementUI/app.py
@@ -0,0 +1,12 @@
+from flask import Flask
+from flask import render_template
+app = Flask(__name__)
+
+
+@app.route('/')
+def home(): # put application's code here
+ return render_template("index.html")
+
+if __name__ == '__main__':
+ app.run(debug=True, host='0.0.0.0')
+
diff --git a/FlowManagementUI/requirements.txt b/FlowManagementUI/requirements.txt
new file mode 100644
index 00000000..8ab6294c
--- /dev/null
+++ b/FlowManagementUI/requirements.txt
@@ -0,0 +1 @@
+flask
\ No newline at end of file
diff --git a/FlowManagementUI/static/Scripts/script.js b/FlowManagementUI/static/Scripts/script.js
new file mode 100644
index 00000000..8fd4ec0d
--- /dev/null
+++ b/FlowManagementUI/static/Scripts/script.js
@@ -0,0 +1,322 @@
+// This script contains functions for making API requests, handling data, and updating the UI.
+
+// Variable to store the selected X500Name from the dropdown
+let selectedX500Name;
+
+// Variable to indicate whether data is currently being loaded from the pull request
+let loading = false;
+
+// Function to make a GET request to an external API and return the data
+function getData() {
+ // Replace the URL with the actual API endpoint
+ return fetch('https://jsonplaceholder.typicode.com/todos/1')
+ .then(response => response.json())
+ .then(data => {
+ console.log('API Result:', data);
+
+ // Return specific data fields
+ return {
+ id: data.id,
+ title: data.title
+ };
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Function to get the data and display it on the page
+function getDataAndDisplay() {
+ getData()
+ .then(result => {
+ // Update the result div with the data
+ document.getElementById('result').innerHTML = `
+
ID: ${result.id}
+
Title: ${result.title}
+ `;
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Function to make a GET request to retrieve CPI data
+function getCPI() {
+ const url = 'https://localhost:8888/api/v1/cpi';
+ // Perform the GET request with authorization headers
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Basic YWRtaW46YWRtaW4='
+ }
+ })
+ .then(response => response.json())
+ .then(data => {
+ console.log('API Result:', data);
+ // Further processing of the data can be done here
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Function to get all virtual nodes and populate a dropdown with the data
+function getAllVirtualNodes() {
+ const url = 'https://localhost:8888/api/v1/virtualnode';
+
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Basic YWRtaW46YWRtaW4='
+ }
+ })
+ .then(response => response.json())
+ .then(data => {
+ // Extract virtualNodes from the API response
+ const virtualNodes = data.virtualNodes;
+ console.log('API Result:', virtualNodes);
+
+ // Process the data and populate the dropdown
+ if (Array.isArray(virtualNodes)) {
+ const dropdown = document.getElementById('itemDropdown');
+ dropdown.innerHTML = '';
+ dropdown.innerHTML += '
Select your option
';
+
+ virtualNodes.forEach(item => {
+ // Display each item on the console
+ console.log('Item X500Name:', item.holdingIdentity.x500Name);
+ console.log('Item ShortHash:', item.holdingIdentity.shortHash);
+
+ // Create an option element and add it to the dropdown
+ const option = document.createElement('option');
+ option.value = item.holdingIdentity.shortHash;
+ option.text = item.holdingIdentity.x500Name;
+ dropdown.appendChild(option);
+ });
+
+ // Add event listener to the dropdown to detect changes
+ dropdown.addEventListener('change', function () {
+ selectedX500Name = this.value;
+ console.log('Selected ShortHash:', selectedX500Name);
+
+ // Call a function or update a variable based on the selected item
+ handleDropdownChange(selectedX500Name);
+ });
+
+ } else {
+ console.warn('API Result is not an array.');
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Initialize the virtual nodes dropdown on page load
+getAllVirtualNodes();
+
+// function to handle dropdown change
+function handleDropdownChange(selectedX500Name) {
+ console.log('Handling dropdown change for Item ID:', selectedX500Name);
+ getSelectedVNode();
+ // Additional actions based on the selected item can be performed here
+}
+
+// Function to get the selected virtual node and display it
+function getSelectedVNode() {
+ const displayElement = document.getElementById('selectedX500Display');
+ displayElement.textContent = `Selected X500: ${selectedX500Name}`;
+}
+
+// Function to get all flow results based on the selected virtual node
+function getAllFlowResult() {
+ const url = `https://localhost:8888/api/v1/flow/${selectedX500Name}`;
+
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Basic YWRtaW46YWRtaW4='
+ }
+ })
+ .then(response => response.json())
+ .then(data => {
+ const flowStatusResponses = data.flowStatusResponses;
+ console.log('API Result:', flowStatusResponses);
+
+ // Convert the JSON object to a string for display
+ const jsonString = JSON.stringify(flowStatusResponses, null, 2);
+
+ // Display the JSON string in the result div
+ document.getElementById('idResutl').innerHTML = `
${jsonString}
`;
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Function to make a POST request with a request body
+async function postCallFlow() {
+ let postBtn = $('#postBtn');
+ const url = `https://localhost:8888/api/v1/flow/${selectedX500Name}`;
+
+ // Change the button text to indicate loading
+ postBtn.html('Loading...');
+
+ try {
+ // Perform the POST request with the provided request body
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Basic YWRtaW46YWRtaW4=',
+ 'Content-Type': 'application/json'
+ },
+ body: `${document.getElementById('requestBody').value}`
+ });
+
+ // Parse the response as JSON
+ const data = await response.json();
+
+ if (!data.ok) {
+ console.log(data.status);
+
+ // Check if the response status is not OK (2xx range)
+ if (data.status == "409" || data.status == "400") {
+ let flowStatusResponse = "title: " + data.title + "\nStatus: " + data.status;
+
+ // Display additional details for 400 status
+ if (data.status == "400") {
+ flowStatusResponse += "\nDetails: \n Cause: " + data.details.cause + "\n Reason: " + data.details.reason;
+ }
+
+ document.getElementById('queryResult').innerHTML = `
${flowStatusResponse}
`;
+ return;
+ }
+ }
+
+ let msg = "null";
+ let typ = "null";
+
+ // Construct a string with the flow status responses
+ let flowStatusResponses = "client request ID: " + data.clientRequestId +
+ "\nFlow Result " + data.flowResult +
+ "\nFlow Error Message: " + msg +
+ "\nflow error type: " + typ +
+ "\nFlow ID: " + data.flowId +
+ "\nFlow status: " + data.flowStatus +
+ "\nHolding identity short hash: " + data.holdingIdentityShortHash +
+ "\nTime stamp: " + data.timestamp;
+
+ console.log('API Result:', flowStatusResponses);
+
+ // Display the flow status responses in the result div
+ document.getElementById('queryResult').innerHTML = `
${flowStatusResponses}
`;
+ } catch (error) {
+ console.log('Error:', error);
+ } finally {
+ // Restore the button text after the operation is complete
+ postBtn.html('Post');
+ }
+}
+
+// Function to display an item on the page
+function displayItemOnPage(item) {
+ const resultDiv = document.getElementById('queryResult');
+
+ // Create a new element to display the item
+ const itemElement = document.createElement('div');
+ itemElement.innerHTML = `
+
QueryResult: ${item}
+ `;
+
+ // Append the new element to the result div
+ resultDiv.appendChild(itemElement);
+}
+
+// Function to open a specific tab by hiding/showing content
+function openTab(tabName) {
+ // Hide all tab content
+ var tabContents = document.getElementsByClassName("tab-content");
+ for (var i = 0; i < tabContents.length; i++) {
+ tabContents[i].style.display = "none";
+ document.getElementById(tabContents[i].id + "-tab").style.backgroundColor = "rgb(52,152,219)";
+ }
+
+ // Show the selected tab content
+ var selectedTab = document.getElementById(tabName);
+ if (selectedTab) {
+ selectedTab.style.display = "block";
+ document.getElementById(tabName + "-tab").style.backgroundColor = "rgb(173,216,230)";
+ }
+}
+
+// Function to display a flow for a specific virtual node
+function oneFlow() {
+ const url = `https://localhost:8888/api/v1/flow/${selectedX500Name}/${document.getElementById('clientID').value}`;
+
+ // Validate clientID input
+ if (document.getElementById('clientID').value == "") {
+ alert("Please input a clientId");
+ return;
+ }
+
+ // Perform a GET request to display a flow
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ 'Authorization': 'Basic YWRtaW46YWRtaW4='
+ }
+ })
+ .then(response => response.json())
+ .then(data => {
+ let msg = "null";
+ let typ = "null";
+
+ // Check if the flow status is "FAILED" and extract error details
+ if (data.flowStatus == "FAILED") {
+ msg = data.flowError.message;
+ typ = data.flowError.type;
+ }
+
+ // Construct a string with the flow status responses
+ const flowStatusResponses = "client request ID: " + data.clientRequestId +
+ "\nFlow Result " + data.flowResult +
+ "\nFlow Error Message: " + msg +
+ "\nflow error type: " + typ +
+ "\nFlow ID: " + data.flowId +
+ "\nFlow status: " + data.flowStatus +
+ "\nHolding identity short hash: " + data.holdingIdentityShortHash +
+ "\nTime stamp: " + data.timestamp;
+
+ console.log('API Result:', flowStatusResponses);
+
+ // Display the flow status responses in the result div
+ document.getElementById('idResutl').innerHTML = `
${flowStatusResponses}
`;
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ });
+}
+
+// Function to determine which flow-related action to execute based on user input
+function executeButtonFlow() {
+ // Check the value of the dropdown to determine which action to perform
+ if (document.getElementById("dropdown").value == "option1") {
+ getAllFlowResult();
+ } else {
+ oneFlow();
+ }
+}
+
+function queryDropDownChange(){
+ if (document.getElementById("dropdown").value == "option1") {
+ document.getElementById("clientID").style.display = 'none';
+ }else{
+ document.getElementById("clientID").style.display = 'block';
+
+ }
+}
\ No newline at end of file
diff --git a/FlowManagementUI/static/css/main.css b/FlowManagementUI/static/css/main.css
new file mode 100644
index 00000000..5e4d8493
--- /dev/null
+++ b/FlowManagementUI/static/css/main.css
@@ -0,0 +1,202 @@
+body {
+ font-family: 'Roboto', sans-serif;
+ background-color: #f4f4f4;
+ color: #333;
+ margin: 50px; /* Add margin to the entire body */
+ padding: 0;
+}
+
+h1 {
+ text-align: center;
+ color: #0e0c0c;
+}
+
+/* Style for the label */
+label {
+ display: block;
+ margin-bottom: 10px;
+ font-weight: bold;
+ color: #333;
+}
+/* Style for the dropdown button */
+select {
+ width: 20%;
+ padding: 8px;
+ margin-right: 10px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+ font-size: 14px;
+ color: #555;
+}
+
+#itemDropdown {
+ width: 40%;
+ padding: 10px;
+ box-sizing: border-box;
+}
+
+#clientID{
+ padding: 8px;
+ margin-bottom: 15px;
+ margin-right: 10px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+ font-size: 14px;
+ color: #555;
+}
+
+#OneFlowButon{
+ padding: 8px;
+ margin-bottom: 15px;
+ margin-right: 10px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ box-sizing: border-box;
+ font-size: 14px;
+}
+
+#result {
+ margin-bottom: 10px;
+}
+
+/* Button styling */
+button {
+ background-color: #3498db;
+ color: #fff;
+ padding: 10px 25px;
+ font-size: 16px;
+ border: 2px;
+ border-radius: 15px;
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+}
+
+button:hover {
+ background-color: #2980b9;
+}
+
+/* Tab styling */
+.tab {
+ list-style-type: none; /* Remove default list styles */
+ display: inline-block; /* Display tabs inline */
+ padding: 2px 00px; /* Add padding to the tabs */
+ margin: 0 1px; /* Add margin between tabs */
+ cursor: pointer; /* Change cursor to pointer on hover */
+}
+
+
+.tab li {
+ flex: 1;
+ text-align: center;
+ padding: 10px;
+ background-color: #3498db;
+ color: #fff;
+ border-radius: 8px 15px 0 0;
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+}
+
+.tab li:hover {
+ background-color: #2980b9;
+}
+
+/* Tab content styling */
+.tab-content {
+ display: none;
+ padding: 20px;
+ border: 1px solid #3498db;
+ border-radius: 0 0 5px 5px;
+ background-color: #fff;
+}
+
+.styled-input {
+ width: 100%;
+ padding: 10px;
+ margin-bottom: 10px;
+ box-sizing: border-box;
+}
+
+.output {
+ border: 1px solid #3498db;
+ padding: 10px;
+ border-radius: 5px;
+ background-color: #fff;
+ box-sizing: border-box;
+}
+
+#idResutl {
+ border: 1px solid #3498db;
+ padding: 10px;
+ border-radius: 5px;
+ background-color: #fff;
+ margin-top: 10px;
+ height: 290px;
+ max-height: 290px; /* Set a maximum height for the scroll box */
+ overflow-y: auto; /* Enable vertical scrolling if content exceeds the box height */
+}
+
+/* Responsive design */
+@media screen and (max-width: 600px) {
+ .tab li {
+ border-radius: 5px;
+ margin-bottom: 5px;
+ }
+ .tab-content {
+ border-radius: 5px;
+ }
+}
+#call {
+ display: -ms-inline-flexbox;
+ flex-wrap: wrap;
+
+}
+
+/* Style for side-by-side input boxes */
+.flowcall-container {
+ display: flex;
+}
+
+.input-box, .text-box {
+ width: 150px; /* Set the desired width */
+ margin-right: 10px; /* Optional: Add margin for spacing between input boxes */
+ border-radius: 5px;
+ border: 1px solid #3498db;
+}
+
+.queryoption-container{
+ display: flex;
+}
+
+
+
+#requestBody {
+ flex: 1;
+ box-sizing: border-box;
+ width: 100px; /* Set the desired width */
+ height: 300px; /* Set the desired height */
+ padding: 10px; /* Optional: Add padding for better aesthetics */
+ margin-right: 10px; /* Add some margin between the input and button */
+}
+
+#postBtn {
+ flex: 0 0 auto; /* Don't allow the button to grow or shrink */
+ margin-top: 10px; /* Add some margin between the button and result box */
+ margin-right: 10px; /* Add some margin between the button and result box */
+ width: 500px; /* Set the desired width */
+ height: 50px; /* Set the desired height */
+}
+
+#queryResult {
+ flex: 1;
+ box-sizing: border-box;
+ width: 100px; /* Set the desired width */
+ height: 300px; /* Set the desired height */
+ padding: 10px; /* Optional: Add padding for better aesthetics */
+}
+.content-box{
+ padding: 10px; /* Add padding to the content boxes */
+}
+
+
diff --git a/FlowManagementUI/templates/index.html b/FlowManagementUI/templates/index.html
new file mode 100644
index 00000000..44df7acc
--- /dev/null
+++ b/FlowManagementUI/templates/index.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+ Flask Frontend Example
+
+
+
+
+
+
+
+
+
+
+
+
+
Flow Management APIs
+
+
+
+
+
+
+
+
Please select a flow initiator
+
+
+
+
+
Flow Call
+
Flow Query
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Result will be displayed here
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Result will be displayed here
+
+
+
diff --git a/LICENCE b/LICENCE
deleted file mode 100644
index 3ff572d1..00000000
--- a/LICENCE
+++ /dev/null
@@ -1,13 +0,0 @@
- Copyright 2016, R3 Limited.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
diff --git a/README.md b/README.md
index 4969063b..46502f07 100644
--- a/README.md
+++ b/README.md
@@ -1,142 +1,122 @@
-
-
-
+# cordapp-template-kotlin (Corda v5.2)
-# CorDapp Template - Kotlin
+## This template repository provides:
-Welcome to the Kotlin CorDapp template. The CorDapp template is a stubbed-out CorDapp that you can use to bootstrap
-your own CorDapps.
+- A pre-setup Cordapp Project which you can use as a starting point to develop your own prototypes.
-**This is the Kotlin version of the CorDapp template. The Java equivalent is
-[here](https://github.com/corda/cordapp-template-java/).**
+- A base Gradle configuration which brings in the dependencies you need to write and test a Corda 5 Cordapp.
-# Pre-Requisites
+- A set of Gradle helper tasks, provided by the [Corda runtime gradle plugin](https://github.com/corda/corda-runtime-os/tree/release/os/5.2/tools/corda-runtime-gradle-plugin#readme), which speed up and simplify the development and deployment process.
-See https://docs.corda.net/getting-set-up.html.
+- Debug configuration for debugging a local Corda cluster.
-# Usage
+- The MyFirstFlow code which forms the basis of this getting started documentation, this is located in package com.r3.developers.cordapptemplate.flowexample
-## Running tests inside IntelliJ
+- A UTXO example in package com.r3.developers.cordapptemplate.utxoexample packages
-We recommend editing your IntelliJ preferences so that you use the Gradle runner - this means that the quasar utils
-plugin will make sure that some flags (like ``-javaagent`` - see below) are
-set for you.
+- Ability to configure the Members of the Local Corda Network.
-To switch to using the Gradle runner:
+To find out how to use the template, please refer to the *CorDapp Template* subsection within the *Developing Applications* section in the latest Corda 5 documentation at https://docs.r3.com/
-* Navigate to ``Build, Execution, Deployment -> Build Tools -> Gradle -> Runner`` (or search for `runner`)
- * Windows: this is in "Settings"
- * MacOS: this is in "Preferences"
-* Set "Delegate IDE build/run actions to gradle" to true
-* Set "Run test using:" to "Gradle Test Runner"
+## Prerequisite
+1. Java 17
+2. Corda-cli (v5.2), Download [here](https://github.com/corda/corda-runtime-os/releases/tag/release-5.2.0.0). You need to install Java 17 first.
+3. Docker Desktop
-If you would prefer to use the built in IntelliJ JUnit test runner, you can run ``gradlew installQuasar`` which will
-copy your quasar JAR file to the lib directory. You will then need to specify ``-javaagent:lib/quasar.jar``
-and set the run directory to the project root directory for each test.
+## Setting up
-## Running the nodes
+1. We will begin our test deployment with clicking the `startCorda`. This task will load up the combined Corda workers in docker.
+ A successful deployment will allow you to open the REST APIs at: https://localhost:8888/api/v5_2/swagger#. You can test out some of the
+ functions to check connectivity. (GET /cpi function call should return an empty list as for now.)
+2. We will now deploy the cordapp with a click of `vNodeSetup` task. Upon successful deployment of the CPI, the GET /cpi function call should now return the meta data of the cpi you just upload
-See https://docs.corda.net/tutorial-cordapp.html#running-the-example-cordapp.
+## Flow Management Tool[Optional]
+We had developed a simple GUI for you to interact with the cordapp. You can access the website by using https://localhost:5000 or https://127.0.0.1:5000. The Flow Management Tool will automatically connect with the CorDapp running locally from your Corda cluster. You can test the connection by click on the dropdown list at the Flow Initiator section. You should be able to see the vNodes of your started CorDapp. You can easily trigger and query a Corda flow.
-## Interacting with the nodes
-### Shell
-When started via the command line, each node will display an interactive shell:
+
- Welcome to the Corda interactive shell.
- Useful commands include 'help' to see what is available, and 'bye' to shut down the node.
-
- Tue Nov 06 11:58:13 GMT 2018>>>
-You can use this shell to interact with your node. For example, enter `run networkMapSnapshot` to see a list of
-the other nodes on the network:
+## Running the Chat app
+We have built a simple one to one chat app to demo some functionalities of the next gen Corda platform.
- Tue Nov 06 11:58:13 GMT 2018>>> run networkMapSnapshot
- [
- {
- "addresses" : [ "localhost:10002" ],
- "legalIdentitiesAndCerts" : [ "O=Notary, L=London, C=GB" ],
- "platformVersion" : 3,
- "serial" : 1541505484825
- },
- {
- "addresses" : [ "localhost:10005" ],
- "legalIdentitiesAndCerts" : [ "O=PartyA, L=London, C=GB" ],
- "platformVersion" : 3,
- "serial" : 1541505382560
- },
- {
- "addresses" : [ "localhost:10008" ],
- "legalIdentitiesAndCerts" : [ "O=PartyB, L=New York, C=US" ],
- "platformVersion" : 3,
- "serial" : 1541505384742
- }
- ]
-
- Tue Nov 06 12:30:11 GMT 2018>>>
-
-You can find out more about the node shell [here](https://docs.corda.net/shell.html).
-
-### Client
-
-`clients/src/main/kotlin/com/template/Client.kt` defines a simple command-line client that connects to a node via RPC
-and prints a list of the other nodes on the network.
-
-#### Running the client
-
-##### Via the command line
-
-Run the `runTemplateClient` Gradle task. By default, it connects to the node with RPC address `localhost:10006` with
-the username `user1` and the password `test`.
-
-##### Via IntelliJ
+In this app you can:
+1. Create a new chat with a counterparty. `CreateNewChatFlow`
+2. List out the chat entries you had. `ListChatsFlow`
+3. Individually query out the history of one chat entry. `GetChatFlowArgs`
+4. Continue chatting within the chat entry with the counterparty. `UpdateChatFlow`
-Run the `Run Template Client` run configuration. By default, it connects to the node with RPC address `localhost:10006`
-with the username `user1` and the password `test`.
-### Webserver
-`clients/src/main/kotlin/com/template/webserver/` defines a simple Spring webserver that connects to a node via RPC and
-allows you to interact with the node over HTTP.
-The API endpoints are defined here:
+### Running the chat app
- clients/src/main/kotlin/com/template/webserver/Controller.kt
+In Corda 5, flows will be triggered via `POST /flow/{holdingidentityshorthash}` and flow result will need to be view at `GET /flow/{holdingidentityshorthash}/{clientrequestid}`
+* holdingidentityshorthash: the id of the network participants, ie Bob, Alice, Charlie. You can view all the short hashes of the network member with another gradle task called `listVNodes`
+* clientrequestid: the id you specify in the flow requestBody when you trigger a flow.
-And a static webpage is defined here:
+#### Step 1: Create Chat Entry
+Pick a VNode identity to initiate the chat, and get its short hash. (Let's pick Alice. Dont pick Bob because Bob is the person who we will have the chat with).
- clients/src/main/resources/static/
+Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Alice's hash) and request body:
+```
+{
+ "clientRequestId": "create-1",
+ "flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.CreateNewChatFlow",
+ "requestBody": {
+ "chatName":"Chat with Bob",
+ "otherMember":"CN=Bob, OU=Test Dept, O=R3, L=London, C=GB",
+ "message": "Hello Bob"
+ }
+}
+```
-#### Running the webserver
+After trigger the create-chat flow, hop to `GET /flow/{holdingidentityshorthash}/{clientrequestid}` and enter the short hash(Alice's hash) and clientrequestid to view the flow result
-##### Via the command line
+#### Step 2: List the chat
+In order to continue the chat, we would need the chat ID. This step will bring out all the chat entries this entity (Alice) has.
+Go to `POST /flow/{holdingidentityshorthash}`, enter the identity short hash(Alice's hash) and request body:
+```
+{
+ "clientRequestId": "list-1",
+ "flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.ListChatsFlow",
+ "requestBody": {}
+}
+```
+After trigger the list-chats flow, again, we need to hop to `GET /flow/{holdingidentityshorthash}/{clientrequestid}` and check the result. As the screenshot shows, in the response body,
+we will see a list of chat entries, but it currently only has one entry. And we can see the id of the chat entry. Let's record that id.
-Run the `runTemplateServer` Gradle task. By default, it connects to the node with RPC address `localhost:10006` with
-the username `user1` and the password `test`, and serves the webserver on port `localhost:10050`.
-##### Via IntelliJ
+#### Step 3: Continue the chat with `UpdateChatFlow`
+In this step, we will continue the chat between Alice and Bob.
+Goto `POST /flow/{holdingidentityshorthash}`, enter the identity short hash and request body. Note that here we can have either Alice or Bob's short hash. If you enter Alice's hash,
+this message will be recorded as a message from Alice, vice versa. And the id field is the chat entry id we got from the previous step.
+```
+{
+ "clientRequestId": "update-1",
+ "flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.UpdateChatFlow",
+ "requestBody": {
+ "id":" ** fill in id **",
+ "message": "How are you today?"
+ }
+}
+```
+And as for the result of this flow, go to `GET /flow/{holdingidentityshorthash}/{clientrequestid}` and enter the required fields.
-Run the `Run Template Server` run configuration. By default, it connects to the node with RPC address `localhost:10006`
-with the username `user1` and the password `test`, and serves the webserver on port `localhost:10050`.
+#### Step 4: See the whole chat history of one chat entry
+After a few back and forth of the messaging, you can view entire chat history by calling GetChatFlow.
-#### Interacting with the webserver
-
-The static webpage is served on:
-
- http://localhost:10050
-
-While the sole template endpoint is served on:
-
- http://localhost:10050/templateendpoint
-
-# Extending the template
-
-You should extend this template as follows:
-
-* Add your own state and contract definitions under `contracts/src/main/kotlin/`
-* Add your own flow definitions under `workflows/src/main/kotlin/`
-* Extend or replace the client and webserver under `clients/src/main/kotlin/`
+```
+{
+ "clientRequestId": "get-1",
+ "flowClassName": "com.r3.developers.cordapptemplate.utxoexample.workflows.GetChatFlow",
+ "requestBody": {
+ "id":" ** fill in id **",
+ "numberOfRecords":"4"
+ }
+}
+```
+And as for the result, you need to go to the Get API again and enter the short hash and client request ID.
-For a guided example of how to extend this template, see the Hello, World! tutorial
-[here](https://docs.corda.net/hello-world-introduction.html).
+Thus, we have concluded a full run through of the chat app.
diff --git a/TRADEMARK b/TRADEMARK
deleted file mode 100644
index aa7e20f6..00000000
--- a/TRADEMARK
+++ /dev/null
@@ -1,4 +0,0 @@
-Corda and the Corda logo are trademarks of R3CEV LLC and its affiliates. All rights reserved.
-
-For R3CEV LLC's trademark and logo usage information, please consult our Trademark Usage Policy at
-https://www.r3.com/trademark-policy/.
diff --git a/build.gradle b/build.gradle
index ddefb499..2a4ec7b6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,141 +1,88 @@
-buildscript { //properties that you need to build the project
-
- Properties constants = new Properties()
- file("$projectDir/./constants.properties").withInputStream { constants.load(it) }
-
- ext {
- corda_release_group = constants.getProperty("cordaReleaseGroup")
- corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup")
- corda_release_version = constants.getProperty("cordaVersion")
- corda_core_release_version = constants.getProperty("cordaCoreVersion")
- corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion")
- kotlin_version = constants.getProperty("kotlinVersion")
- junit_version = constants.getProperty("junitVersion")
- quasar_version = constants.getProperty("quasarVersion")
- log4j_version = constants.getProperty("log4jVersion")
- slf4j_version = constants.getProperty("slf4jVersion")
- corda_platform_version = constants.getProperty("platformVersion").toInteger()
- //springboot
- spring_boot_version = '2.0.2.RELEASE'
- spring_boot_gradle_plugin_version = '2.0.2.RELEASE'
- }
-
- repositories {
- mavenLocal()
- mavenCentral()
- maven { url 'https://download.corda.net/maven/corda-releases' }
- }
-
- dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version"
- classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version"
- classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version"
- classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version"
- }
-}
-
-allprojects { //Properties that you need to compile your project (The application)
- apply from: "${rootProject.projectDir}/repositories.gradle"
- apply plugin: 'kotlin'
-
- repositories {
- mavenLocal()
- mavenCentral()
- maven { url 'https://download.corda.net/maven/corda-dependencies' }
- maven { url 'https://download.corda.net/maven/corda-releases' }
- maven { url 'https://jitpack.io' }
- }
-
- tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
- kotlinOptions {
- languageVersion = "1.2"
- apiVersion = "1.2"
- jvmTarget = "1.8"
- javaParameters = true // Useful for reflection.
- }
- }
-
- jar {
- // This makes the JAR's SHA-256 hash repeatable.
- preserveFileTimestamps = false
- reproducibleFileOrder = true
- }
-}
-
-apply plugin: 'net.corda.plugins.cordapp'
-apply plugin: 'net.corda.plugins.cordformation'
-apply plugin: 'net.corda.plugins.quasar-utils'
-
-sourceSets {
- main {
- resources {
- srcDir rootProject.file("config/dev")
- }
- }
-}
-
-//Module dependencis
-dependencies {
- // Corda dependencies.
- cordaCompile "$corda_core_release_group:corda-core:$corda_core_release_version"
- cordaRuntime "$corda_release_group:corda-node-api:$corda_release_version"
- cordaRuntime "$corda_release_group:corda:$corda_release_version"
-
- // CorDapp dependencies.
- cordapp project(":workflows")
- cordapp project(":contracts")
-
- cordaCompile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
- cordaCompile "org.apache.logging.log4j:log4j-web:${log4j_version}"
- cordaCompile "org.slf4j:jul-to-slf4j:$slf4j_version"
- cordaDriver "net.corda:corda-shell:4.9"
-}
-
-//Task to deploy the nodes in order to bootstrap a network
-task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) {
-
- /* This property will load the CorDapps to each of the node by default, including the Notary. You can find them
- * in the cordapps folder of the node at build/nodes/Notary/cordapps. However, the notary doesn't really understand
- * the notion of cordapps. In production, Notary does not need cordapps as well. This is just a short cut to load
- * the Corda network bootstrapper.
- */
- nodeDefaults {
- projectCordapp {
- deploy = false
- }
- cordapp project(':contracts')
- cordapp project(':workflows')
- runSchemaMigration = true //This configuration is for any CorDapps with custom schema, We will leave this as true to avoid
- //problems for developers who are not familiar with Corda. If you are not using custom schemas, you can change
- //it to false for quicker project compiling time.
- }
- node {
- name "O=Notary,L=London,C=GB"
- notary = [validating : false]
- p2pPort 10002
- rpcSettings {
- address("localhost:10003")
- adminAddress("localhost:10043")
- }
- }
- node {
- name "O=PartyA,L=London,C=GB"
- p2pPort 10005
- rpcSettings {
- address("localhost:10006")
- adminAddress("localhost:10046")
- }
- rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
- }
- node {
- name "O=PartyB,L=New York,C=US"
- p2pPort 10008
- rpcSettings {
- address("localhost:10009")
- adminAddress("localhost:10049")
- }
- rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]]
- }
-
-}
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static org.gradle.api.JavaVersion.VERSION_17
+
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id 'net.corda.cordapp.cordapp-configuration'
+ id 'org.jetbrains.kotlin.plugin.jpa'
+ id 'java'
+ id 'maven-publish'
+ id 'net.corda.gradle.plugin'
+}
+
+allprojects {
+ group 'com.r3.developers.cordapptemplate'
+ version '1.0-SNAPSHOT'
+
+ def javaVersion = VERSION_17
+
+ // Configure Corda runtime gradle plugin
+ cordaRuntimeGradlePlugin {
+ notaryVersion = cordaNotaryPluginsVersion
+ notaryCpiName = "NotaryServer"
+ corDappCpiName = "MyCorDapp"
+ cpiUploadTimeout = "30000"
+ vnodeRegistrationTimeout = "60000"
+ cordaProcessorTimeout = "300000"
+ workflowsModuleName = "workflows"
+ cordaClusterURL = "https://localhost:8888"
+ cordaRestUser = "admin"
+ cordaRestPasswd ="admin"
+ composeFilePath = "config/combined-worker-compose.yaml"
+ networkConfigFile = "config/static-network-config.json"
+ r3RootCertFile = "config/r3-ca-key.pem"
+ skipTestsDuringBuildCpis = "false"
+ cordaRuntimePluginWorkspaceDir = "workspace"
+ cordaBinDir = "${System.getProperty("user.home")}/.corda/corda5"
+ cordaCliBinDir = "${System.getProperty("user.home")}/.corda/cli"
+ }
+
+ // Declare the set of Kotlin compiler options we need to build a CorDapp.
+ tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ allWarningsAsErrors = false
+
+ // Specify the version of Kotlin that we are that we will be developing.
+ languageVersion = '1.7'
+ // Specify the Kotlin libraries that code is compatible with
+ apiVersion = '1.7'
+ // Note that we Need to use a version of Kotlin that will be compatible with the Corda API.
+ // Currently that is developed in Kotlin 1.7 so picking the same version ensures compatibility with that.
+
+ // Specify the version of Java to target.
+ jvmTarget = javaVersion
+
+ // Needed for reflection to work correctly.
+ javaParameters = true
+
+ // -Xjvm-default determines how Kotlin supports default methods.
+ // JetBrains currently recommends developers use -Xjvm-default=all
+ // https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-jvm-default/
+ freeCompilerArgs += [
+ "-Xjvm-default=all"
+ ]
+ }
+ }
+
+ repositories {
+ // All dependencies are held in Maven Central
+ mavenLocal()
+ mavenCentral()
+ }
+
+ tasks.withType(Test).configureEach {
+ useJUnitPlatform()
+ }
+
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ artifactId "corda-dev-template-kotlin-sample"
+ groupId project.group
+ artifact jar
+ }
+ }
+}
diff --git a/clients/build.gradle b/clients/build.gradle
deleted file mode 100644
index eb58eac2..00000000
--- a/clients/build.gradle
+++ /dev/null
@@ -1,48 +0,0 @@
-apply plugin: 'org.springframework.boot'
-
-sourceSets {
- main {
- resources {
- srcDir rootProject.file("config/dev")
- }
- }
-}
-
-dependencies {
- // Corda dependencies.
- compile "$corda_release_group:corda-rpc:$corda_release_version"
-
- // CorDapp dependencies.
- compile project(":contracts")
- compile project(":workflows")
- compile("org.springframework.boot:spring-boot-starter-websocket:$spring_boot_version") {
- exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
- }
- compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}"
- compile "org.apache.logging.log4j:log4j-web:${log4j_version}"
- compile "org.slf4j:jul-to-slf4j:$slf4j_version"
-}
-
-
-springBoot {
- mainClassName = "com.template.webserver.ServerKt"
-}
-
-/* The Client is the communication channel between the external and the node. This task will help you immediately
- * execute your rpc methods in the main method of the client.kt. You can somewhat see this as a quick test of making
- * RPC calls to your nodes.
- */
-task runTemplateClient(type: JavaExec, dependsOn: assemble) {
- classpath = sourceSets.main.runtimeClasspath
- main = 'com.template.ClientKt'
- args 'localhost:10006', 'user1', 'test'
-}
-
-/* This task will start the springboot server that connects to your node (via RPC connection). All of the http requests
- * are in the Controller file. You can leave the Server.kt and NodeRPCConnection.kt file untouched for your use.
- */
-task runTemplateServer(type: JavaExec, dependsOn: assemble) {
- classpath = sourceSets.main.runtimeClasspath
- main = 'com.template.webserver.ServerKt'
- args '--server.port=10050', '--config.rpc.host=localhost', '--config.rpc.port=10006', '--config.rpc.username=user1', '--config.rpc.password=test'
-}
\ No newline at end of file
diff --git a/clients/src/main/kotlin/com/template/Client.kt b/clients/src/main/kotlin/com/template/Client.kt
deleted file mode 100644
index cb1cb91e..00000000
--- a/clients/src/main/kotlin/com/template/Client.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.template
-
-import net.corda.client.rpc.CordaRPCClient
-import net.corda.core.utilities.NetworkHostAndPort.Companion.parse
-import net.corda.core.utilities.loggerFor
-
-/**
- * Connects to a Corda node via RPC and performs RPC operations on the node.
- *
- * The RPC connection is configured using command line arguments.
- */
-fun main(args: Array) = Client().main(args)
-
-private class Client {
- companion object {
- val logger = loggerFor()
- }
-
- fun main(args: Array) {
- // Create an RPC connection to the node.
- require(args.size == 3) { "Usage: Client " }
- val nodeAddress = parse(args[0])
- val rpcUsername = args[1]
- val rpcPassword = args[2]
- val client = CordaRPCClient(nodeAddress)
- val clientConnection = client.start(rpcUsername, rpcPassword)
- val proxy = clientConnection.proxy
-
- // Interact with the node.
- // Example #1, here we print the nodes on the network.
- val nodes = proxy.networkMapSnapshot()
- println("\n-- Here is the networkMap snapshot --")
- logger.info("{}", nodes)
-
- // Example #2, here we print the PartyA's node info
- val me = proxy.nodeInfo().legalIdentities.first().name
- println("\n-- Here is the node info of the node that the client connected to --")
- logger.info("{}", me)
-
- //Close the client connection
- clientConnection.close()
- }
-}
\ No newline at end of file
diff --git a/clients/src/main/kotlin/com/template/webserver/Controller.kt b/clients/src/main/kotlin/com/template/webserver/Controller.kt
deleted file mode 100644
index 8f995c57..00000000
--- a/clients/src/main/kotlin/com/template/webserver/Controller.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.template.webserver
-
-import org.slf4j.LoggerFactory
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
-
-/**
- * Define your API endpoints here.
- */
-@RestController
-@RequestMapping("/") // The paths for HTTP requests are relative to this base path.
-class Controller(rpc: NodeRPCConnection) {
-
- companion object {
- private val logger = LoggerFactory.getLogger(RestController::class.java)
- }
-
- private val proxy = rpc.proxy
-
- @GetMapping(value = ["/templateendpoint"], produces = ["text/plain"])
- private fun templateendpoint(): String {
- return "Define an endpoint here."
- }
-}
\ No newline at end of file
diff --git a/clients/src/main/kotlin/com/template/webserver/NodeRPCConnection.kt b/clients/src/main/kotlin/com/template/webserver/NodeRPCConnection.kt
deleted file mode 100644
index 2954cafd..00000000
--- a/clients/src/main/kotlin/com/template/webserver/NodeRPCConnection.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.template.webserver
-
-import net.corda.client.rpc.CordaRPCClient
-import net.corda.client.rpc.CordaRPCConnection
-import net.corda.core.messaging.CordaRPCOps
-import net.corda.core.utilities.NetworkHostAndPort
-import org.springframework.beans.factory.annotation.Value
-import org.springframework.stereotype.Component
-import javax.annotation.PostConstruct
-import javax.annotation.PreDestroy
-
-private const val CORDA_USER_NAME = "config.rpc.username"
-private const val CORDA_USER_PASSWORD = "config.rpc.password"
-private const val CORDA_NODE_HOST = "config.rpc.host"
-private const val CORDA_RPC_PORT = "config.rpc.port"
-
-/**
- * Wraps an RPC connection to a Corda node.
- *
- * The RPC connection is configured using command line arguments.
- *
- * @param host The host of the node we are connecting to.
- * @param rpcPort The RPC port of the node we are connecting to.
- * @param username The username for logging into the RPC client.
- * @param password The password for logging into the RPC client.
- * @property proxy The RPC proxy.
- */
-@Component
-open class NodeRPCConnection(
- @Value("\${$CORDA_NODE_HOST}") private val host: String,
- @Value("\${$CORDA_USER_NAME}") private val username: String,
- @Value("\${$CORDA_USER_PASSWORD}") private val password: String,
- @Value("\${$CORDA_RPC_PORT}") private val rpcPort: Int): AutoCloseable {
-
- lateinit var rpcConnection: CordaRPCConnection
- private set
- lateinit var proxy: CordaRPCOps
- private set
-
- @PostConstruct
- fun initialiseNodeRPCConnection() {
- val rpcAddress = NetworkHostAndPort(host, rpcPort)
- val rpcClient = CordaRPCClient(rpcAddress)
- val rpcConnection = rpcClient.start(username, password)
- proxy = rpcConnection.proxy
- }
-
- @PreDestroy
- override fun close() {
- rpcConnection.notifyServerAndClose()
- }
-}
\ No newline at end of file
diff --git a/clients/src/main/kotlin/com/template/webserver/Server.kt b/clients/src/main/kotlin/com/template/webserver/Server.kt
deleted file mode 100644
index fb48c058..00000000
--- a/clients/src/main/kotlin/com/template/webserver/Server.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.template.webserver
-
-import org.springframework.boot.Banner
-import org.springframework.boot.SpringApplication
-import org.springframework.boot.WebApplicationType.SERVLET
-import org.springframework.boot.autoconfigure.SpringBootApplication
-
-/**
- * Our Spring Boot application.
- */
-@SpringBootApplication
-private open class Starter
-
-/**
- * Starts our Spring Boot application.
- */
-fun main(args: Array) {
- val app = SpringApplication(Starter::class.java)
- app.setBannerMode(Banner.Mode.OFF)
- app.webApplicationType = SERVLET
- app.run(*args)
-}
diff --git a/clients/src/main/resources/static/app.js b/clients/src/main/resources/static/app.js
deleted file mode 100644
index c58d2de8..00000000
--- a/clients/src/main/resources/static/app.js
+++ /dev/null
@@ -1,3 +0,0 @@
-"use strict";
-
-// Define your client-side logic here.
\ No newline at end of file
diff --git a/clients/src/main/resources/static/index.html b/clients/src/main/resources/static/index.html
deleted file mode 100644
index ab27dbfb..00000000
--- a/clients/src/main/resources/static/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- Example front-end.
-
-
-
-
-
CorDapp Template (Kotlin Version)
-
Learn more about how to build CorDapps at sample-kotlin