mirror of
https://github.com/corda/corda.git
synced 2025-06-10 03:11:44 +00:00
Merge branch 'release/os/4.5' into jamesh/error-reporting-sync-29-04-20
# Conflicts: # node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt
This commit is contained in:
commit
adbe030a2c
83
.ci/dev/compatibility/JenkinsfileJDK11Azul
Normal file
83
.ci/dev/compatibility/JenkinsfileJDK11Azul
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
||||||
|
@Library('corda-shared-build-pipeline-steps')
|
||||||
|
import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
||||||
|
|
||||||
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
|
pipeline {
|
||||||
|
agent { label 'k8s' }
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
timeout(time: 3, unit: 'HOURS')
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
DOCKER_TAG_TO_USE = "${env.GIT_COMMIT.subSequence(0, 8)}"
|
||||||
|
EXECUTOR_NUMBER = "${env.EXECUTOR_NUMBER}"
|
||||||
|
BUILD_ID = "${env.BUILD_ID}-${env.JOB_NAME}"
|
||||||
|
ARTIFACTORY_CREDENTIALS = credentials('artifactory-credentials')
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Corda Pull Request - Generate Build Image') {
|
||||||
|
steps {
|
||||||
|
withCredentials([string(credentialsId: 'container_reg_passwd', variable: 'DOCKER_PUSH_PWD')]) {
|
||||||
|
sh "./gradlew --no-daemon " +
|
||||||
|
"-Dkubenetize=true " +
|
||||||
|
"-Ddocker.push.password=\"\${DOCKER_PUSH_PWD}\" " +
|
||||||
|
"-Ddocker.work.dir=\"/tmp/\${EXECUTOR_NUMBER}\" " +
|
||||||
|
"-Ddocker.build.tag=\"\${DOCKER_TAG_TO_USE}\" " +
|
||||||
|
"-Ddocker.buildbase.tag=11latest " +
|
||||||
|
"-Ddocker.dockerfile=DockerfileJDK11Azul" +
|
||||||
|
" clean pushBuildImage --stacktrace"
|
||||||
|
}
|
||||||
|
sh "kubectl auth can-i get pods"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Corda Pull Request - Run Tests') {
|
||||||
|
parallel {
|
||||||
|
stage('Integration Tests') {
|
||||||
|
steps {
|
||||||
|
sh "./gradlew --no-daemon " +
|
||||||
|
"-DbuildId=\"\${BUILD_ID}\" " +
|
||||||
|
"-Dkubenetize=true " +
|
||||||
|
"-Ddocker.run.tag=\"\${DOCKER_TAG_TO_USE}\" " +
|
||||||
|
"-Dartifactory.username=\"\${ARTIFACTORY_CREDENTIALS_USR}\" " +
|
||||||
|
"-Dartifactory.password=\"\${ARTIFACTORY_CREDENTIALS_PSW}\" " +
|
||||||
|
"-Dgit.branch=\"\${GIT_BRANCH}\" " +
|
||||||
|
"-Dgit.target.branch=\"\${CHANGE_TARGET}\" " +
|
||||||
|
"-Ddependx.branch.origin=${env.GIT_COMMIT} " +
|
||||||
|
"-Ddependx.branch.target=${CHANGE_TARGET} " +
|
||||||
|
" allParallelIntegrationTest --stacktrace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Unit Tests') {
|
||||||
|
steps {
|
||||||
|
sh "./gradlew --no-daemon " +
|
||||||
|
"-DbuildId=\"\${BUILD_ID}\" " +
|
||||||
|
"-Dkubenetize=true " +
|
||||||
|
"-Ddocker.run.tag=\"\${DOCKER_TAG_TO_USE}\" " +
|
||||||
|
"-Dartifactory.username=\"\${ARTIFACTORY_CREDENTIALS_USR}\" " +
|
||||||
|
"-Dartifactory.password=\"\${ARTIFACTORY_CREDENTIALS_PSW}\" " +
|
||||||
|
"-Dgit.branch=\"\${GIT_BRANCH}\" " +
|
||||||
|
"-Dgit.target.branch=\"\${CHANGE_TARGET}\" " +
|
||||||
|
"-Ddependx.branch.origin=${env.GIT_COMMIT} " +
|
||||||
|
"-Ddependx.branch.target=${CHANGE_TARGET} " +
|
||||||
|
" allParallelUnitTest --stacktrace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
archiveArtifacts artifacts: '**/pod-logs/**/*.log', fingerprint: false
|
||||||
|
junit '**/build/test-results-xml/**/*.xml'
|
||||||
|
}
|
||||||
|
cleanup {
|
||||||
|
deleteDir() /* clean up our workspace */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
.ci/dev/integration/Jenkinsfile
vendored
2
.ci/dev/integration/Jenkinsfile
vendored
@ -5,7 +5,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
timeout(time: 3, unit: 'HOURS')
|
timeout(time: 3, unit: 'HOURS')
|
||||||
|
2
.ci/dev/nightly-regression/Jenkinsfile
vendored
2
.ci/dev/nightly-regression/Jenkinsfile
vendored
@ -4,7 +4,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
overrideIndexTriggers(false)
|
overrideIndexTriggers(false)
|
||||||
|
2
.ci/dev/on-demand-tests/Jenkinsfile
vendored
2
.ci/dev/on-demand-tests/Jenkinsfile
vendored
@ -3,4 +3,4 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
|
|
||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
onDemandTestPipeline('local-k8s', '.ci/dev/on-demand-tests/commentMappings.yml')
|
onDemandTestPipeline('k8s', '.ci/dev/on-demand-tests/commentMappings.yml')
|
||||||
|
32
.ci/dev/regression/Jenkinsfile
vendored
32
.ci/dev/regression/Jenkinsfile
vendored
@ -4,7 +4,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7'))
|
buildDiscarder(logRotator(daysToKeepStr: '7', artifactDaysToKeepStr: '7'))
|
||||||
@ -61,6 +61,36 @@ pipeline {
|
|||||||
" allParallelSlowIntegrationTest --stacktrace"
|
" allParallelSlowIntegrationTest --stacktrace"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stage('Generate sonarqube report') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
try {
|
||||||
|
// running this step here is the only way to not majorly affect the distributed test plugin,
|
||||||
|
// as now that neither returns build files nor runs jacoco reports
|
||||||
|
sh "./gradlew --no-daemon build jacocoRootReport --stacktrace"
|
||||||
|
withSonarQubeEnv('sq01') {
|
||||||
|
sh "./gradlew --no-daemon sonarqube -x test --stacktrace"
|
||||||
|
}
|
||||||
|
timeout(time: 3, unit: 'MINUTES') {
|
||||||
|
script {
|
||||||
|
try {
|
||||||
|
def qg = waitForQualityGate();
|
||||||
|
if (qg.status != 'OK') {
|
||||||
|
error "Pipeline aborted due to quality gate failure: ${qg.status}"
|
||||||
|
}
|
||||||
|
} catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
|
||||||
|
println('No sonarqube webhook response within timeout. Please check the webhook configuration in sonarqube.')
|
||||||
|
// continue the pipeline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
println('Error while trying to execute sonarqube analysis, will be skipped.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
.ci/dev/smoke/Jenkinsfile
vendored
2
.ci/dev/smoke/Jenkinsfile
vendored
@ -4,7 +4,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
overrideIndexTriggers(false)
|
overrideIndexTriggers(false)
|
||||||
|
2
.ci/dev/unit/Jenkinsfile
vendored
2
.ci/dev/unit/Jenkinsfile
vendored
@ -5,7 +5,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
timeout(time: 3, unit: 'HOURS')
|
timeout(time: 3, unit: 'HOURS')
|
||||||
|
19
.github/workflows/jira_assign_issue.yml
vendored
Normal file
19
.github/workflows/jira_assign_issue.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Sync assigned jira issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '15 * * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync_assigned:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Assign
|
||||||
|
uses: corda/jira-sync-assigned-action@master
|
||||||
|
with:
|
||||||
|
jiraBaseUrl: ${{ secrets.JIRA_BASE_URL }}
|
||||||
|
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
jiraToken: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
owner: corda
|
||||||
|
repository: corda
|
20
.github/workflows/jira_close_issue.yml
vendored
Normal file
20
.github/workflows/jira_close_issue.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Sync closed jira issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '30 * * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync_closed:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Close
|
||||||
|
uses: corda/jira-sync-closed-action@master
|
||||||
|
with:
|
||||||
|
project: CORDA
|
||||||
|
jiraBaseUrl: https://r3-cev.atlassian.net
|
||||||
|
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
jiraToken: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
owner: corda
|
||||||
|
repository: corda
|
36
.github/workflows/jira_create_issue.yml
vendored
Normal file
36
.github/workflows/jira_create_issue.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
name: Create jira issue from github issue
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update_jira:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Jira Create issue
|
||||||
|
id: create
|
||||||
|
uses: corda/jira-create-issue-action@master
|
||||||
|
with:
|
||||||
|
jiraBaseUrl: https://r3-cev.atlassian.net
|
||||||
|
project: CORDA
|
||||||
|
issuetype: Bug
|
||||||
|
summary: ${{ github.event.issue.title }}
|
||||||
|
labels: community
|
||||||
|
jiraEmail: ${{ secrets.JIRA_USER_EMAIL }}
|
||||||
|
jiraToken: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
|
description: |
|
||||||
|
${{ github.event.issue.body }}
|
||||||
|
|
||||||
|
Created by github action.
|
||||||
|
|
||||||
|
- name: Create comment
|
||||||
|
uses: peter-evans/create-or-update-comment@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
issue-number: ${{ github.event.issue.number }}
|
||||||
|
body: |
|
||||||
|
Automatically created Jira issue: ${{ steps.create.outputs.issue }}
|
||||||
|
reaction-type: '+1'
|
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -5,7 +5,7 @@ import static com.r3.build.BuildControl.killAllExistingBuildsForJob
|
|||||||
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
killAllExistingBuildsForJob(env.JOB_NAME, env.BUILD_NUMBER.toInteger())
|
||||||
|
|
||||||
pipeline {
|
pipeline {
|
||||||
agent { label 'local-k8s' }
|
agent { label 'k8s' }
|
||||||
options {
|
options {
|
||||||
timestamps()
|
timestamps()
|
||||||
timeout(time: 3, unit: 'HOURS')
|
timeout(time: 3, unit: 'HOURS')
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<img src="https://www.corda.net/wp-content/themes/corda/assets/images/crda-logo-big.svg" alt="Corda" width="500">
|
<img src="https://www.corda.net/wp-content/themes/corda/assets/images/crda-logo-big.svg" alt="Corda" width="500">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<a href="https://ci-master.corda.r3cev.com/viewType.html?buildTypeId=Corda_CordaBuild&tab=buildTypeStatusDiv&guest=1"><img src="https://ci.corda.r3cev.com/app/rest/builds/buildType:Corda_CordaBuild/statusIcon"/></a> [](https://opensource.org/licenses/Apache-2.0)
|
<a href="https://ci-master.corda.r3cev.com/viewType.html?buildTypeId=Corda_Build_ActiveReleaseBranches_BuildOsRelease45&tab=buildTypeStatusDiv&guest=1"><img src="https://ci.corda.r3cev.com/app/rest/builds/buildType:Corda_Build_ActiveReleaseBranches_BuildOsRelease45/statusIcon"/></a> [](https://opensource.org/licenses/Apache-2.0)
|
||||||
|
|
||||||
# Corda
|
# Corda
|
||||||
|
|
||||||
|
120
build.gradle
120
build.gradle
@ -79,8 +79,8 @@ buildscript {
|
|||||||
ext.djvm_version = constants.getProperty("djvmVersion")
|
ext.djvm_version = constants.getProperty("djvmVersion")
|
||||||
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
|
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
|
||||||
ext.okhttp_version = '3.14.2'
|
ext.okhttp_version = '3.14.2'
|
||||||
ext.netty_version = '4.1.29.Final'
|
ext.netty_version = '4.1.46.Final'
|
||||||
ext.tcnative_version = '2.0.14.Final'
|
ext.tcnative_version = '2.0.29.Final'
|
||||||
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
|
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
|
||||||
ext.fileupload_version = '1.4'
|
ext.fileupload_version = '1.4'
|
||||||
ext.kryo_version = '4.0.2'
|
ext.kryo_version = '4.0.2'
|
||||||
@ -187,8 +187,9 @@ buildscript {
|
|||||||
// See https://github.com/corda/gradle-capsule-plugin
|
// See https://github.com/corda/gradle-capsule-plugin
|
||||||
classpath "us.kirchmeier:gradle-capsule-plugin:1.0.4_r3"
|
classpath "us.kirchmeier:gradle-capsule-plugin:1.0.4_r3"
|
||||||
classpath group: "com.r3.testing", name: "gradle-distributed-testing-plugin", version: "1.2-LOCAL-K8S-SHARED-CACHE-SNAPSHOT", changing: true
|
classpath group: "com.r3.testing", name: "gradle-distributed-testing-plugin", version: "1.2-LOCAL-K8S-SHARED-CACHE-SNAPSHOT", changing: true
|
||||||
classpath group: "com.r3.dependx", name: "gradle-dependx", version: "0.1.12", changing: true
|
classpath group: "com.r3.dependx", name: "gradle-dependx", version: "0.1.13", changing: true
|
||||||
classpath "com.bmuschko:gradle-docker-plugin:5.0.0"
|
classpath "com.bmuschko:gradle-docker-plugin:5.0.0"
|
||||||
|
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +242,7 @@ allprojects {
|
|||||||
apply plugin: 'jacoco'
|
apply plugin: 'jacoco'
|
||||||
apply plugin: 'org.owasp.dependencycheck'
|
apply plugin: 'org.owasp.dependencycheck'
|
||||||
apply plugin: 'kotlin-allopen'
|
apply plugin: 'kotlin-allopen'
|
||||||
|
apply plugin: 'org.sonarqube'
|
||||||
|
|
||||||
allOpen {
|
allOpen {
|
||||||
annotations(
|
annotations(
|
||||||
@ -400,6 +402,16 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sonarqube {
|
||||||
|
properties {
|
||||||
|
property "sonar.projectName", "Corda"
|
||||||
|
property "sonar.projectKey", "corda"
|
||||||
|
property 'sonar.tests', '**/src/test/**,**/src/smoke-test/**,**/src/integration-test/**,**/src/integration-test-slow/**'
|
||||||
|
property 'sonar.coverage.jacoco.xmlReportPaths', "${rootDir.path}/build/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
|
||||||
|
property 'detekt.sonar.kotlin.baseline.path', "${rootDir.path}/detekt-baseline.xml"
|
||||||
|
property 'detekt.sonar.kotlin.config.path', "${rootDir.path}/detekt-config.yml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that we are running on a Java 8 JDK. The source/targetCompatibility values above aren't sufficient to
|
// Check that we are running on a Java 8 JDK. The source/targetCompatibility values above aren't sufficient to
|
||||||
// guarantee this because those are properties checked by the Java plugin, but we're using Kotlin.
|
// guarantee this because those are properties checked by the Java plugin, but we're using Kotlin.
|
||||||
@ -459,6 +471,28 @@ task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) {
|
|||||||
it.exists()
|
it.exists()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
afterEvaluate {
|
||||||
|
classDirectories = files(classDirectories.files.collect {
|
||||||
|
fileTree(dir: it,
|
||||||
|
// these exclusions are necessary because jacoco gets confused by same class names
|
||||||
|
// which occur due to deterministic versions of non deterministic classes
|
||||||
|
exclude: ['**/net/corda/core/crypto/SHA256DigestSupplier**',
|
||||||
|
'**/net/corda/core/crypto/DelegatingSecureRandomService',
|
||||||
|
'**/net/corda/core/internal/ThreadLocalToggleField**',
|
||||||
|
'**/net/corda/core/internal/InheritableThreadLocalToggleField**',
|
||||||
|
'**/net/corda/core/internal/ToggleField**',
|
||||||
|
'net/corda/core/internal/rules/StateContractValidationEnforcementRule**',
|
||||||
|
'net/corda/core/internal/SimpleToggleField**',
|
||||||
|
'net/corda/core/serialization/SerializationFactory**',
|
||||||
|
'net/corda/serialization/internal/amqp/AMQPStreams**',
|
||||||
|
'net/corda/serialization/internal/amqp/AMQPSerializerFactories**',
|
||||||
|
'net/corda/serialization/internal/amqp/AMQPSerializationThreadContext**',
|
||||||
|
'net/corda/serialization/internal/ByteBufferStreams**',
|
||||||
|
'net/corda/serialization/internal/model/DefaultCacheProvider**',
|
||||||
|
'net/corda/serialization/internal/DefaultWhitelist**'
|
||||||
|
])
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('detekt', JavaExec) {
|
tasks.register('detekt', JavaExec) {
|
||||||
@ -635,67 +669,83 @@ buildScan {
|
|||||||
termsOfServiceAgree = 'yes'
|
termsOfServiceAgree = 'yes'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ext.generalPurpose = [
|
||||||
|
numberOfShards: 10,
|
||||||
|
streamOutput: false,
|
||||||
|
coresPerFork: 2,
|
||||||
|
memoryInGbPerFork: 12,
|
||||||
|
nodeTaints: "small"
|
||||||
|
]
|
||||||
|
|
||||||
|
ext.largeScaleSet = [
|
||||||
|
numberOfShards: 15,
|
||||||
|
streamOutput: false,
|
||||||
|
coresPerFork: 6,
|
||||||
|
memoryInGbPerFork: 10,
|
||||||
|
nodeTaints: "big"
|
||||||
|
]
|
||||||
|
|
||||||
task allParallelIntegrationTest(type: ParallelTestGroup) {
|
task allParallelIntegrationTest(type: ParallelTestGroup) {
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
podLogLevel PodLogLevel.INFO
|
podLogLevel PodLogLevel.INFO
|
||||||
testGroups "integrationTest"
|
testGroups "integrationTest"
|
||||||
numberOfShards 10
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 2
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 12
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
|
nodeTaints generalPurpose.nodeTaints
|
||||||
distribute DistributeTestsBy.METHOD
|
distribute DistributeTestsBy.METHOD
|
||||||
nodeTaints "big"
|
|
||||||
}
|
}
|
||||||
task allParallelUnitTest(type: ParallelTestGroup) {
|
task allParallelUnitTest(type: ParallelTestGroup) {
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
podLogLevel PodLogLevel.INFO
|
podLogLevel PodLogLevel.INFO
|
||||||
testGroups "test"
|
testGroups "test"
|
||||||
numberOfShards 10
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 2
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 12
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
|
nodeTaints generalPurpose.nodeTaints
|
||||||
distribute DistributeTestsBy.CLASS
|
distribute DistributeTestsBy.CLASS
|
||||||
nodeTaints "small"
|
|
||||||
}
|
}
|
||||||
task allParallelUnitAndIntegrationTest(type: ParallelTestGroup) {
|
task allParallelUnitAndIntegrationTest(type: ParallelTestGroup) {
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
testGroups "test", "integrationTest"
|
testGroups "test", "integrationTest"
|
||||||
numberOfShards 15
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 6
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 10
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
|
nodeTaints generalPurpose.nodeTaints
|
||||||
distribute DistributeTestsBy.METHOD
|
distribute DistributeTestsBy.METHOD
|
||||||
nodeTaints "big"
|
|
||||||
}
|
}
|
||||||
task parallelRegressionTest(type: ParallelTestGroup) {
|
task parallelRegressionTest(type: ParallelTestGroup) {
|
||||||
testGroups "test", "integrationTest", "smokeTest"
|
testGroups "test", "integrationTest", "smokeTest"
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
numberOfShards 15
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 2
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 10
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
|
nodeTaints generalPurpose.nodeTaints
|
||||||
distribute DistributeTestsBy.METHOD
|
distribute DistributeTestsBy.METHOD
|
||||||
nodeTaints "big"
|
|
||||||
}
|
}
|
||||||
task allParallelSmokeTest(type: ParallelTestGroup) {
|
task allParallelSmokeTest(type: ParallelTestGroup) {
|
||||||
testGroups "smokeTest"
|
testGroups "smokeTest"
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
numberOfShards 4
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 6
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 10
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
distribute DistributeTestsBy.CLASS
|
nodeTaints generalPurpose.nodeTaints
|
||||||
nodeTaints "big"
|
distribute DistributeTestsBy.METHOD
|
||||||
}
|
}
|
||||||
task allParallelSlowIntegrationTest(type: ParallelTestGroup) {
|
task allParallelSlowIntegrationTest(type: ParallelTestGroup) {
|
||||||
testGroups "slowIntegrationTest"
|
testGroups "slowIntegrationTest"
|
||||||
dependsOn dependxiesModule
|
dependsOn dependxiesModule
|
||||||
numberOfShards 4
|
numberOfShards generalPurpose.numberOfShards
|
||||||
streamOutput false
|
streamOutput generalPurpose.streamOutput
|
||||||
coresPerFork 6
|
coresPerFork generalPurpose.coresPerFork
|
||||||
memoryInGbPerFork 10
|
memoryInGbPerFork generalPurpose.memoryInGbPerFork
|
||||||
distribute DistributeTestsBy.CLASS
|
nodeTaints generalPurpose.nodeTaints
|
||||||
nodeTaints "big"
|
distribute DistributeTestsBy.METHOD
|
||||||
}
|
}
|
||||||
apply plugin: 'com.r3.testing.distributed-testing'
|
apply plugin: 'com.r3.testing.distributed-testing'
|
||||||
apply plugin: 'com.r3.testing.image-building'
|
apply plugin: 'com.r3.testing.image-building'
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.client.rpc
|
package net.corda.client.rpc
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import com.esotericsoftware.kryo.KryoException
|
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.flows.StartableByRPC
|
import net.corda.core.flows.StartableByRPC
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
|
@ -14,13 +14,13 @@ import net.corda.core.utilities.Try
|
|||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.coretesting.internal.testThreadFactory
|
||||||
import net.corda.node.services.rpc.RPCServerConfiguration
|
import net.corda.node.services.rpc.RPCServerConfiguration
|
||||||
import net.corda.nodeapi.RPCApi
|
import net.corda.nodeapi.RPCApi
|
||||||
import net.corda.testing.common.internal.eventually
|
import net.corda.testing.common.internal.eventually
|
||||||
import net.corda.testing.common.internal.succeeds
|
import net.corda.testing.common.internal.succeeds
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||||
import net.corda.coretesting.internal.testThreadFactory
|
|
||||||
import net.corda.testing.node.internal.RPCDriverDSL
|
import net.corda.testing.node.internal.RPCDriverDSL
|
||||||
import net.corda.testing.node.internal.RpcBrokerHandle
|
import net.corda.testing.node.internal.RpcBrokerHandle
|
||||||
import net.corda.testing.node.internal.RpcServerHandle
|
import net.corda.testing.node.internal.RpcServerHandle
|
||||||
@ -75,7 +75,7 @@ class RPCStabilityTests {
|
|||||||
values.poll()
|
values.poll()
|
||||||
}
|
}
|
||||||
val first = values.peek()
|
val first = values.peek()
|
||||||
if (values.size == 5 && values.all { it.keys.size == first.keys.size }) {
|
if (values.size == 5 && values.all { it.keys == first.keys }) {
|
||||||
first
|
first
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -21,7 +21,7 @@ object Configuration {
|
|||||||
/**
|
/**
|
||||||
* Describes a [Config] hiding sensitive data.
|
* Describes a [Config] hiding sensitive data.
|
||||||
*/
|
*/
|
||||||
fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue = { value -> ConfigValueFactory.fromAnyRef(value.toString()) }): ConfigValue?
|
fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue = { value -> ConfigValueFactory.fromAnyRef(value.toString()) }, options: Options): ConfigValue?
|
||||||
}
|
}
|
||||||
|
|
||||||
object Value {
|
object Value {
|
||||||
@ -36,10 +36,11 @@ object Configuration {
|
|||||||
*
|
*
|
||||||
* @throws ConfigException.Missing if the [Config] does not specify the value.
|
* @throws ConfigException.Missing if the [Config] does not specify the value.
|
||||||
* @throws ConfigException.WrongType if the [Config] specifies a value of the wrong type.
|
* @throws ConfigException.WrongType if the [Config] specifies a value of the wrong type.
|
||||||
* @throws ConfigException.BadValue if the [Config] specifies a value of the correct type, but this in unacceptable according to application-level validation rules..
|
* @throws ConfigException.BadValue if the [Config] specifies a value of the correct type, but this in unacceptable according to
|
||||||
|
* application-level validation rules.
|
||||||
*/
|
*/
|
||||||
@Throws(ConfigException.Missing::class, ConfigException.WrongType::class, ConfigException.BadValue::class)
|
@Throws(ConfigException.Missing::class, ConfigException.WrongType::class, ConfigException.BadValue::class)
|
||||||
fun valueIn(configuration: Config): TYPE
|
fun valueIn(configuration: Config, options: Options): TYPE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the value is specified by the [Config].
|
* Returns whether the value is specified by the [Config].
|
||||||
@ -50,27 +51,28 @@ object Configuration {
|
|||||||
* Returns a value out of a [Config] if all is good, or null if no value is present. Otherwise, it throws an exception.
|
* Returns a value out of a [Config] if all is good, or null if no value is present. Otherwise, it throws an exception.
|
||||||
*
|
*
|
||||||
* @throws ConfigException.WrongType if the [Config] specifies a value of the wrong type.
|
* @throws ConfigException.WrongType if the [Config] specifies a value of the wrong type.
|
||||||
* @throws ConfigException.BadValue if the [Config] specifies a value of the correct type, but this in unacceptable according to application-level validation rules..
|
* @throws ConfigException.BadValue if the [Config] specifies a value of the correct type, but this in unacceptable according to
|
||||||
|
* application-level validation rules.
|
||||||
*/
|
*/
|
||||||
@Throws(ConfigException.WrongType::class, ConfigException.BadValue::class)
|
@Throws(ConfigException.WrongType::class, ConfigException.BadValue::class)
|
||||||
fun valueInOrNull(configuration: Config): TYPE? {
|
fun valueInOrNull(configuration: Config, options: Options): TYPE? {
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
isSpecifiedBy(configuration) -> valueIn(configuration)
|
isSpecifiedBy(configuration) -> valueIn(configuration, options)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Able to parse a value from a [Config] and [Configuration.Validation.Options], returning a [Valid] result containing either the value itself, or some [Configuration.Validation.Error]s.
|
* Able to parse a value from a [Config] and [Configuration.Options], returning a [Valid] result containing either the value itself, or some [Configuration.Validation.Error]s.
|
||||||
*/
|
*/
|
||||||
interface Parser<VALUE> {
|
interface Parser<VALUE> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Valid] wrapper either around a valid value extracted from the [Config], or around a set of [Configuration.Validation.Error] with details about what went wrong.
|
* Returns a [Valid] wrapper either around a valid value extracted from the [Config], or around a set of [Configuration.Validation.Error] with details about what went wrong.
|
||||||
*/
|
*/
|
||||||
fun parse(configuration: Config, options: Configuration.Validation.Options = Configuration.Validation.Options.defaults): Valid<VALUE>
|
fun parse(configuration: Config, options: Options = Options.defaults): Valid<VALUE>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,11 +111,6 @@ object Configuration {
|
|||||||
*/
|
*/
|
||||||
interface Definition<TYPE> : Configuration.Property.Metadata, Configuration.Validator, Configuration.Value.Extractor<TYPE>, Configuration.Describer, Configuration.Value.Parser<TYPE> {
|
interface Definition<TYPE> : Configuration.Property.Metadata, Configuration.Validator, Configuration.Value.Extractor<TYPE>, Configuration.Describer, Configuration.Value.Parser<TYPE> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates target [Config] with default [Configuration.Validation.Options].
|
|
||||||
*/
|
|
||||||
fun validate(target: Config): Valid<Config> = validate(target, Configuration.Validation.Options.defaults)
|
|
||||||
|
|
||||||
override fun isSpecifiedBy(configuration: Config): Boolean = configuration.hasPath(key)
|
override fun isSpecifiedBy(configuration: Config): Boolean = configuration.hasPath(key)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,9 +178,8 @@ object Configuration {
|
|||||||
fun <MAPPED> map(mappedTypeName: String, convert: (TYPE) -> MAPPED): Standard<MAPPED> = mapValid(mappedTypeName) { value -> valid(convert.invoke(value)) }
|
fun <MAPPED> map(mappedTypeName: String, convert: (TYPE) -> MAPPED): Standard<MAPPED> = mapValid(mappedTypeName) { value -> valid(convert.invoke(value)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(configuration: Config, options: Configuration.Validation.Options): Validated<TYPE, Validation.Error> {
|
override fun parse(configuration: Config, options: Configuration.Options): Validated<TYPE, Validation.Error> {
|
||||||
|
return validate(configuration, options).mapValid { config -> valid(valueIn(config, options)) }
|
||||||
return validate(configuration, options).mapValid { config -> valid(valueIn(config)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -199,7 +195,6 @@ object Configuration {
|
|||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [Int].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [Int].
|
||||||
*/
|
*/
|
||||||
fun int(key: String, sensitive: Boolean = false): Standard<Int> = long(key, sensitive).mapValid { value ->
|
fun int(key: String, sensitive: Boolean = false): Standard<Int> = long(key, sensitive).mapValid { value ->
|
||||||
|
|
||||||
try {
|
try {
|
||||||
valid(Math.toIntExact(value))
|
valid(Math.toIntExact(value))
|
||||||
} catch (e: ArithmeticException) {
|
} catch (e: ArithmeticException) {
|
||||||
@ -210,18 +205,17 @@ object Configuration {
|
|||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [Boolean].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [Boolean].
|
||||||
*/
|
*/
|
||||||
fun boolean(key: String, sensitive: Boolean = false): Standard<Boolean> = StandardProperty(key, Boolean::class.javaObjectType.simpleName, Config::getBoolean, Config::getBooleanList, sensitive)
|
fun boolean(key: String, sensitive: Boolean = false): Standard<Boolean> = StandardProperty(key, Boolean::class.javaObjectType.simpleName, { config, path, _ -> config.getBoolean(path) }, { config, path, _ -> config.getBooleanList(path) }, sensitive)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [Double].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [Double].
|
||||||
*/
|
*/
|
||||||
fun double(key: String, sensitive: Boolean = false): Standard<Double> = StandardProperty(key, Double::class.javaObjectType.simpleName, Config::getDouble, Config::getDoubleList, sensitive)
|
fun double(key: String, sensitive: Boolean = false): Standard<Double> = StandardProperty(key, Double::class.javaObjectType.simpleName, { config, path, _ -> config.getDouble(path) }, { config, path, _ -> config.getDoubleList(path) }, sensitive)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [Float].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [Float].
|
||||||
*/
|
*/
|
||||||
fun float(key: String, sensitive: Boolean = false): Standard<Float> = double(key, sensitive).mapValid { value ->
|
fun float(key: String, sensitive: Boolean = false): Standard<Float> = double(key, sensitive).mapValid { value ->
|
||||||
|
|
||||||
val floatValue = value.toFloat()
|
val floatValue = value.toFloat()
|
||||||
if (floatValue.isInfinite() || floatValue.isNaN()) {
|
if (floatValue.isInfinite() || floatValue.isNaN()) {
|
||||||
invalid<Float, Configuration.Validation.Error>(Configuration.Validation.Error.BadValue.of(key, Float::class.javaObjectType.simpleName, "Provided value exceeds Float range."))
|
invalid<Float, Configuration.Validation.Error>(Configuration.Validation.Error.BadValue.of(key, Float::class.javaObjectType.simpleName, "Provided value exceeds Float range."))
|
||||||
@ -233,24 +227,43 @@ object Configuration {
|
|||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [String].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [String].
|
||||||
*/
|
*/
|
||||||
fun string(key: String, sensitive: Boolean = false): Standard<String> = StandardProperty(key, String::class.java.simpleName, Config::getString, Config::getStringList, sensitive)
|
fun string(key: String, sensitive: Boolean = false): Standard<String> = StandardProperty(
|
||||||
|
key,
|
||||||
|
String::class.java.simpleName,
|
||||||
|
{ config, path, _ -> config.getString(path) },
|
||||||
|
{ config, path, _ -> config.getStringList(path) },
|
||||||
|
sensitive
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [Duration].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [Duration].
|
||||||
*/
|
*/
|
||||||
fun duration(key: String, sensitive: Boolean = false): Standard<Duration> = StandardProperty(key, Duration::class.java.simpleName, Config::getDuration, Config::getDurationList, sensitive)
|
fun duration(key: String, sensitive: Boolean = false): Standard<Duration> = StandardProperty(key, Duration::class.java.simpleName, { config, path, _ -> config.getDuration(path) }, { config, path, _ -> config.getDurationList(path) }, sensitive)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [ConfigObject].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [ConfigObject].
|
||||||
* It supports an optional [Configuration.Schema], which is used for validation and more when provided.
|
* It supports an optional [Configuration.Schema], which is used for validation and more when provided.
|
||||||
*/
|
*/
|
||||||
fun nestedObject(key: String, schema: Schema? = null, sensitive: Boolean = false): Standard<ConfigObject> = StandardProperty(key, ConfigObject::class.java.simpleName, Config::getObject, Config::getObjectList, sensitive, schema)
|
fun nestedObject(key: String, schema: Schema? = null, sensitive: Boolean = false): Standard<ConfigObject> = StandardProperty(
|
||||||
|
key,
|
||||||
|
ConfigObject::class.java.simpleName,
|
||||||
|
{ config, path, _ -> config.getObject(path) },
|
||||||
|
{ config, path, _ -> config.getObjectList(path) },
|
||||||
|
sensitive,
|
||||||
|
schema
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [Configuration.Property.Definition.Standard] with value of type [ENUM].
|
* Returns a [Configuration.Property.Definition.Standard] with value of type [ENUM].
|
||||||
* This property expects a value in the configuration matching one of the cases of [ENUM], as text, in uppercase.
|
* This property expects a value in the configuration matching one of the cases of [ENUM], as text, in uppercase.
|
||||||
*/
|
*/
|
||||||
fun <ENUM : Enum<ENUM>> enum(key: String, enumClass: KClass<ENUM>, sensitive: Boolean = false): Standard<ENUM> = StandardProperty(key, enumClass.java.simpleName, { conf: Config, propertyKey: String -> conf.getEnum(enumClass.java, propertyKey) }, { conf: Config, propertyKey: String -> conf.getEnumList(enumClass.java, propertyKey) }, sensitive)
|
fun <ENUM : Enum<ENUM>> enum(key: String, enumClass: KClass<ENUM>, sensitive: Boolean = false): Standard<ENUM> = StandardProperty(
|
||||||
|
key,
|
||||||
|
enumClass.java.simpleName,
|
||||||
|
{ conf: Config, propertyKey: String, _ -> conf.getEnum(enumClass.java, propertyKey) },
|
||||||
|
{ conf: Config, propertyKey: String, _ -> conf.getEnumList(enumClass.java, propertyKey) },
|
||||||
|
sensitive
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,12 +288,7 @@ object Configuration {
|
|||||||
*/
|
*/
|
||||||
val properties: Set<Property.Definition<*>>
|
val properties: Set<Property.Definition<*>>
|
||||||
|
|
||||||
/**
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue
|
||||||
* Validates target [Config] with default [Configuration.Validation.Options].
|
|
||||||
*/
|
|
||||||
fun validate(target: Config): Valid<Config> = validate(target, Configuration.Validation.Options.defaults)
|
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -368,35 +376,35 @@ object Configuration {
|
|||||||
|
|
||||||
override fun description() = schema.description()
|
override fun description() = schema.description()
|
||||||
|
|
||||||
override fun validate(target: Config, options: Validation.Options) = schema.validate(target, options)
|
override fun validate(target: Config, options: Options) = schema.validate(target, options)
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue) = schema.describe(configuration, serialiseValue)
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options) = schema.describe(configuration, serialiseValue, options)
|
||||||
|
|
||||||
final override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<VALUE> = validate(configuration, options).mapValid(::parseValid)
|
final override fun parse(configuration: Config, options: Options): Valid<VALUE> = validate(configuration, options).mapValid { parseValid(it, options) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement to define further mapping and validation logic, assuming the underlying raw [Config] is correct in terms of this [Configuration.Specification].
|
* Implement to define further mapping and validation logic, assuming the underlying raw [Config] is correct in terms of this [Configuration.Specification].
|
||||||
*/
|
*/
|
||||||
protected abstract fun parseValid(configuration: Config): Valid<VALUE>
|
protected abstract fun parseValid(configuration: Config, options: Options): Valid<VALUE>
|
||||||
}
|
}
|
||||||
|
|
||||||
object Validation {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Config] validation options.
|
* Validation and processing options.
|
||||||
* @property strict whether to raise unknown property keys as errors.
|
* @property strict whether to raise unknown property keys as errors.
|
||||||
*/
|
*/
|
||||||
data class Options(val strict: Boolean) {
|
class Options(val strict: Boolean = false) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default [Config] validation options, without [strict] parsing enabled.
|
* Default [Config] options, without [strict] parsing enabled.
|
||||||
*/
|
*/
|
||||||
val defaults: Configuration.Validation.Options = Options(strict = false)
|
val defaults: Configuration.Options = Options()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Validation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Super-type for the errors raised by the parsing and validation of a [Config] object.
|
* Super-type for the errors raised by the parsing and validation of a [Config] object.
|
||||||
*
|
*
|
||||||
@ -531,7 +539,7 @@ object Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raised when a key-value pair appeared in the [Config] object without a matching property in the [Configuration.Schema], and [Configuration.Validation.Options.strict] was enabled.
|
* Raised when a key-value pair appeared in the [Config] object without a matching property in the [Configuration.Schema], and [Configuration.Options.strict] was enabled.
|
||||||
*/
|
*/
|
||||||
class Unknown private constructor(override val keyName: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, null, message(keyName), containingPath) {
|
class Unknown private constructor(override val keyName: String, containingPath: List<String> = emptyList()) : Configuration.Validation.Error(keyName, null, message(keyName), containingPath) {
|
||||||
|
|
||||||
@ -586,5 +594,5 @@ object Configuration {
|
|||||||
/**
|
/**
|
||||||
* Defines the ability to validate a [Config] object, producing a valid [Config] or a set of [Configuration.Validation.Error].
|
* Defines the ability to validate a [Config] object, producing a valid [Config] or a set of [Configuration.Validation.Error].
|
||||||
*/
|
*/
|
||||||
interface Validator : net.corda.common.validation.internal.Validator<Config, Configuration.Validation.Error, Configuration.Validation.Options>
|
interface Validator : net.corda.common.validation.internal.Validator<Config, Configuration.Validation.Error, Configuration.Options>
|
||||||
}
|
}
|
@ -5,10 +5,9 @@ import net.corda.common.validation.internal.Validated
|
|||||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||||
import net.corda.common.validation.internal.Validated.Companion.valid
|
import net.corda.common.validation.internal.Validated.Companion.valid
|
||||||
|
|
||||||
internal class LongProperty(key: String, sensitive: Boolean = false) : StandardProperty<Long>(key, Long::class.javaObjectType.simpleName, Config::getLong, Config::getLongList, sensitive) {
|
internal class LongProperty(key: String, sensitive: Boolean = false) : StandardProperty<Long>(key, Long::class.javaObjectType.simpleName, { config, path, _ -> config.getLong(path) }, { config, path, _ -> config.getLongList(path) }, sensitive) {
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
|
||||||
|
|
||||||
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
val validated = super.validate(target, options)
|
val validated = super.validate(target, options)
|
||||||
if (validated.isValid && target.getValue(key).unwrapped().toString().contains(".")) {
|
if (validated.isValid && target.getValue(key).unwrapped().toString().contains(".")) {
|
||||||
return invalid(ConfigException.WrongType(target.origin(), key, Long::class.javaObjectType.simpleName, Double::class.javaObjectType.simpleName).toValidationError(key, typeName))
|
return invalid(ConfigException.WrongType(target.origin(), key, Long::class.javaObjectType.simpleName, Double::class.javaObjectType.simpleName).toValidationError(key, typeName))
|
||||||
@ -17,9 +16,11 @@ internal class LongProperty(key: String, sensitive: Boolean = false) : StandardP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal open class StandardProperty<TYPE : Any>(override val key: String, typeNameArg: String, private val extractSingleValue: (Config, String) -> TYPE, internal val extractListValue: (Config, String) -> List<TYPE>, override val isSensitive: Boolean = false, final override val schema: Configuration.Schema? = null) : Configuration.Property.Definition.Standard<TYPE> {
|
typealias ValueSelector<T> = (Config, String, Configuration.Options) -> T
|
||||||
|
|
||||||
override fun valueIn(configuration: Config) = extractSingleValue.invoke(configuration, key)
|
internal open class StandardProperty<TYPE : Any>(override val key: String, typeNameArg: String, private val extractSingleValue: ValueSelector<TYPE>, internal val extractListValue: ValueSelector<List<TYPE>>, override val isSensitive: Boolean = false, final override val schema: Configuration.Schema? = null) : Configuration.Property.Definition.Standard<TYPE> {
|
||||||
|
|
||||||
|
override fun valueIn(configuration: Config, options: Configuration.Options) = extractSingleValue.invoke(configuration, key, options)
|
||||||
|
|
||||||
override val typeName: String = schema?.let { "#${it.name ?: "Object@$key"}" } ?: typeNameArg
|
override val typeName: String = schema?.let { "#${it.name ?: "Object@$key"}" } ?: typeNameArg
|
||||||
|
|
||||||
@ -29,20 +30,18 @@ internal open class StandardProperty<TYPE : Any>(override val key: String, typeN
|
|||||||
|
|
||||||
override fun list(): Configuration.Property.Definition.RequiredList<TYPE> = ListProperty(this)
|
override fun list(): Configuration.Property.Definition.RequiredList<TYPE> = ListProperty(this)
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue {
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue {
|
||||||
|
|
||||||
if (isSensitive) {
|
if (isSensitive) {
|
||||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||||
}
|
}
|
||||||
return schema?.describe(configuration.getConfig(key), serialiseValue) ?: valueDescription(valueIn(configuration), serialiseValue)
|
return schema?.describe(configuration.getConfig(key), serialiseValue, options) ?: valueDescription(valueIn(configuration, options), serialiseValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isMandatory = true
|
override val isMandatory = true
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
|
|
||||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||||
errors += errorsWhenExtractingValue(target)
|
errors += errorsWhenExtractingValue(target, options)
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
schema?.let { nestedSchema ->
|
schema?.let { nestedSchema ->
|
||||||
val nestedConfig: Config? = target.getConfig(key)
|
val nestedConfig: Config? = target.getConfig(key)
|
||||||
@ -61,15 +60,19 @@ private class ListProperty<TYPE : Any>(delegate: StandardProperty<TYPE>) : Requi
|
|||||||
|
|
||||||
override val typeName: String = "List<${delegate.typeName}>"
|
override val typeName: String = "List<${delegate.typeName}>"
|
||||||
|
|
||||||
override fun valueIn(configuration: Config): List<TYPE> = delegate.extractListValue.invoke(configuration, key)
|
override fun valueIn(configuration: Config, options: Configuration.Options): List<TYPE> = delegate.extractListValue.invoke(configuration, key, options)
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
|
||||||
|
|
||||||
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||||
errors += errorsWhenExtractingValue(target)
|
errors += errorsWhenExtractingValue(target, options)
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
delegate.schema?.let { schema ->
|
delegate.schema?.let { schema ->
|
||||||
errors += valueIn(target).asSequence().map { element -> element as ConfigObject }.map(ConfigObject::toConfig).mapIndexed { index, targetConfig -> schema.validate(targetConfig, options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }.toSet()
|
errors += valueIn(target, options).asSequence()
|
||||||
|
.map { element -> element as ConfigObject }
|
||||||
|
.map(ConfigObject::toConfig)
|
||||||
|
.mapIndexed { index, targetConfig -> schema.validate(targetConfig, options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }
|
||||||
|
.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }
|
||||||
|
.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Validated.withResult(target, errors)
|
return Validated.withResult(target, errors)
|
||||||
@ -77,17 +80,16 @@ private class ListProperty<TYPE : Any>(delegate: StandardProperty<TYPE>) : Requi
|
|||||||
|
|
||||||
override fun <MAPPED> mapValid(mappedTypeName: String, convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>): Configuration.Property.Definition.Required<MAPPED> = ListMappingProperty(this, mappedTypeName, convert)
|
override fun <MAPPED> mapValid(mappedTypeName: String, convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>): Configuration.Property.Definition.Required<MAPPED> = ListMappingProperty(this, mappedTypeName, convert)
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue {
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue {
|
||||||
|
|
||||||
if (isSensitive) {
|
if (isSensitive) {
|
||||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||||
}
|
}
|
||||||
return when {
|
return when {
|
||||||
delegate.schema != null -> {
|
delegate.schema != null -> {
|
||||||
val elementsDescription = valueIn(configuration).asSequence().map { it as ConfigObject }.map(ConfigObject::toConfig).map { delegate.schema.describe(it, serialiseValue) }.toList()
|
val elementsDescription = valueIn(configuration, options).asSequence().map { it as ConfigObject }.map(ConfigObject::toConfig).map { delegate.schema.describe(it, serialiseValue, options) }.toList()
|
||||||
ConfigValueFactory.fromIterable(elementsDescription)
|
ConfigValueFactory.fromIterable(elementsDescription)
|
||||||
}
|
}
|
||||||
else -> valueDescription(valueIn(configuration), serialiseValue)
|
else -> valueDescription(valueIn(configuration, options), serialiseValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,16 +108,17 @@ private class OptionalPropertyWithDefault<TYPE>(delegate: Configuration.Property
|
|||||||
|
|
||||||
override val typeName: String = delegate.typeName.removeSuffix("?")
|
override val typeName: String = delegate.typeName.removeSuffix("?")
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue? = delegate.describe(configuration, serialiseValue) ?: valueDescription(if (isSensitive) Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER else defaultValue, serialiseValue)
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue? = delegate.describe(configuration, serialiseValue, options) ?: valueDescription(if (isSensitive) Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER else defaultValue, serialiseValue)
|
||||||
|
|
||||||
override fun valueIn(configuration: Config): TYPE = delegate.valueIn(configuration) ?: defaultValue
|
override fun valueIn(configuration: Config, options: Configuration.Options): TYPE = delegate.valueIn(configuration, options) ?: defaultValue
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> = delegate.validate(target, options)
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> = delegate.validate(target, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FunctionalProperty<TYPE, MAPPED>(delegate: Configuration.Property.Definition.Standard<TYPE>, private val mappedTypeName: String, internal val extractListValue: (Config, String) -> List<TYPE>, private val convert: (TYPE) -> Valid<MAPPED>) : RequiredDelegatedProperty<MAPPED, Configuration.Property.Definition.Standard<TYPE>>(delegate), Configuration.Property.Definition.Standard<MAPPED> {
|
private class FunctionalProperty<TYPE, MAPPED>(delegate: Configuration.Property.Definition.Standard<TYPE>, private val mappedTypeName: String, internal val extractListValue: ValueSelector<List<TYPE>>, private val convert: (TYPE) -> Valid<MAPPED>)
|
||||||
|
: RequiredDelegatedProperty<MAPPED, Configuration.Property.Definition.Standard<TYPE>>(delegate), Configuration.Property.Definition.Standard<MAPPED> {
|
||||||
|
|
||||||
override fun valueIn(configuration: Config) = convert.invoke(delegate.valueIn(configuration)).value()
|
override fun valueIn(configuration: Config, options: Configuration.Options) = convert.invoke(delegate.valueIn(configuration, options)).value()
|
||||||
|
|
||||||
override val typeName: String = if (super.typeName == "#$mappedTypeName") super.typeName else "$mappedTypeName(${super.typeName})"
|
override val typeName: String = if (super.typeName == "#$mappedTypeName") super.typeName else "$mappedTypeName(${super.typeName})"
|
||||||
|
|
||||||
@ -123,29 +126,31 @@ private class FunctionalProperty<TYPE, MAPPED>(delegate: Configuration.Property.
|
|||||||
|
|
||||||
override fun list(): Configuration.Property.Definition.RequiredList<MAPPED> = FunctionalListProperty(this)
|
override fun list(): Configuration.Property.Definition.RequiredList<MAPPED> = FunctionalListProperty(this)
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
|
|
||||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||||
errors += delegate.validate(target, options).errors
|
errors += delegate.validate(target, options).errors
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
errors += convert.invoke(delegate.valueIn(target)).mapErrors { error -> error.with(delegate.key, mappedTypeName) }.errors
|
errors += convert.invoke(delegate.valueIn(target, options)).mapErrors { error -> error.with(delegate.key, mappedTypeName) }.errors
|
||||||
}
|
}
|
||||||
return Validated.withResult(target, errors)
|
return Validated.withResult(target, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue) = delegate.describe(configuration, serialiseValue)
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options) = delegate.describe(configuration, serialiseValue, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FunctionalListProperty<RAW, TYPE>(delegate: FunctionalProperty<RAW, TYPE>) : RequiredDelegatedProperty<List<TYPE>, FunctionalProperty<RAW, TYPE>>(delegate), Configuration.Property.Definition.RequiredList<TYPE> {
|
private class FunctionalListProperty<RAW, TYPE>(delegate: FunctionalProperty<RAW, TYPE>) : RequiredDelegatedProperty<List<TYPE>, FunctionalProperty<RAW, TYPE>>(delegate), Configuration.Property.Definition.RequiredList<TYPE> {
|
||||||
|
|
||||||
override val typeName: String = "List<${super.typeName}>"
|
override val typeName: String = "List<${super.typeName}>"
|
||||||
|
|
||||||
override fun valueIn(configuration: Config): List<TYPE> = delegate.extractListValue.invoke(configuration, key).asSequence().map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }.map(ConfigObject::toConfig).map(delegate::valueIn).toList()
|
override fun valueIn(configuration: Config, options: Configuration.Options): List<TYPE> = delegate.extractListValue.invoke(configuration, key, options).asSequence()
|
||||||
|
.map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
.map(ConfigObject::toConfig)
|
||||||
|
.map { delegate.valueIn(it, options) }
|
||||||
|
.toList()
|
||||||
|
|
||||||
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
val list = try {
|
val list = try {
|
||||||
delegate.extractListValue.invoke(target, key)
|
delegate.extractListValue.invoke(target, key, options)
|
||||||
} catch (e: ConfigException) {
|
} catch (e: ConfigException) {
|
||||||
if (isErrorExpected(e)) {
|
if (isErrorExpected(e)) {
|
||||||
return invalid(e.toValidationError(key, typeName))
|
return invalid(e.toValidationError(key, typeName))
|
||||||
@ -153,7 +158,11 @@ private class FunctionalListProperty<RAW, TYPE>(delegate: FunctionalProperty<RAW
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val errors = list.asSequence().map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }.mapIndexed { index, value -> delegate.validate(value.toConfig(), options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }.toSet()
|
val errors = list.asSequence()
|
||||||
|
.map { configObject(key to ConfigValueFactory.fromAnyRef(it)) }
|
||||||
|
.mapIndexed { index, value -> delegate.validate(value.toConfig(), options).errors.map { error -> error.withContainingPath(*error.containingPath(index).toTypedArray()) } }
|
||||||
|
.fold(emptyList<Configuration.Validation.Error>()) { one, other -> one + other }
|
||||||
|
.toSet()
|
||||||
return Validated.withResult(target, errors)
|
return Validated.withResult(target, errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,12 +174,11 @@ private class FunctionalListProperty<RAW, TYPE>(delegate: FunctionalProperty<RAW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue {
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue {
|
||||||
|
|
||||||
if (isSensitive) {
|
if (isSensitive) {
|
||||||
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
return valueDescription(Configuration.Property.Definition.SENSITIVE_DATA_PLACEHOLDER, serialiseValue)
|
||||||
}
|
}
|
||||||
return delegate.schema?.let { schema -> valueDescription(valueIn(configuration).asSequence().map { element -> valueDescription(element, serialiseValue) }.map { it as ConfigObject }.map(ConfigObject::toConfig).map { schema.describe(it, serialiseValue) }.toList(), serialiseValue) } ?: valueDescription(valueIn(configuration), serialiseValue)
|
return delegate.schema?.let { schema -> valueDescription(valueIn(configuration, options).asSequence() .map { element -> valueDescription(element, serialiseValue) } .map { it as ConfigObject } .map(ConfigObject::toConfig) .map { schema.describe(it, serialiseValue, options) } .toList(), serialiseValue) } ?: valueDescription(valueIn(configuration, options), serialiseValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <MAPPED> mapValid(mappedTypeName: String, convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>): Configuration.Property.Definition.Required<MAPPED> = ListMappingProperty(this, mappedTypeName, convert)
|
override fun <MAPPED> mapValid(mappedTypeName: String, convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>): Configuration.Property.Definition.Required<MAPPED> = ListMappingProperty(this, mappedTypeName, convert)
|
||||||
@ -187,18 +195,16 @@ private class OptionalDelegatedProperty<TYPE>(private val delegate: Configuratio
|
|||||||
|
|
||||||
override val typeName: String = "${delegate.typeName}?"
|
override val typeName: String = "${delegate.typeName}?"
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue) = if (isSpecifiedBy(configuration)) delegate.describe(configuration, serialiseValue) else null
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options) = if (isSpecifiedBy(configuration)) delegate.describe(configuration, serialiseValue, options) else null
|
||||||
|
|
||||||
override fun valueIn(configuration: Config): TYPE? {
|
|
||||||
|
|
||||||
|
override fun valueIn(configuration: Config, options: Configuration.Options): TYPE? {
|
||||||
return when {
|
return when {
|
||||||
isSpecifiedBy(configuration) -> delegate.valueIn(configuration)
|
isSpecifiedBy(configuration) -> delegate.valueIn(configuration, options)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
|
|
||||||
val result = delegate.validate(target, options)
|
val result = delegate.validate(target, options)
|
||||||
val errors = result.errors
|
val errors = result.errors
|
||||||
val missingValueError = errors.asSequence().filterIsInstance<Configuration.Validation.Error.MissingValue>().filter { it.pathAsString == key }.singleOrNull()
|
val missingValueError = errors.asSequence().filterIsInstance<Configuration.Validation.Error.MissingValue>().filter { it.pathAsString == key }.singleOrNull()
|
||||||
@ -221,18 +227,17 @@ private abstract class RequiredDelegatedProperty<TYPE, DELEGATE : Configuration.
|
|||||||
|
|
||||||
private class ListMappingProperty<TYPE, MAPPED>(private val delegate: Configuration.Property.Definition.RequiredList<TYPE>, private val mappedTypeName: String, private val convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>) : Configuration.Property.Definition.Required<MAPPED> {
|
private class ListMappingProperty<TYPE, MAPPED>(private val delegate: Configuration.Property.Definition.RequiredList<TYPE>, private val mappedTypeName: String, private val convert: (List<TYPE>) -> Validated<MAPPED, Configuration.Validation.Error>) : Configuration.Property.Definition.Required<MAPPED> {
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue? = delegate.describe(configuration, serialiseValue)
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue? = delegate.describe(configuration, serialiseValue, options)
|
||||||
|
|
||||||
override fun valueIn(configuration: Config) = convert.invoke(delegate.valueIn(configuration)).value()
|
override fun valueIn(configuration: Config, options: Configuration.Options) = convert.invoke(delegate.valueIn(configuration, options)).value()
|
||||||
|
|
||||||
override fun optional(): Configuration.Property.Definition.Optional<MAPPED> = OptionalDelegatedProperty(this)
|
override fun optional(): Configuration.Property.Definition.Optional<MAPPED> = OptionalDelegatedProperty(this)
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Validated<Config, Configuration.Validation.Error> {
|
override fun validate(target: Config, options: Configuration.Options): Validated<Config, Configuration.Validation.Error> {
|
||||||
|
|
||||||
val errors = mutableSetOf<Configuration.Validation.Error>()
|
val errors = mutableSetOf<Configuration.Validation.Error>()
|
||||||
errors += delegate.validate(target, options).errors
|
errors += delegate.validate(target, options).errors
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
errors += convert.invoke(delegate.valueIn(target)).mapErrors { error -> error.with(delegate.key, mappedTypeName) }.errors
|
errors += convert.invoke(delegate.valueIn(target, options)).mapErrors { error -> error.with(delegate.key, mappedTypeName) }.errors
|
||||||
}
|
}
|
||||||
return Validated.withResult(target, errors)
|
return Validated.withResult(target, errors)
|
||||||
}
|
}
|
||||||
@ -248,7 +253,6 @@ private class ListMappingProperty<TYPE, MAPPED>(private val delegate: Configurat
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ConfigException.toValidationError(keyName: String? = null, typeName: String): Configuration.Validation.Error {
|
fun ConfigException.toValidationError(keyName: String? = null, typeName: String): Configuration.Validation.Error {
|
||||||
|
|
||||||
val toError = when (this) {
|
val toError = when (this) {
|
||||||
is ConfigException.Missing -> Configuration.Validation.Error.MissingValue.Companion::of
|
is ConfigException.Missing -> Configuration.Validation.Error.MissingValue.Companion::of
|
||||||
is ConfigException.WrongType -> Configuration.Validation.Error.WrongType.Companion::of
|
is ConfigException.WrongType -> Configuration.Validation.Error.WrongType.Companion::of
|
||||||
@ -260,10 +264,9 @@ fun ConfigException.toValidationError(keyName: String? = null, typeName: String)
|
|||||||
return toError.invoke(message!!, keyName, typeName, emptyList())
|
return toError.invoke(message!!, keyName, typeName, emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Configuration.Property.Definition<*>.errorsWhenExtractingValue(target: Config): Set<Configuration.Validation.Error> {
|
private fun Configuration.Property.Definition<*>.errorsWhenExtractingValue(target: Config, options: Configuration.Options): Set<Configuration.Validation.Error> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
valueIn(target)
|
valueIn(target, options)
|
||||||
return emptySet()
|
return emptySet()
|
||||||
} catch (exception: ConfigException) {
|
} catch (exception: ConfigException) {
|
||||||
if (isErrorExpected(exception)) {
|
if (isErrorExpected(exception)) {
|
||||||
|
@ -16,7 +16,7 @@ internal class Schema(override val name: String?, unorderedProperties: Iterable<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun validate(target: Config, options: Configuration.Validation.Options): Valid<Config> {
|
override fun validate(target: Config, options: Configuration.Options): Valid<Config> {
|
||||||
|
|
||||||
val propertyErrors = properties.flatMap { property ->
|
val propertyErrors = properties.flatMap { property ->
|
||||||
property.validate(target, options).errors
|
property.validate(target, options).errors
|
||||||
@ -47,9 +47,9 @@ internal class Schema(override val name: String?, unorderedProperties: Iterable<
|
|||||||
return description.toString()
|
return description.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue): ConfigValue {
|
override fun describe(configuration: Config, serialiseValue: (Any?) -> ConfigValue, options: Configuration.Options): ConfigValue {
|
||||||
|
|
||||||
return properties.asSequence().map { it.key to it.describe(configuration, serialiseValue) }.filter { it.second != null }.fold(configObject()) { config, (key, value) -> config.withValue(key, value) }
|
return properties.asSequence().map { it.key to it.describe(configuration, serialiseValue, options) }.filter { it.second != null }.fold(configObject()) { config, (key, value) -> config.withValue(key, value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
@ -21,7 +21,11 @@ inline fun <TYPE, reified MAPPED> Configuration.Property.Definition.RequiredList
|
|||||||
|
|
||||||
inline fun <TYPE, reified MAPPED> Configuration.Property.Definition.RequiredList<TYPE>.map(noinline convert: (List<TYPE>) -> MAPPED): Configuration.Property.Definition.Required<MAPPED> = map(MAPPED::class.java.simpleName, convert)
|
inline fun <TYPE, reified MAPPED> Configuration.Property.Definition.RequiredList<TYPE>.map(noinline convert: (List<TYPE>) -> MAPPED): Configuration.Property.Definition.Required<MAPPED> = map(MAPPED::class.java.simpleName, convert)
|
||||||
|
|
||||||
operator fun <TYPE> Config.get(property: Configuration.Property.Definition<TYPE>): TYPE = property.valueIn(this)
|
fun Config.withOptions(options: Configuration.Options) = ConfigurationWithOptions(this, options)
|
||||||
|
|
||||||
|
data class ConfigurationWithOptions(private val config: Config, private val options: Configuration.Options) {
|
||||||
|
operator fun <TYPE> get(property: Configuration.Value.Extractor<TYPE>): TYPE = property.valueIn(config, options)
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <reified NESTED : Any> Configuration.Specification<*>.nested(specification: Configuration.Specification<NESTED>, key: String? = null, sensitive: Boolean = false): PropertyDelegate.Standard<NESTED> = nestedObject(schema = specification, key = key, sensitive = sensitive).map(ConfigObject::toConfig).mapValid { value -> specification.parse(value) }
|
inline fun <reified NESTED : Any> Configuration.Specification<*>.nested(specification: Configuration.Specification<NESTED>, key: String? = null, sensitive: Boolean = false): PropertyDelegate.Standard<NESTED> = nestedObject(schema = specification, key = key, sensitive = sensitive).map(ConfigObject::toConfig).mapValid { value -> specification.parse(value) }
|
||||||
|
|
||||||
@ -66,15 +70,6 @@ internal typealias Valid<TARGET> = Validated<TARGET, Configuration.Validation.Er
|
|||||||
|
|
||||||
internal fun <TYPE> valid(target: TYPE) = Validated.valid<TYPE, Configuration.Validation.Error>(target)
|
internal fun <TYPE> valid(target: TYPE) = Validated.valid<TYPE, Configuration.Validation.Error>(target)
|
||||||
|
|
||||||
/**
|
|
||||||
* Value extracted from a configuration file is a function of the actual value specified and configuration options.
|
|
||||||
* E.g. password value may be stored in the encrypted form rather than in a clear text.
|
|
||||||
*/
|
|
||||||
data class ConfigurationWithOptions(private val config: Config, private val options: Configuration.Validation.Options) {
|
|
||||||
operator fun <TYPE> get(property: Configuration.Property.Definition<TYPE>): TYPE = property.valueIn(config)
|
|
||||||
operator fun <TYPE> get(property: Configuration.Value.Extractor<TYPE>): TYPE = property.valueIn(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper interface to mark objects that will have [ConfigurationWithOptions] in them.
|
* Helper interface to mark objects that will have [ConfigurationWithOptions] in them.
|
||||||
*/
|
*/
|
||||||
|
@ -6,21 +6,17 @@ import net.corda.common.configuration.parsing.internal.Valid
|
|||||||
import net.corda.common.configuration.parsing.internal.valid
|
import net.corda.common.configuration.parsing.internal.valid
|
||||||
|
|
||||||
internal class VersionExtractor(versionPath: String, versionDefaultValue: Int) : Configuration.Version.Extractor {
|
internal class VersionExtractor(versionPath: String, versionDefaultValue: Int) : Configuration.Version.Extractor {
|
||||||
|
|
||||||
private val containingPath = versionPath.split(".").let { if (it.size > 1) it.subList(0, it.size - 1) else null }
|
private val containingPath = versionPath.split(".").let { if (it.size > 1) it.subList(0, it.size - 1) else null }
|
||||||
private val key = versionPath.split(".").last()
|
private val key = versionPath.split(".").last()
|
||||||
|
|
||||||
private val spec = Spec(key, versionDefaultValue, containingPath?.joinToString("."))
|
private val spec = Spec(key, versionDefaultValue, containingPath?.joinToString("."))
|
||||||
|
|
||||||
override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<Int> {
|
override fun parse(configuration: Config, options: Configuration.Options): Valid<Int> {
|
||||||
|
|
||||||
return spec.parse(configuration)
|
return spec.parse(configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Spec(key: String, versionDefaultValue: Int, prefix: String?) : Configuration.Specification<Int>("Version", prefix) {
|
private class Spec(key: String, versionDefaultValue: Int, prefix: String?) : Configuration.Specification<Int>("Version", prefix) {
|
||||||
|
|
||||||
private val version by int(key = key).optional().withDefaultValue(versionDefaultValue)
|
private val version by int(key = key).optional().withDefaultValue(versionDefaultValue)
|
||||||
|
override fun parseValid(configuration: Config, options: Configuration.Options) = valid(version.valueIn(configuration, options))
|
||||||
override fun parseValid(configuration: Config) = valid(version.valueIn(configuration))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,8 +21,8 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value)
|
||||||
assertThat(configuration[property]).isEqualTo(value)
|
assertThat(configuration.withOptions(Configuration.Options.defaults)[property]).isEqualTo(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -38,7 +38,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThatThrownBy { property.valueIn(configuration) }.isInstanceOf(ConfigException.WrongType::class.java)
|
assertThatThrownBy { property.valueIn(configuration, Configuration.Options.defaults) }.isInstanceOf(ConfigException.WrongType::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -54,7 +54,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -70,7 +70,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value.max())
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value.max())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -85,7 +85,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(null)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -101,7 +101,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value.max())
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value.max())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -116,7 +116,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(null)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -132,7 +132,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -147,7 +147,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isNull()
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isNull()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(defaultValue)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -179,7 +179,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isTrue()
|
assertThat(property.isMandatory).isTrue()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThatThrownBy { property.valueIn(configuration) }.isInstanceOf(ConfigException.Missing::class.java)
|
assertThatThrownBy { property.valueIn(configuration, Configuration.Options.defaults) }.isInstanceOf(ConfigException.Missing::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -195,7 +195,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(value)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -211,7 +211,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
assertThat(property.isSpecifiedBy(configuration)).isTrue()
|
||||||
assertThatThrownBy { property.valueIn(configuration) }.isInstanceOf(ConfigException.WrongType::class.java)
|
assertThatThrownBy { property.valueIn(configuration, Configuration.Options.defaults) }.isInstanceOf(ConfigException.WrongType::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -226,7 +226,7 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isNull()
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -242,6 +242,6 @@ class PropertyTest {
|
|||||||
assertThat(property.key).isEqualTo(key)
|
assertThat(property.key).isEqualTo(key)
|
||||||
assertThat(property.isMandatory).isFalse()
|
assertThat(property.isMandatory).isFalse()
|
||||||
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
assertThat(property.isSpecifiedBy(configuration)).isFalse()
|
||||||
assertThat(property.valueIn(configuration)).isEqualTo(defaultValue)
|
assertThat(property.valueIn(configuration, Configuration.Options.defaults)).isEqualTo(defaultValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,7 +15,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key)
|
val property = Configuration.Property.Definition.long(key)
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -34,7 +34,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key)
|
val property = Configuration.Property.Definition.long(key)
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -53,7 +53,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key).list()
|
val property = Configuration.Property.Definition.long(key).list()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -72,7 +72,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key).list()
|
val property = Configuration.Property.Definition.long(key).list()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -94,7 +94,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key).list().mapValid(::parseMax)
|
val property = Configuration.Property.Definition.long(key).list().mapValid(::parseMax)
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).isEmpty()
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -114,7 +114,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val property = Configuration.Property.Definition.long(key).list().mapValid(::parseMax)
|
val property = Configuration.Property.Definition.long(key).list().mapValid(::parseMax)
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.BadValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.BadValue::class.java) { error ->
|
||||||
@ -134,7 +134,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to false).toConfig()
|
val configuration = configObject(key to false).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -154,7 +154,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to 1.2).toConfig()
|
val configuration = configObject(key to 1.2).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -174,7 +174,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to 1).toConfig()
|
val configuration = configObject(key to 1).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).isValid).isTrue()
|
assertThat(property.validate(configuration, Configuration.Options.defaults).isValid).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -186,7 +186,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to listOf(false, true)).toConfig()
|
val configuration = configObject(key to listOf(false, true)).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -206,7 +206,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to listOf(1, 2, 3)).toConfig()
|
val configuration = configObject(key to listOf(1, 2, 3)).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -226,7 +226,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to 1).toConfig()
|
val configuration = configObject(key to 1).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -249,7 +249,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.WrongType::class.java) { error ->
|
||||||
@ -272,7 +272,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to configObject()).toConfig()
|
val configuration = configObject(key to configObject()).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -295,7 +295,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to configObject(nestedKey to null)).toConfig()
|
val configuration = configObject(key to configObject(nestedKey to null)).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).errors).satisfies { errors ->
|
assertThat(property.validate(configuration, Configuration.Options.defaults).errors).satisfies { errors ->
|
||||||
|
|
||||||
assertThat(errors).hasSize(1)
|
assertThat(errors).hasSize(1)
|
||||||
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
assertThat(errors.first()).isInstanceOfSatisfying(Configuration.Validation.Error.MissingValue::class.java) { error ->
|
||||||
@ -317,7 +317,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
val configuration = configObject(key to configObject(nestedKey to false)).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).isValid).isTrue()
|
assertThat(property.validate(configuration, Configuration.Options.defaults).isValid).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -333,7 +333,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to value).toConfig()
|
val configuration = configObject(key to value).toConfig()
|
||||||
|
|
||||||
assertThat(property.validate(configuration).isValid).isTrue()
|
assertThat(property.validate(configuration, Configuration.Options.defaults).isValid).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -350,7 +350,7 @@ class PropertyValidationTest {
|
|||||||
|
|
||||||
val configuration = configObject(key to value).toConfig()
|
val configuration = configObject(key to value).toConfig()
|
||||||
|
|
||||||
val result = property.validate(configuration)
|
val result = property.validate(configuration, Configuration.Options.defaults)
|
||||||
|
|
||||||
assertThat(result.errors).satisfies { errors ->
|
assertThat(result.errors).satisfies { errors ->
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), double("prop5")) }
|
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), double("prop5")) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
||||||
|
|
||||||
val result = barConfigSchema.validate(configuration)
|
val result = barConfigSchema.validate(configuration, Configuration.Options.defaults)
|
||||||
println(barConfigSchema.description())
|
println(barConfigSchema.description())
|
||||||
|
|
||||||
assertThat(result.isValid).isTrue()
|
assertThat(result.isValid).isTrue()
|
||||||
@ -59,17 +59,17 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
||||||
|
|
||||||
val strictErrors = barConfigSchema.validate(configuration, Configuration.Validation.Options(strict = true)).errors
|
val strictErrors = barConfigSchema.validate(configuration, Configuration.Options(strict = true)).errors
|
||||||
|
|
||||||
assertThat(strictErrors).hasSize(2)
|
assertThat(strictErrors).hasSize(2)
|
||||||
assertThat(strictErrors.filter { error -> error.keyName == "prop4" }).hasSize(1)
|
assertThat(strictErrors.filter { error -> error.keyName == "prop4" }).hasSize(1)
|
||||||
assertThat(strictErrors.filter { error -> error.keyName == "prop6" }).hasSize(1)
|
assertThat(strictErrors.filter { error -> error.keyName == "prop6" }).hasSize(1)
|
||||||
|
|
||||||
val errors = barConfigSchema.validate(configuration, Configuration.Validation.Options(strict = false)).errors
|
val errors = barConfigSchema.validate(configuration, Configuration.Options(strict = false)).errors
|
||||||
|
|
||||||
assertThat(errors).isEmpty()
|
assertThat(errors).isEmpty()
|
||||||
|
|
||||||
val errorsWithDefaultOptions = barConfigSchema.validate(configuration).errors
|
val errorsWithDefaultOptions = barConfigSchema.validate(configuration, Configuration.Options.defaults).errors
|
||||||
|
|
||||||
assertThat(errorsWithDefaultOptions).isEmpty()
|
assertThat(errorsWithDefaultOptions).isEmpty()
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
||||||
|
|
||||||
val result = barConfigSchema.validate(configuration)
|
val result = barConfigSchema.validate(configuration, Configuration.Options.defaults)
|
||||||
|
|
||||||
assertThat(result.isValid).isTrue()
|
assertThat(result.isValid).isTrue()
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
val fooConfigSchema = Configuration.Schema.withProperties { setOf(boolean("prop4"), double("prop5")) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
val barConfigSchema = Configuration.Schema.withProperties { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
||||||
|
|
||||||
val errors = barConfigSchema.validate(configuration).errors
|
val errors = barConfigSchema.validate(configuration, Configuration.Options.defaults).errors
|
||||||
errors.forEach(::println)
|
errors.forEach(::println)
|
||||||
|
|
||||||
assertThat(errors).hasSize(2)
|
assertThat(errors).hasSize(2)
|
||||||
@ -154,7 +154,7 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), string("prop5", sensitive = true)) }
|
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), string("prop5", sensitive = true)) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema)) }
|
||||||
|
|
||||||
val printedConfiguration = barConfigSchema.describe(configuration)
|
val printedConfiguration = barConfigSchema.describe(configuration, options = Configuration.Options.defaults)
|
||||||
|
|
||||||
val description = printedConfiguration.serialize().also { println(it) }
|
val description = printedConfiguration.serialize().also { println(it) }
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ class SchemaTest {
|
|||||||
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), string("prop5", sensitive = true)) }
|
val fooConfigSchema = Configuration.Schema.withProperties(name = "Foo") { setOf(boolean("prop4"), string("prop5", sensitive = true)) }
|
||||||
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema).list()) }
|
val barConfigSchema = Configuration.Schema.withProperties(name = "Bar") { setOf(string(prop1), long(prop2), nestedObject("prop3", fooConfigSchema).list()) }
|
||||||
|
|
||||||
val printedConfiguration = barConfigSchema.describe(configuration)
|
val printedConfiguration = barConfigSchema.describe(configuration, options = Configuration.Options.defaults)
|
||||||
|
|
||||||
val description = printedConfiguration.serialize().also { println(it) }
|
val description = printedConfiguration.serialize().also { println(it) }
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.common.configuration.parsing.internal
|
package net.corda.common.configuration.parsing.internal
|
||||||
|
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import net.corda.common.validation.internal.Validated
|
|
||||||
import net.corda.common.validation.internal.Validated.Companion.invalid
|
import net.corda.common.validation.internal.Validated.Companion.invalid
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -16,7 +15,7 @@ class SpecificationTest {
|
|||||||
val principal by string().mapValid(::parseAddress)
|
val principal by string().mapValid(::parseAddress)
|
||||||
val admin by string().mapValid(::parseAddress)
|
val admin by string().mapValid(::parseAddress)
|
||||||
|
|
||||||
override fun parseValid(configuration: Config) = valid(Addresses(configuration[principal], configuration[admin]))
|
override fun parseValid(configuration: Config, options: Configuration.Options) = configuration.withOptions(options).let { valid(Addresses(it[principal], it[admin])) }
|
||||||
|
|
||||||
private fun parseAddress(rawValue: String): Valid<Address> {
|
private fun parseAddress(rawValue: String): Valid<Address> {
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ class SpecificationTest {
|
|||||||
val useSsl by boolean()
|
val useSsl by boolean()
|
||||||
val addresses by nested(AddressesSpec)
|
val addresses by nested(AddressesSpec)
|
||||||
|
|
||||||
override fun parseValid(configuration: Config) = valid<RpcSettings>(RpcSettingsImpl(configuration[addresses], configuration[useSsl]))
|
override fun parseValid(configuration: Config, options: Configuration.Options) = configuration.withOptions(options).let { valid<RpcSettings>(RpcSettingsImpl(it[addresses], it[useSsl])) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -60,9 +59,9 @@ class SpecificationTest {
|
|||||||
|
|
||||||
private val maxElement by long("elements").list().map { elements -> elements.max() }
|
private val maxElement by long("elements").list().map { elements -> elements.max() }
|
||||||
|
|
||||||
override fun parseValid(configuration: Config): Valid<AtomicLong> {
|
override fun parseValid(configuration: Config, options: Configuration.Options): Valid<AtomicLong> {
|
||||||
|
val config = configuration.withOptions(options)
|
||||||
return valid(AtomicLong(configuration[maxElement]!!))
|
return valid(AtomicLong(config[maxElement]!!))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +110,9 @@ class SpecificationTest {
|
|||||||
|
|
||||||
private val maxElement by long("elements").list().mapValid(::parseMax)
|
private val maxElement by long("elements").list().mapValid(::parseMax)
|
||||||
|
|
||||||
override fun parseValid(configuration: Config): Valid<AtomicLong> {
|
override fun parseValid(configuration: Config, options: Configuration.Options): Valid<AtomicLong> {
|
||||||
|
val config = configuration.withOptions(options)
|
||||||
return valid(AtomicLong(configuration[maxElement]))
|
return valid(AtomicLong(config[maxElement]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +158,7 @@ class SpecificationTest {
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val myProp by string().list().optional()
|
val myProp by string().list().optional()
|
||||||
|
|
||||||
override fun parseValid(configuration: Config) = valid(configuration[myProp])
|
override fun parseValid(configuration: Config, options: Configuration.Options) = configuration.withOptions(options).let { valid(it[myProp]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(spec.properties).hasSize(1)
|
assertThat(spec.properties).hasSize(1)
|
||||||
|
@ -15,5 +15,5 @@ internal fun <VALUE> extractValueWithErrors(errors: Set<Configuration.Validation
|
|||||||
|
|
||||||
internal fun <VALUE> extractValue(value: Valid<VALUE>) = object : Configuration.Value.Parser<VALUE> {
|
internal fun <VALUE> extractValue(value: Valid<VALUE>) = object : Configuration.Value.Parser<VALUE> {
|
||||||
|
|
||||||
override fun parse(configuration: Config, options: Configuration.Validation.Options): Valid<VALUE> = value
|
override fun parse(configuration: Config, options: Configuration.Options): Valid<VALUE> = value
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ java8MinUpdateVersion=171
|
|||||||
# When incrementing platformVersion make sure to update #
|
# When incrementing platformVersion make sure to update #
|
||||||
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
|
# net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. #
|
||||||
# ***************************************************************#
|
# ***************************************************************#
|
||||||
platformVersion=6
|
platformVersion=7
|
||||||
guavaVersion=28.0-jre
|
guavaVersion=28.0-jre
|
||||||
# Quasar version to use with Java 8:
|
# Quasar version to use with Java 8:
|
||||||
quasarVersion=0.7.12_r3
|
quasarVersion=0.7.12_r3
|
||||||
@ -21,7 +21,7 @@ quasarVersion11=0.8.0_r3
|
|||||||
jdkClassifier11=jdk11
|
jdkClassifier11=jdk11
|
||||||
proguardVersion=6.1.1
|
proguardVersion=6.1.1
|
||||||
bouncycastleVersion=1.60
|
bouncycastleVersion=1.60
|
||||||
classgraphVersion=4.8.58
|
classgraphVersion=4.8.68
|
||||||
disruptorVersion=3.4.2
|
disruptorVersion=3.4.2
|
||||||
typesafeConfigVersion=1.3.4
|
typesafeConfigVersion=1.3.4
|
||||||
jsr305Version=3.0.2
|
jsr305Version=3.0.2
|
||||||
@ -30,7 +30,7 @@ snakeYamlVersion=1.19
|
|||||||
caffeineVersion=2.7.0
|
caffeineVersion=2.7.0
|
||||||
metricsVersion=4.1.0
|
metricsVersion=4.1.0
|
||||||
metricsNewRelicVersion=1.1.1
|
metricsNewRelicVersion=1.1.1
|
||||||
djvmVersion=1.0-RC10
|
djvmVersion=1.1-RC01
|
||||||
deterministicRtVersion=1.0-RC02
|
deterministicRtVersion=1.0-RC02
|
||||||
openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
|
openSourceBranch=https://github.com/corda/corda/blob/release/os/4.4
|
||||||
openSourceSamplesBranch=https://github.com/corda/samples/blob/release-V4
|
openSourceSamplesBranch=https://github.com/corda/samples/blob/release-V4
|
||||||
|
@ -23,7 +23,6 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import static net.corda.testing.driver.Driver.driver;
|
import static net.corda.testing.driver.Driver.driver;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class FlowExternalOperationInJavaTest extends AbstractFlowExternalOperationTest {
|
public class FlowExternalOperationInJavaTest extends AbstractFlowExternalOperationTest {
|
||||||
|
|
||||||
@ -32,16 +31,16 @@ public class FlowExternalOperationInJavaTest extends AbstractFlowExternalOperati
|
|||||||
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
||||||
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
return KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
return KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
||||||
FlowWithExternalOperationInJava.class,
|
FlowWithExternalOperationInJava.class,
|
||||||
TestUtils.singleIdentity(bob.getNodeInfo())
|
TestUtils.singleIdentity(bob.getNodeInfo())
|
||||||
).getReturnValue(), Duration.of(20, ChronoUnit.SECONDS));
|
).getReturnValue(), Duration.of(1, ChronoUnit.MINUTES));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,16 +49,16 @@ public class FlowExternalOperationInJavaTest extends AbstractFlowExternalOperati
|
|||||||
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
||||||
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
return KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
return KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
||||||
FlowWithExternalAsyncOperationInJava.class,
|
FlowWithExternalAsyncOperationInJava.class,
|
||||||
TestUtils.singleIdentity(bob.getNodeInfo())
|
TestUtils.singleIdentity(bob.getNodeInfo())
|
||||||
).getReturnValue(), Duration.of(20, ChronoUnit.SECONDS));
|
).getReturnValue(), Duration.of(1, ChronoUnit.MINUTES));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,22 +67,18 @@ public class FlowExternalOperationInJavaTest extends AbstractFlowExternalOperati
|
|||||||
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
driver(new DriverParameters().withStartNodesInProcess(true), driver -> {
|
||||||
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
NodeHandle alice = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.ALICE_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
NodeHandle bob = KotlinUtilsKt.getOrThrow(
|
||||||
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
driver.startNode(new NodeParameters().withProvidedName(TestConstants.BOB_NAME)),
|
||||||
Duration.of(20, ChronoUnit.SECONDS)
|
Duration.of(1, ChronoUnit.MINUTES)
|
||||||
);
|
);
|
||||||
KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
||||||
FlowWithExternalOperationThatGetsRetriedInJava.class,
|
FlowWithExternalOperationThatGetsRetriedInJava.class,
|
||||||
TestUtils.singleIdentity(bob.getNodeInfo())
|
TestUtils.singleIdentity(bob.getNodeInfo())
|
||||||
).getReturnValue(), Duration.of(20, ChronoUnit.SECONDS));
|
).getReturnValue(), Duration.of(1, ChronoUnit.MINUTES));
|
||||||
|
|
||||||
HospitalCounts counts = KotlinUtilsKt.getOrThrow(alice.getRpc().startFlowDynamic(
|
assertHospitalCounters(1, 0);
|
||||||
GetHospitalCountersFlow.class
|
|
||||||
).getReturnValue(), Duration.of(20, ChronoUnit.SECONDS));
|
|
||||||
assertEquals(1, counts.getDischarge());
|
|
||||||
assertEquals(0, counts.getObservation());
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -12,26 +12,55 @@ import net.corda.core.flows.StartableByRPC
|
|||||||
import net.corda.core.flows.StartableByService
|
import net.corda.core.flows.StartableByService
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.concurrent.doOnComplete
|
import net.corda.core.internal.concurrent.doOnComplete
|
||||||
|
import net.corda.core.messaging.FlowHandle
|
||||||
import net.corda.core.node.AppServiceHub
|
import net.corda.core.node.AppServiceHub
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.CordaService
|
import net.corda.core.node.services.CordaService
|
||||||
import net.corda.core.schemas.MappedSchema
|
import net.corda.core.schemas.MappedSchema
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.core.utilities.unwrap
|
||||||
import net.corda.node.services.statemachine.StaffedFlowHospital
|
import net.corda.node.services.statemachine.StaffedFlowHospital
|
||||||
|
import org.junit.Before
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.Semaphore
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import javax.persistence.Column
|
import javax.persistence.Column
|
||||||
import javax.persistence.Entity
|
import javax.persistence.Entity
|
||||||
import javax.persistence.Id
|
import javax.persistence.Id
|
||||||
import javax.persistence.Table
|
import javax.persistence.Table
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
abstract class AbstractFlowExternalOperationTest {
|
abstract class AbstractFlowExternalOperationTest {
|
||||||
|
|
||||||
|
var dischargeCounter = 0
|
||||||
|
var observationCounter = 0
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun before() {
|
||||||
|
StaffedFlowHospital.onFlowDischarged.clear()
|
||||||
|
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++dischargeCounter }
|
||||||
|
StaffedFlowHospital.onFlowKeptForOvernightObservation.clear()
|
||||||
|
StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> ++observationCounter }
|
||||||
|
dischargeCounter = 0
|
||||||
|
observationCounter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun blockUntilFlowKeptInForObservation(flow: () -> FlowHandle<*>) {
|
||||||
|
val lock = Semaphore(0)
|
||||||
|
StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> lock.release() }
|
||||||
|
flow()
|
||||||
|
lock.acquire()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertHospitalCounters(discharge: Int, observation: Int) {
|
||||||
|
assertEquals(discharge, dischargeCounter)
|
||||||
|
assertEquals(observation, observationCounter)
|
||||||
|
}
|
||||||
|
|
||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
@InitiatingFlow
|
@InitiatingFlow
|
||||||
@StartableByService
|
@StartableByService
|
||||||
@ -44,11 +73,12 @@ abstract class AbstractFlowExternalOperationTest {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call(): Any {
|
override fun call(): Any {
|
||||||
log.info("Started my flow")
|
log.info("Started my flow")
|
||||||
|
subFlow(PingPongFlow(party))
|
||||||
val result = testCode()
|
val result = testCode()
|
||||||
val session = initiateFlow(party)
|
val session = initiateFlow(party)
|
||||||
session.send("hi there")
|
session.sendAndReceive<String>("hi there").unwrap { it }
|
||||||
log.info("ServiceHub value = $serviceHub")
|
session.sendAndReceive<String>("hi there").unwrap { it }
|
||||||
session.receive<String>()
|
subFlow(PingPongFlow(party))
|
||||||
log.info("Finished my flow")
|
log.info("Finished my flow")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -64,8 +94,28 @@ abstract class AbstractFlowExternalOperationTest {
|
|||||||
class FlowWithExternalOperationResponder(val session: FlowSession) : FlowLogic<Unit>() {
|
class FlowWithExternalOperationResponder(val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun call() {
|
override fun call() {
|
||||||
session.receive<String>()
|
session.receive<String>().unwrap { it }
|
||||||
session.send("go away")
|
session.send("go away")
|
||||||
|
session.receive<String>().unwrap { it }
|
||||||
|
session.send("go away")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatingFlow
|
||||||
|
class PingPongFlow(val party: Party): FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val session = initiateFlow(party)
|
||||||
|
session.sendAndReceive<String>("ping pong").unwrap { it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(PingPongFlow::class)
|
||||||
|
class PingPongResponder(val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
session.receive<String>().unwrap { it }
|
||||||
|
session.send("I got you bro")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +133,7 @@ abstract class AbstractFlowExternalOperationTest {
|
|||||||
fun createFuture(): CompletableFuture<Any> {
|
fun createFuture(): CompletableFuture<Any> {
|
||||||
return CompletableFuture.supplyAsync(Supplier<Any> {
|
return CompletableFuture.supplyAsync(Supplier<Any> {
|
||||||
log.info("Starting sleep inside of future")
|
log.info("Starting sleep inside of future")
|
||||||
Thread.sleep(2000)
|
Thread.sleep(1000)
|
||||||
log.info("Finished sleep inside of future")
|
log.info("Finished sleep inside of future")
|
||||||
"Here is your return value"
|
"Here is your return value"
|
||||||
}, executorService)
|
}, executorService)
|
||||||
@ -182,31 +232,6 @@ abstract class AbstractFlowExternalOperationTest {
|
|||||||
|
|
||||||
object CustomMappedSchema : MappedSchema(CustomSchema::class.java, 1, listOf(CustomTableEntity::class.java))
|
object CustomMappedSchema : MappedSchema(CustomSchema::class.java, 1, listOf(CustomTableEntity::class.java))
|
||||||
|
|
||||||
// Internal use for testing only!!
|
|
||||||
@StartableByRPC
|
|
||||||
class GetHospitalCountersFlow : FlowLogic<HospitalCounts>() {
|
|
||||||
override fun call(): HospitalCounts =
|
|
||||||
HospitalCounts(
|
|
||||||
serviceHub.cordaService(HospitalCounter::class.java).dischargeCounter,
|
|
||||||
serviceHub.cordaService(HospitalCounter::class.java).observationCounter
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class HospitalCounts(val discharge: Int, val observation: Int)
|
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
@CordaService
|
|
||||||
class HospitalCounter(services: AppServiceHub) : SingletonSerializeAsToken() {
|
|
||||||
var observationCounter: Int = 0
|
|
||||||
var dischargeCounter: Int = 0
|
|
||||||
|
|
||||||
init {
|
|
||||||
StaffedFlowHospital.onFlowDischarged.add { _, _ -> ++dischargeCounter }
|
|
||||||
StaffedFlowHospital.onFlowKeptForOvernightObservation.add { _, _ -> ++observationCounter }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyCordaException(message: String) : CordaException(message)
|
class MyCordaException(message: String) : CordaException(message)
|
||||||
|
|
||||||
class DirectlyAccessedServiceHubException : CordaException("Null pointer from accessing flow's serviceHub")
|
class DirectlyAccessedServiceHubException : CordaException("Null pointer from accessing flow's serviceHub")
|
||||||
|
@ -6,12 +6,7 @@ import net.corda.core.flows.StartableByRPC
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.DirectlyAccessedServiceHubException
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.ExternalAsyncOperation
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.FlowWithExternalProcess
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.FutureService
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.MyCordaException
|
|
||||||
import net.corda.node.services.statemachine.StateTransitionException
|
import net.corda.node.services.statemachine.StateTransitionException
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_NAME
|
import net.corda.testing.core.BOB_NAME
|
||||||
@ -21,27 +16,23 @@ import net.corda.testing.driver.driver
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation`() {
|
fun `external async operation`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::FlowWithExternalAsyncOperation, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::FlowWithExternalAsyncOperation, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that checks deduplicationId is not rerun when flow is retried`() {
|
fun `external async operation that checks deduplicationId is not rerun when flow is retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -50,15 +41,13 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationWithDeduplication,
|
::FlowWithExternalAsyncOperationWithDeduplication,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(1, 0)
|
||||||
assertEquals(1, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation propagates exception to calling flow`() {
|
fun `external async operation propagates exception to calling flow`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -68,15 +57,13 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
::FlowWithExternalAsyncOperationPropagatesException,
|
::FlowWithExternalAsyncOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
MyCordaException::class.java
|
MyCordaException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation exception can be caught in flow`() {
|
fun `external async operation exception can be caught in flow`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -84,83 +71,73 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
val result = alice.rpc.startFlow(
|
val result = alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationThatThrowsExceptionAndCaughtInFlow,
|
::FlowWithExternalAsyncOperationThatThrowsExceptionAndCaughtInFlow,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(result as Boolean)
|
assertTrue(result as Boolean)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation with exception that hospital keeps for observation does not fail`() {
|
fun `external async operation with exception that hospital keeps for observation does not fail`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationPropagatesException,
|
::FlowWithExternalAsyncOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
HospitalizeFlowException::class.java
|
HospitalizeFlowException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 1)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation with exception that hospital discharges is retried and runs the future again`() {
|
fun `external async operation with exception that hospital discharges is retried and runs the future again`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationPropagatesException,
|
::FlowWithExternalAsyncOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
SQLTransientConnectionException::class.java
|
SQLTransientConnectionException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(3, 1)
|
||||||
assertEquals(3, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that throws exception rather than completing future exceptionally fails with internal exception`() {
|
fun `external async operation that throws exception rather than completing future exceptionally fails with internal exception`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<StateTransitionException> {
|
assertFailsWith<StateTransitionException> {
|
||||||
alice.rpc.startFlow(::FlowWithExternalAsyncOperationUnhandledException, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::FlowWithExternalAsyncOperationUnhandledException, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that passes serviceHub into process can be retried`() {
|
fun `external async operation that passes serviceHub into process can be retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationThatPassesInServiceHubCanRetry,
|
::FlowWithExternalAsyncOperationThatPassesInServiceHubCanRetry,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(3, 1)
|
||||||
assertEquals(3, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that accesses serviceHub from flow directly will fail when retried`() {
|
fun `external async operation that accesses serviceHub from flow directly will fail when retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -169,23 +146,19 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalAsyncOperationThatDirectlyAccessesServiceHubFailsRetry,
|
::FlowWithExternalAsyncOperationThatDirectlyAccessesServiceHubFailsRetry,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(1, 0)
|
||||||
assertEquals(1, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `starting multiple futures and joining on their results`() {
|
fun `starting multiple futures and joining on their results`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::FlowThatStartsMultipleFuturesAndJoins, bob.nodeInfo.singleIdentity()).returnValue.getOrThrow(20.seconds)
|
alice.rpc.startFlow(::FlowThatStartsMultipleFuturesAndJoins, bob.nodeInfo.singleIdentity()).returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +177,14 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
FlowWithExternalProcess(party) {
|
FlowWithExternalProcess(party) {
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any =
|
override fun testCode(): Any {
|
||||||
await(ExternalAsyncOperation(serviceHub) { _, _ ->
|
val e = createException()
|
||||||
|
return await(ExternalAsyncOperation(serviceHub) { _, _ ->
|
||||||
CompletableFuture<Any>().apply {
|
CompletableFuture<Any>().apply {
|
||||||
completeExceptionally(createException())
|
completeExceptionally(e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private fun createException() = when (exceptionType) {
|
private fun createException() = when (exceptionType) {
|
||||||
HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around")
|
HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around")
|
||||||
|
@ -5,40 +5,35 @@ import net.corda.core.flows.StartableByRPC
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.BOB_NAME
|
import net.corda.testing.core.BOB_NAME
|
||||||
import net.corda.testing.core.singleIdentity
|
import net.corda.testing.core.singleIdentity
|
||||||
import net.corda.testing.driver.DriverParameters
|
import net.corda.testing.driver.DriverParameters
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
class FlowExternalOperationStartFlowTest : AbstractFlowExternalOperationTest() {
|
class FlowExternalOperationStartFlowTest : AbstractFlowExternalOperationTest() {
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `starting a flow inside of a flow that starts a future will succeed`() {
|
fun `starting a flow inside of a flow that starts a future will succeed`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::FlowThatStartsAnotherFlowInAnExternalOperation, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::FlowThatStartsAnotherFlowInAnExternalOperation, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(40.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `multiple flows can be started and their futures joined from inside a flow`() {
|
fun `multiple flows can be started and their futures joined from inside a flow`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::ForkJoinFlows, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::ForkJoinFlows, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(40.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,7 @@ import net.corda.core.messaging.startFlow
|
|||||||
import net.corda.core.node.services.queryBy
|
import net.corda.core.node.services.queryBy
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.CustomTableEntity
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.DirectlyAccessedServiceHubException
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.ExternalOperation
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.FlowWithExternalProcess
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.FutureService
|
|
||||||
import net.corda.coretests.flows.AbstractFlowExternalOperationTest.MyCordaException
|
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.contracts.DummyState
|
import net.corda.testing.contracts.DummyState
|
||||||
import net.corda.testing.core.ALICE_NAME
|
import net.corda.testing.core.ALICE_NAME
|
||||||
@ -26,29 +20,24 @@ import net.corda.testing.driver.DriverParameters
|
|||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import net.corda.testing.node.internal.cordappsForPackages
|
import net.corda.testing.node.internal.cordappsForPackages
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.lang.IllegalStateException
|
|
||||||
import java.sql.SQLTransientConnectionException
|
import java.sql.SQLTransientConnectionException
|
||||||
import java.util.concurrent.TimeoutException
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation`() {
|
fun `external operation`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::FlowWithExternalOperation, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::FlowWithExternalOperation, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation that checks deduplicationId is not rerun when flow is retried`() {
|
fun `external operation that checks deduplicationId is not rerun when flow is retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -57,15 +46,13 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationWithDeduplication,
|
::FlowWithExternalOperationWithDeduplication,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(1, 0)
|
||||||
assertEquals(1, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation propagates exception to calling flow`() {
|
fun `external operation propagates exception to calling flow`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -75,81 +62,71 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
::FlowWithExternalOperationPropagatesException,
|
::FlowWithExternalOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
MyCordaException::class.java
|
MyCordaException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation exception can be caught in flow`() {
|
fun `external operation exception can be caught in flow`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
alice.rpc.startFlow(::FlowWithExternalOperationThatThrowsExceptionAndCaughtInFlow, bob.nodeInfo.singleIdentity())
|
alice.rpc.startFlow(::FlowWithExternalOperationThatThrowsExceptionAndCaughtInFlow, bob.nodeInfo.singleIdentity())
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 0)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation with exception that hospital keeps for observation does not fail`() {
|
fun `external operation with exception that hospital keeps for observation does not fail`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationPropagatesException,
|
::FlowWithExternalOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
HospitalizeFlowException::class.java
|
HospitalizeFlowException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(0, 1)
|
||||||
assertEquals(0, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation with exception that hospital discharges is retried and runs the external operation again`() {
|
fun `external operation with exception that hospital discharges is retried and runs the external operation again`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationPropagatesException,
|
::FlowWithExternalOperationPropagatesException,
|
||||||
bob.nodeInfo.singleIdentity(),
|
bob.nodeInfo.singleIdentity(),
|
||||||
SQLTransientConnectionException::class.java
|
SQLTransientConnectionException::class.java
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(3, 1)
|
||||||
assertEquals(3, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that passes serviceHub into process can be retried`() {
|
fun `external async operation that passes serviceHub into process can be retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
assertFailsWith<TimeoutException> {
|
blockUntilFlowKeptInForObservation {
|
||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationThatPassesInServiceHubCanRetry,
|
::FlowWithExternalOperationThatPassesInServiceHubCanRetry,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(3, 1)
|
||||||
assertEquals(3, discharged)
|
|
||||||
assertEquals(1, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external async operation that accesses serviceHub from flow directly will fail when retried`() {
|
fun `external async operation that accesses serviceHub from flow directly will fail when retried`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -158,15 +135,13 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
alice.rpc.startFlow(
|
alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationThatDirectlyAccessesServiceHubFailsRetry,
|
::FlowWithExternalOperationThatDirectlyAccessesServiceHubFailsRetry,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
}
|
}
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(1, 0)
|
||||||
assertEquals(1, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `vault can be queried`() {
|
fun `vault can be queried`() {
|
||||||
driver(
|
driver(
|
||||||
DriverParameters(
|
DriverParameters(
|
||||||
@ -176,52 +151,52 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
) {
|
) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val success = alice.rpc.startFlow(::FlowWithWithExternalOperationThatQueriesVault)
|
val success = alice.rpc.startFlow(::FlowWithWithExternalOperationThatQueriesVault)
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `data can be persisted to node database via entity manager`() {
|
fun `data can be persisted to node database via entity manager`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaEntityManager)
|
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaEntityManager)
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `data can be persisted to node database via jdbc session`() {
|
fun `data can be persisted to node database via jdbc session`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaJdbcSession)
|
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaJdbcSession)
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `data can be persisted to node database via servicehub database transaction`() {
|
fun `data can be persisted to node database via servicehub database transaction`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaDatabaseTransaction)
|
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsViaDatabaseTransaction)
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `data can be persisted to node database in external operation and read from another process once finished`() {
|
fun `data can be persisted to node database in external operation and read from another process once finished`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsToDatabaseAndReadsFromExternalOperation)
|
val success = alice.rpc.startFlow(::FlowWithExternalOperationThatPersistsToDatabaseAndReadsFromExternalOperation)
|
||||||
.returnValue.getOrThrow(20.seconds)
|
.returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout = 300_000)
|
||||||
fun `external operation can be retried when an error occurs inside of database transaction`() {
|
fun `external operation can be retried when an error occurs inside of database transaction`() {
|
||||||
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
@ -229,11 +204,9 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
val success = alice.rpc.startFlow(
|
val success = alice.rpc.startFlow(
|
||||||
::FlowWithExternalOperationThatErrorsInsideOfDatabaseTransaction,
|
::FlowWithExternalOperationThatErrorsInsideOfDatabaseTransaction,
|
||||||
bob.nodeInfo.singleIdentity()
|
bob.nodeInfo.singleIdentity()
|
||||||
).returnValue.getOrThrow(20.seconds)
|
).returnValue.getOrThrow(1.minutes)
|
||||||
assertTrue(success as Boolean)
|
assertTrue(success as Boolean)
|
||||||
val (discharged, observation) = alice.rpc.startFlow(::GetHospitalCountersFlow).returnValue.getOrThrow()
|
assertHospitalCounters(1, 0)
|
||||||
assertEquals(1, discharged)
|
|
||||||
assertEquals(0, observation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +233,10 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() {
|
|||||||
FlowWithExternalProcess(party) {
|
FlowWithExternalProcess(party) {
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
override fun testCode(): Any = await(ExternalOperation(serviceHub) { _, _ -> throw createException() })
|
override fun testCode() {
|
||||||
|
val e = createException()
|
||||||
|
await(ExternalOperation(serviceHub) { _, _ -> throw e })
|
||||||
|
}
|
||||||
|
|
||||||
private fun createException() = when (exceptionType) {
|
private fun createException() = when (exceptionType) {
|
||||||
HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around")
|
HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around")
|
||||||
|
@ -0,0 +1,364 @@
|
|||||||
|
package net.corda.coretests.flows
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.FlowSession
|
||||||
|
import net.corda.core.flows.InitiatedBy
|
||||||
|
import net.corda.core.flows.InitiatingFlow
|
||||||
|
import net.corda.core.flows.KilledFlowException
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.flows.StateMachineRunId
|
||||||
|
import net.corda.core.flows.UnexpectedFlowEndException
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.core.utilities.minutes
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.BOB_NAME
|
||||||
|
import net.corda.testing.core.CHARLIE_NAME
|
||||||
|
import net.corda.testing.core.singleIdentity
|
||||||
|
import net.corda.testing.driver.DriverParameters
|
||||||
|
import net.corda.testing.driver.driver
|
||||||
|
import org.apache.logging.log4j.Level
|
||||||
|
import org.apache.logging.log4j.core.config.Configurator
|
||||||
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.concurrent.Semaphore
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class FlowIsKilledTest {
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val EXCEPTION_MESSAGE = "Goodbye, cruel world!"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
Configurator.setLevel("net.corda.node.services.statemachine", Level.DEBUG)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `manually handle the isKilled check`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
alice.rpc.let { rpc ->
|
||||||
|
val handle = rpc.startFlow(::AFlowThatWantsToDie)
|
||||||
|
AFlowThatWantsToDie.lockA.acquire()
|
||||||
|
rpc.killFlow(handle.id)
|
||||||
|
AFlowThatWantsToDie.lockB.release()
|
||||||
|
assertThatExceptionOfType(KilledFlowException::class.java)
|
||||||
|
.isThrownBy { handle.returnValue.getOrThrow(1.minutes) }
|
||||||
|
.withMessage(EXCEPTION_MESSAGE)
|
||||||
|
assertEquals(11, AFlowThatWantsToDie.position)
|
||||||
|
val checkpoints = rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, checkpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `manually handled killed flows propagate error to counter parties`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
|
val charlie = startNode(providedName = CHARLIE_NAME).getOrThrow()
|
||||||
|
alice.rpc.let { rpc ->
|
||||||
|
val handle = rpc.startFlow(
|
||||||
|
::AFlowThatWantsToDieAndKillsItsFriends,
|
||||||
|
listOf(bob.nodeInfo.singleIdentity(), charlie.nodeInfo.singleIdentity())
|
||||||
|
)
|
||||||
|
AFlowThatWantsToDieAndKillsItsFriends.lockA.acquire()
|
||||||
|
AFlowThatWantsToDieAndKillsItsFriendsResponder.locks.forEach { it.value.acquire() }
|
||||||
|
rpc.killFlow(handle.id)
|
||||||
|
AFlowThatWantsToDieAndKillsItsFriends.lockB.release()
|
||||||
|
assertThatExceptionOfType(KilledFlowException::class.java)
|
||||||
|
.isThrownBy { handle.returnValue.getOrThrow(1.minutes) }
|
||||||
|
.withMessage(EXCEPTION_MESSAGE)
|
||||||
|
AFlowThatWantsToDieAndKillsItsFriendsResponder.locks.forEach { it.value.acquire() }
|
||||||
|
assertEquals(11, AFlowThatWantsToDieAndKillsItsFriends.position)
|
||||||
|
assertTrue(AFlowThatWantsToDieAndKillsItsFriendsResponder.receivedKilledExceptions[BOB_NAME]!!)
|
||||||
|
assertTrue(AFlowThatWantsToDieAndKillsItsFriendsResponder.receivedKilledExceptions[CHARLIE_NAME]!!)
|
||||||
|
val aliceCheckpoints = alice.rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, aliceCheckpoints)
|
||||||
|
val bobCheckpoints = bob.rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, bobCheckpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `a manually killed initiated flow will propagate the killed error to the initiator and its counter parties`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
|
val handle = alice.rpc.startFlow(
|
||||||
|
::AFlowThatGetsMurderedByItsFriend,
|
||||||
|
bob.nodeInfo.singleIdentity()
|
||||||
|
)
|
||||||
|
|
||||||
|
AFlowThatGetsMurderedByItsFriendResponder.lockA.acquire()
|
||||||
|
|
||||||
|
val initiatedFlowId = AFlowThatGetsMurderedByItsFriendResponder.flowId!!
|
||||||
|
|
||||||
|
bob.rpc.killFlow(initiatedFlowId)
|
||||||
|
|
||||||
|
AFlowThatGetsMurderedByItsFriendResponder.lockB.release()
|
||||||
|
|
||||||
|
assertFailsWith<UnexpectedFlowEndException> {
|
||||||
|
handle.returnValue.getOrThrow(1.minutes)
|
||||||
|
}
|
||||||
|
assertTrue(AFlowThatGetsMurderedByItsFriend.receivedKilledException)
|
||||||
|
assertEquals(11, AFlowThatGetsMurderedByItsFriendResponder.position)
|
||||||
|
val aliceCheckpoints = alice.rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, aliceCheckpoints)
|
||||||
|
val bobCheckpoints = bob.rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, bobCheckpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `manually handle killed flows using checkForIsNotKilled`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
alice.rpc.let { rpc ->
|
||||||
|
val handle = rpc.startFlow(::AFlowThatChecksIfItWantsToDie)
|
||||||
|
AFlowThatChecksIfItWantsToDie.lockA.acquire()
|
||||||
|
rpc.killFlow(handle.id)
|
||||||
|
AFlowThatChecksIfItWantsToDie.lockB.release()
|
||||||
|
assertThatExceptionOfType(KilledFlowException::class.java)
|
||||||
|
.isThrownBy { handle.returnValue.getOrThrow(1.minutes) }
|
||||||
|
.withMessageNotContaining(EXCEPTION_MESSAGE)
|
||||||
|
assertEquals(11, AFlowThatChecksIfItWantsToDie.position)
|
||||||
|
val checkpoints = rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, checkpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `manually handle killed flows using checkForIsNotKilled with lazy message`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
alice.rpc.let { rpc ->
|
||||||
|
val handle = rpc.startFlow(::AFlowThatChecksIfItWantsToDieAndLeavesANote)
|
||||||
|
AFlowThatChecksIfItWantsToDieAndLeavesANote.lockA.acquire()
|
||||||
|
rpc.killFlow(handle.id)
|
||||||
|
AFlowThatChecksIfItWantsToDieAndLeavesANote.lockB.release()
|
||||||
|
assertThatExceptionOfType(KilledFlowException::class.java)
|
||||||
|
.isThrownBy { handle.returnValue.getOrThrow(1.minutes) }
|
||||||
|
.withMessage(EXCEPTION_MESSAGE)
|
||||||
|
assertEquals(11, AFlowThatChecksIfItWantsToDie.position)
|
||||||
|
val checkpoints = rpc.startFlow(::GetNumberOfCheckpointsFlow).returnValue.getOrThrow(20.seconds)
|
||||||
|
assertEquals(1, checkpoints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class AFlowThatWantsToDie : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val lockA = Semaphore(0)
|
||||||
|
val lockB = Semaphore(0)
|
||||||
|
|
||||||
|
var position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
for (i in 0..100) {
|
||||||
|
position = i
|
||||||
|
logger.info("i = $i")
|
||||||
|
if (isKilled) {
|
||||||
|
throw KilledFlowException(runId, EXCEPTION_MESSAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
lockA.release()
|
||||||
|
lockB.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
@InitiatingFlow
|
||||||
|
class AFlowThatWantsToDieAndKillsItsFriends(private val parties: List<Party>) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val lockA = Semaphore(0)
|
||||||
|
val lockB = Semaphore(0)
|
||||||
|
var position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val sessionOne = initiateFlow(parties[0])
|
||||||
|
val sessionTwo = initiateFlow(parties[1])
|
||||||
|
// trigger sessions with 2 counter parties
|
||||||
|
sessionOne.sendAndReceive<String>("what is up")
|
||||||
|
sessionOne.send("what is up 2")
|
||||||
|
sessionTwo.sendAndReceive<String>("what is up")
|
||||||
|
sessionTwo.send("what is up 2")
|
||||||
|
for (i in 0..100) {
|
||||||
|
position = i
|
||||||
|
logger.info("i = $i")
|
||||||
|
if (isKilled) {
|
||||||
|
throw KilledFlowException(runId, EXCEPTION_MESSAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
lockA.release()
|
||||||
|
lockB.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(AFlowThatWantsToDieAndKillsItsFriends::class)
|
||||||
|
class AFlowThatWantsToDieAndKillsItsFriendsResponder(private val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val locks = mapOf(
|
||||||
|
BOB_NAME to Semaphore(0),
|
||||||
|
CHARLIE_NAME to Semaphore(0)
|
||||||
|
)
|
||||||
|
var receivedKilledExceptions = mutableMapOf(
|
||||||
|
BOB_NAME to false,
|
||||||
|
CHARLIE_NAME to false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
session.receive<String>()
|
||||||
|
session.send("hi")
|
||||||
|
session.receive<String>()
|
||||||
|
locks[ourIdentity.name]!!.release()
|
||||||
|
try {
|
||||||
|
session.receive<String>()
|
||||||
|
} catch (e: UnexpectedFlowEndException) {
|
||||||
|
receivedKilledExceptions[ourIdentity.name] = true
|
||||||
|
locks[ourIdentity.name]!!.release()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
@InitiatingFlow
|
||||||
|
class AFlowThatGetsMurderedByItsFriend(private val party: Party) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var receivedKilledException = false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val sessionOne = initiateFlow(party)
|
||||||
|
// trigger sessions with 2 counter parties
|
||||||
|
sessionOne.sendAndReceive<String>("what is up")
|
||||||
|
try {
|
||||||
|
sessionOne.receive<String>()
|
||||||
|
} catch (e: UnexpectedFlowEndException) {
|
||||||
|
receivedKilledException = true
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(AFlowThatGetsMurderedByItsFriend::class)
|
||||||
|
class AFlowThatGetsMurderedByItsFriendResponder(private val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val lockA = Semaphore(0)
|
||||||
|
val lockB = Semaphore(0)
|
||||||
|
var flowId: StateMachineRunId? = null
|
||||||
|
var position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
flowId = runId
|
||||||
|
session.receive<String>()
|
||||||
|
session.send("hi")
|
||||||
|
for (i in 0..100) {
|
||||||
|
position = i
|
||||||
|
if (isKilled) {
|
||||||
|
throw KilledFlowException(runId, EXCEPTION_MESSAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
lockA.release()
|
||||||
|
lockB.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class AFlowThatChecksIfItWantsToDie : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val lockA = Semaphore(0)
|
||||||
|
val lockB = Semaphore(0)
|
||||||
|
|
||||||
|
var position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
for (i in 0..100) {
|
||||||
|
position = i
|
||||||
|
logger.info("i = $i")
|
||||||
|
checkFlowIsNotKilled()
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
lockA.release()
|
||||||
|
lockB.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class AFlowThatChecksIfItWantsToDieAndLeavesANote : FlowLogic<Unit>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val lockA = Semaphore(0)
|
||||||
|
val lockB = Semaphore(0)
|
||||||
|
|
||||||
|
var position = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
for (i in 0..100) {
|
||||||
|
position = i
|
||||||
|
logger.info("i = $i")
|
||||||
|
checkFlowIsNotKilled { EXCEPTION_MESSAGE }
|
||||||
|
|
||||||
|
if (i == 10) {
|
||||||
|
lockA.release()
|
||||||
|
lockB.acquire()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class GetNumberOfCheckpointsFlow : FlowLogic<Long>() {
|
||||||
|
override fun call(): Long {
|
||||||
|
return serviceHub.jdbcSession().prepareStatement("select count(*) from node_checkpoints").use { ps ->
|
||||||
|
ps.executeQuery().use { rs ->
|
||||||
|
rs.next()
|
||||||
|
rs.getLong(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
package net.corda.coretests.flows
|
||||||
|
|
||||||
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.FlowSession
|
||||||
|
import net.corda.core.flows.InitiatedBy
|
||||||
|
import net.corda.core.flows.InitiatingFlow
|
||||||
|
import net.corda.core.flows.StartableByRPC
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.messaging.startFlow
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.core.utilities.minutes
|
||||||
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.core.utilities.unwrap
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.BOB_NAME
|
||||||
|
import net.corda.testing.core.singleIdentity
|
||||||
|
import net.corda.testing.driver.DriverParameters
|
||||||
|
import net.corda.testing.driver.driver
|
||||||
|
import org.apache.logging.log4j.Level
|
||||||
|
import org.apache.logging.log4j.core.config.Configurator
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import java.time.Duration
|
||||||
|
import java.time.Instant
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class FlowSleepTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
Configurator.setLevel("net.corda.node.services.statemachine", Level.DEBUG)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `flow can sleep`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val (start, finish) = alice.rpc.startFlow(::SleepyFlow).returnValue.getOrThrow(1.minutes)
|
||||||
|
val difference = Duration.between(start, finish)
|
||||||
|
assertTrue(difference >= 5.seconds)
|
||||||
|
assertTrue(difference < 7.seconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `flow can sleep multiple times`() {
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val (start, middle, finish) = alice.rpc.startFlow(::AnotherSleepyFlow).returnValue.getOrThrow(1.minutes)
|
||||||
|
val differenceBetweenStartAndMiddle = Duration.between(start, middle)
|
||||||
|
val differenceBetweenMiddleAndFinish = Duration.between(middle, finish)
|
||||||
|
assertTrue(differenceBetweenStartAndMiddle >= 5.seconds)
|
||||||
|
assertTrue(differenceBetweenStartAndMiddle < 7.seconds)
|
||||||
|
assertTrue(differenceBetweenMiddleAndFinish >= 10.seconds)
|
||||||
|
assertTrue(differenceBetweenMiddleAndFinish < 12.seconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 300_000)
|
||||||
|
fun `flow can sleep and perform other suspending functions`() {
|
||||||
|
// ensures that events received while the flow is sleeping are not processed
|
||||||
|
driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true)) {
|
||||||
|
val alice = startNode(providedName = ALICE_NAME).getOrThrow()
|
||||||
|
val bob = startNode(providedName = BOB_NAME).getOrThrow()
|
||||||
|
val (start, finish) = alice.rpc.startFlow(
|
||||||
|
::SleepAndInteractWithPartyFlow,
|
||||||
|
bob.nodeInfo.singleIdentity()
|
||||||
|
).returnValue.getOrThrow(1.minutes)
|
||||||
|
val difference = Duration.between(start, finish)
|
||||||
|
assertTrue(difference >= 5.seconds)
|
||||||
|
assertTrue(difference < 7.seconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class SleepyFlow : FlowLogic<Pair<Instant, Instant>>() {
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call(): Pair<Instant, Instant> {
|
||||||
|
val start = Instant.now()
|
||||||
|
sleep(5.seconds)
|
||||||
|
return start to Instant.now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
class AnotherSleepyFlow : FlowLogic<Triple<Instant, Instant, Instant>>() {
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call(): Triple<Instant, Instant, Instant> {
|
||||||
|
val start = Instant.now()
|
||||||
|
sleep(5.seconds)
|
||||||
|
val middle = Instant.now()
|
||||||
|
sleep(10.seconds)
|
||||||
|
return Triple(start, middle, Instant.now())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@StartableByRPC
|
||||||
|
@InitiatingFlow
|
||||||
|
class SleepAndInteractWithPartyFlow(private val party: Party) : FlowLogic<Pair<Instant, Instant>>() {
|
||||||
|
|
||||||
|
@Suspendable
|
||||||
|
override fun call(): Pair<Instant, Instant> {
|
||||||
|
subFlow(PingPongFlow(party))
|
||||||
|
val start = Instant.now()
|
||||||
|
sleep(5.seconds)
|
||||||
|
val finish = Instant.now()
|
||||||
|
val session = initiateFlow(party)
|
||||||
|
session.sendAndReceive<String>("hi")
|
||||||
|
session.sendAndReceive<String>("hi")
|
||||||
|
subFlow(PingPongFlow(party))
|
||||||
|
return start to finish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(SleepAndInteractWithPartyFlow::class)
|
||||||
|
class SleepAndInteractWithPartyResponder(val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
session.receive<String>().unwrap { it }
|
||||||
|
session.send("go away")
|
||||||
|
session.receive<String>().unwrap { it }
|
||||||
|
session.send("go away")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatingFlow
|
||||||
|
class PingPongFlow(val party: Party) : FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
val session = initiateFlow(party)
|
||||||
|
session.sendAndReceive<String>("ping pong").unwrap { it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InitiatedBy(PingPongFlow::class)
|
||||||
|
class PingPongResponder(val session: FlowSession) : FlowLogic<Unit>() {
|
||||||
|
@Suspendable
|
||||||
|
override fun call() {
|
||||||
|
session.receive<String>().unwrap { it }
|
||||||
|
session.send("I got you bro")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,14 +21,18 @@ import net.corda.testing.internal.services.InternalMockAttachmentStorage
|
|||||||
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
|
import net.corda.testing.node.internal.FINANCE_CONTRACTS_CORDAPP
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.Assert.assertArrayEquals
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
class AttachmentsClassLoaderTests {
|
class AttachmentsClassLoaderTests {
|
||||||
companion object {
|
companion object {
|
||||||
@ -84,15 +88,30 @@ class AttachmentsClassLoaderTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout=300_000)
|
||||||
|
fun `test contracts have no permissions for protection domain`() {
|
||||||
|
val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
||||||
|
assertNull(System.getSecurityManager())
|
||||||
|
|
||||||
|
createClassloader(isolatedId).use { classLoader ->
|
||||||
|
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classLoader)
|
||||||
|
val protectionDomain = contractClass.protectionDomain ?: fail("Protection Domain missing")
|
||||||
|
val permissions = protectionDomain.permissions ?: fail("Protection domain has no permissions")
|
||||||
|
assertThat(permissions.elements().toList()).isEmpty()
|
||||||
|
assertTrue(permissions.isReadOnly)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Dynamically load AnotherDummyContract from isolated contracts jar using the AttachmentsClassLoader`() {
|
fun `Dynamically load AnotherDummyContract from isolated contracts jar using the AttachmentsClassLoader`() {
|
||||||
val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
val isolatedId = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", "isolated.jar")
|
||||||
|
|
||||||
val classloader = createClassloader(isolatedId)
|
createClassloader(isolatedId).use { classloader ->
|
||||||
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classloader)
|
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, classloader)
|
||||||
val contract = contractClass.getDeclaredConstructor().newInstance() as Contract
|
val contract = contractClass.getDeclaredConstructor().newInstance() as Contract
|
||||||
assertEquals("helloworld", contract.declaredField<Any?>("magicString").value)
|
assertEquals("helloworld", contract.declaredField<Any?>("magicString").value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Test non-overlapping contract jar`() {
|
fun `Test non-overlapping contract jar`() {
|
||||||
@ -100,7 +119,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att2 = importAttachment(ISOLATED_CONTRACTS_JAR_PATH_V4.openStream(), "app", "isolated-4.0.jar")
|
val att2 = importAttachment(ISOLATED_CONTRACTS_JAR_PATH_V4.openStream(), "app", "isolated-4.0.jar")
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +130,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val isolatedSignedId = importAttachment(signedJar.first.toUri().toURL().openStream(), "app", "isolated-signed.jar")
|
val isolatedSignedId = importAttachment(signedJar.first.toUri().toURL().openStream(), "app", "isolated-signed.jar")
|
||||||
|
|
||||||
// does not throw OverlappingAttachments exception
|
// does not throw OverlappingAttachments exception
|
||||||
createClassloader(listOf(isolatedId, isolatedSignedId))
|
createClassloader(listOf(isolatedId, isolatedSignedId)).use {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -120,7 +139,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att2 = importAttachment(FINANCE_CONTRACTS_CORDAPP.jarFile.inputStream(), "app", "finance.jar")
|
val att2 = importAttachment(FINANCE_CONTRACTS_CORDAPP.jarFile.inputStream(), "app", "finance.jar")
|
||||||
|
|
||||||
// does not throw OverlappingAttachments exception
|
// does not throw OverlappingAttachments exception
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -128,23 +147,25 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att1 = importAttachment(fakeAttachment("file1.txt", "some data").inputStream(), "app", "file1.jar")
|
val att1 = importAttachment(fakeAttachment("file1.txt", "some data").inputStream(), "app", "file1.jar")
|
||||||
val att2 = importAttachment(fakeAttachment("file2.txt", "some other data").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment("file2.txt", "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
val cl = createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use { cl ->
|
||||||
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
||||||
assertEquals("some data", txt)
|
assertEquals("some data", txt)
|
||||||
|
|
||||||
val txt1 = IOUtils.toString(cl.getResourceAsStream("file2.txt"), Charsets.UTF_8.name())
|
val txt1 = IOUtils.toString(cl.getResourceAsStream("file2.txt"), Charsets.UTF_8.name())
|
||||||
assertEquals("some other data", txt1)
|
assertEquals("some other data", txt1)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `Test valid overlapping file condition`() {
|
fun `Test valid overlapping file condition`() {
|
||||||
val att1 = importAttachment(fakeAttachment("file1.txt", "same data", "file2.txt", "same other data").inputStream(), "app", "file1.jar")
|
val att1 = importAttachment(fakeAttachment("file1.txt", "same data", "file2.txt", "same other data").inputStream(), "app", "file1.jar")
|
||||||
val att2 = importAttachment(fakeAttachment("file1.txt", "same data", "file3.txt", "same totally different").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment("file1.txt", "same data", "file3.txt", "same totally different").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
val cl = createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use { cl ->
|
||||||
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
||||||
assertEquals("same data", txt)
|
assertEquals("same data", txt)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
fun `No overlapping exception thrown on certain META-INF files`() {
|
fun `No overlapping exception thrown on certain META-INF files`() {
|
||||||
@ -152,7 +173,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att1 = importAttachment(fakeAttachment(path, "some data").inputStream(), "app", "file1.jar")
|
val att1 = importAttachment(fakeAttachment(path, "some data").inputStream(), "app", "file1.jar")
|
||||||
val att2 = importAttachment(fakeAttachment(path, "some other data").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment(path, "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +182,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att1 = importAttachment(fakeAttachment("meta-inf/services/net.corda.core.serialization.SerializationWhitelist", "some data").inputStream(), "app", "file1.jar")
|
val att1 = importAttachment(fakeAttachment("meta-inf/services/net.corda.core.serialization.SerializationWhitelist", "some data").inputStream(), "app", "file1.jar")
|
||||||
val att2 = importAttachment(fakeAttachment("meta-inf/services/net.corda.core.serialization.SerializationWhitelist", "some other data").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment("meta-inf/services/net.corda.core.serialization.SerializationWhitelist", "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -170,7 +191,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att2 = importAttachment(fakeAttachment("meta-inf/services/com.example.something", "some other data").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment("meta-inf/services/com.example.something", "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +201,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att2 = storage.importAttachment(fakeAttachment("file1.txt", "some other data").inputStream(), "app", "file2.jar")
|
val att2 = storage.importAttachment(fakeAttachment("file1.txt", "some other data").inputStream(), "app", "file2.jar")
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +212,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
val att1 = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", ISOLATED_CONTRACTS_JAR_PATH.file)
|
val att1 = importAttachment(ISOLATED_CONTRACTS_JAR_PATH.openStream(), "app", ISOLATED_CONTRACTS_JAR_PATH.file)
|
||||||
val att2 = importAttachment(fakeAttachment("net/corda/finance/contracts/isolated/AnotherDummyContract\$State.class", "some attackdata").inputStream(), "app", "file2.jar")
|
val att2 = importAttachment(fakeAttachment("net/corda/finance/contracts/isolated/AnotherDummyContract\$State.class", "some attackdata").inputStream(), "app", "file2.jar")
|
||||||
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.OverlappingAttachmentsException::class) {
|
||||||
createClassloader(listOf(att1, att2))
|
createClassloader(listOf(att1, att2)).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,10 +241,10 @@ class AttachmentsClassLoaderTests {
|
|||||||
val untrustedClassJar = importAttachment(fakeAttachment("/com/example/something/MaliciousClass.class", "some malicious data").inputStream(), "untrusted", "file2.jar")
|
val untrustedClassJar = importAttachment(fakeAttachment("/com/example/something/MaliciousClass.class", "some malicious data").inputStream(), "untrusted", "file2.jar")
|
||||||
val trustedClassJar = importAttachment(fakeAttachment("/com/example/something/VirtuousClass.class", "some other data").inputStream(), "app", "file3.jar")
|
val trustedClassJar = importAttachment(fakeAttachment("/com/example/something/VirtuousClass.class", "some other data").inputStream(), "app", "file3.jar")
|
||||||
|
|
||||||
createClassloader(listOf(trustedResourceJar, untrustedResourceJar, trustedClassJar))
|
createClassloader(listOf(trustedResourceJar, untrustedResourceJar, trustedClassJar)).use {
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
||||||
createClassloader(listOf(trustedResourceJar, untrustedResourceJar, trustedClassJar, untrustedClassJar))
|
createClassloader(listOf(trustedResourceJar, untrustedResourceJar, trustedClassJar, untrustedClassJar)).use {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +278,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
signers = listOf(keyPairA.public, keyPairB.public)
|
signers = listOf(keyPairA.public, keyPairB.public)
|
||||||
)
|
)
|
||||||
|
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -287,7 +308,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
signers = listOf(keyPairA.public, keyPairB.public)
|
signers = listOf(keyPairA.public, keyPairB.public)
|
||||||
)
|
)
|
||||||
|
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@ -306,7 +327,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +358,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,10 +401,10 @@ class AttachmentsClassLoaderTests {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// pass the inherited trust attachment through the classloader first to ensure it does not affect the next loaded attachment
|
// pass the inherited trust attachment through the classloader first to ensure it does not affect the next loaded attachment
|
||||||
createClassloader(inheritedTrustAttachment)
|
createClassloader(inheritedTrustAttachment).use {
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +442,7 @@ class AttachmentsClassLoaderTests {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
assertFailsWith(TransactionVerificationException.UntrustedAttachmentsException::class) {
|
||||||
createClassloader(untrustedAttachment)
|
createClassloader(untrustedAttachment).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,6 +467,6 @@ class AttachmentsClassLoaderTests {
|
|||||||
signers = listOf(keyPairA.public)
|
signers = listOf(keyPairA.public)
|
||||||
)
|
)
|
||||||
|
|
||||||
createClassloader(trustedAttachment)
|
createClassloader(trustedAttachment).use {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,8 @@ task copyQuasarJar(type: Copy) {
|
|||||||
|
|
||||||
jar {
|
jar {
|
||||||
finalizedBy(copyQuasarJar)
|
finalizedBy(copyQuasarJar)
|
||||||
baseName 'corda-core'
|
archiveBaseName = 'corda-core'
|
||||||
|
archiveClassifier = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
@ -49,7 +49,7 @@ interface Attachment : NamedByHash {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the named file case insensitively and copies it to the output stream.
|
* Finds the named file case insensitively and copies it to the output stream.
|
||||||
* @throws FileNotFoundException if the given path doesn't exist in the attachment.
|
* @throws [FileNotFoundException] if the given path doesn't exist in the attachment.
|
||||||
*/
|
*/
|
||||||
@JvmDefault
|
@JvmDefault
|
||||||
fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) }
|
fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) }
|
||||||
|
@ -108,7 +108,7 @@ object Crypto {
|
|||||||
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256k1),
|
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256k1),
|
||||||
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256k1)),
|
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256k1)),
|
||||||
cordaBouncyCastleProvider.name,
|
cordaBouncyCastleProvider.name,
|
||||||
"ECDSA",
|
"EC",
|
||||||
"SHA256withECDSA",
|
"SHA256withECDSA",
|
||||||
ECNamedCurveTable.getParameterSpec("secp256k1"),
|
ECNamedCurveTable.getParameterSpec("secp256k1"),
|
||||||
256,
|
256,
|
||||||
@ -123,7 +123,7 @@ object Crypto {
|
|||||||
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256r1),
|
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256r1),
|
||||||
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1)),
|
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1)),
|
||||||
cordaBouncyCastleProvider.name,
|
cordaBouncyCastleProvider.name,
|
||||||
"ECDSA",
|
"EC",
|
||||||
"SHA256withECDSA",
|
"SHA256withECDSA",
|
||||||
ECNamedCurveTable.getParameterSpec("secp256r1"),
|
ECNamedCurveTable.getParameterSpec("secp256r1"),
|
||||||
256,
|
256,
|
||||||
|
@ -2,7 +2,6 @@ package net.corda.core.crypto
|
|||||||
|
|
||||||
import net.corda.core.KeepForDJVM
|
import net.corda.core.KeepForDJVM
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
@KeepForDJVM
|
@KeepForDJVM
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
|
import net.corda.core.CordaInternal
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.isFulfilledBy
|
import net.corda.core.crypto.isFulfilledBy
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
@ -45,6 +46,13 @@ class FinalityFlow private constructor(val transaction: SignedTransaction,
|
|||||||
private val sessions: Collection<FlowSession>,
|
private val sessions: Collection<FlowSession>,
|
||||||
private val newApi: Boolean,
|
private val newApi: Boolean,
|
||||||
private val statesToRecord: StatesToRecord = ONLY_RELEVANT) : FlowLogic<SignedTransaction>() {
|
private val statesToRecord: StatesToRecord = ONLY_RELEVANT) : FlowLogic<SignedTransaction>() {
|
||||||
|
|
||||||
|
@CordaInternal
|
||||||
|
data class ExtraConstructorArgs(val oldParticipants: Collection<Party>, val sessions: Collection<FlowSession>, val newApi: Boolean, val statesToRecord: StatesToRecord)
|
||||||
|
|
||||||
|
@CordaInternal
|
||||||
|
fun getExtraConstructorArgs() = ExtraConstructorArgs(oldParticipants, sessions, newApi, statesToRecord)
|
||||||
|
|
||||||
@Deprecated(DEPRECATION_MSG)
|
@Deprecated(DEPRECATION_MSG)
|
||||||
constructor(transaction: SignedTransaction, extraRecipients: Set<Party>, progressTracker: ProgressTracker) : this(
|
constructor(transaction: SignedTransaction, extraRecipients: Set<Party>, progressTracker: ProgressTracker) : this(
|
||||||
transaction, extraRecipients, progressTracker, emptyList(), false
|
transaction, extraRecipients, progressTracker, emptyList(), false
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package net.corda.core.flows
|
package net.corda.core.flows
|
||||||
|
|
||||||
import net.corda.core.internal.ServiceHubCoreInternal
|
|
||||||
import net.corda.core.node.ServiceHub
|
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,9 +24,6 @@ import net.corda.core.messaging.DataFeed
|
|||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.SerializationDefaults
|
|
||||||
import net.corda.core.serialization.SerializedBytes
|
|
||||||
import net.corda.core.serialization.serialize
|
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.ProgressTracker
|
import net.corda.core.utilities.ProgressTracker
|
||||||
import net.corda.core.utilities.UntrustworthyData
|
import net.corda.core.utilities.UntrustworthyData
|
||||||
@ -130,6 +127,32 @@ abstract class FlowLogic<out T> {
|
|||||||
*/
|
*/
|
||||||
val serviceHub: ServiceHub get() = stateMachine.serviceHub
|
val serviceHub: ServiceHub get() = stateMachine.serviceHub
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` when the current [FlowLogic] has been killed (has received a command to halt its progress and terminate).
|
||||||
|
*
|
||||||
|
* Check this property in long-running computation loops to exit a flow that has been killed:
|
||||||
|
* ```
|
||||||
|
* while (!isKilled) {
|
||||||
|
* // do some computation
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Ideal usage would include throwing a [KilledFlowException] which will lead to the termination of the flow:
|
||||||
|
* ```
|
||||||
|
* for (item in list) {
|
||||||
|
* if (isKilled) {
|
||||||
|
* throw KilledFlowException(runId)
|
||||||
|
* }
|
||||||
|
* // do some computation
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Note, once the [isKilled] flag is set to `true` the flow may terminate once it reaches the next API function marked with the
|
||||||
|
* @[Suspendable] annotation. Therefore, it is possible to write a flow that does not interact with the [isKilled] flag while still
|
||||||
|
* terminating correctly.
|
||||||
|
*/
|
||||||
|
val isKilled: Boolean get() = stateMachine.isKilled
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a communication session with [destination]. Subsequently you may send/receive using this session object. How the messaging
|
* Creates a communication session with [destination]. Subsequently you may send/receive using this session object. How the messaging
|
||||||
* is routed depends on the [Destination] type, including whether this call does any initial communication.
|
* is routed depends on the [Destination] type, including whether this call does any initial communication.
|
||||||
@ -267,7 +290,7 @@ abstract class FlowLogic<out T> {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
internal fun <R : Any> FlowSession.sendAndReceiveWithRetry(receiveType: Class<R>, payload: Any): UntrustworthyData<R> {
|
internal fun <R : Any> FlowSession.sendAndReceiveWithRetry(receiveType: Class<R>, payload: Any): UntrustworthyData<R> {
|
||||||
val request = FlowIORequest.SendAndReceive(
|
val request = FlowIORequest.SendAndReceive(
|
||||||
sessionToMessage = mapOf(this to payload.serialize(context = SerializationDefaults.P2P_CONTEXT)),
|
sessionToMessage = stateMachine.serialize(mapOf(this to payload)),
|
||||||
shouldRetrySend = true
|
shouldRetrySend = true
|
||||||
)
|
)
|
||||||
return stateMachine.suspend(request, maySkipCheckpoint = false)[this]!!.checkPayloadIs(receiveType)
|
return stateMachine.suspend(request, maySkipCheckpoint = false)[this]!!.checkPayloadIs(receiveType)
|
||||||
@ -333,7 +356,7 @@ abstract class FlowLogic<out T> {
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun sendAll(payload: Any, sessions: Set<FlowSession>, maySkipCheckpoint: Boolean = false) {
|
fun sendAll(payload: Any, sessions: Set<FlowSession>, maySkipCheckpoint: Boolean = false) {
|
||||||
val sessionToPayload = sessions.map { it to payload }.toMap()
|
val sessionToPayload = sessions.map { it to payload }.toMap()
|
||||||
return sendAll(sessionToPayload, maySkipCheckpoint)
|
return sendAllMap(sessionToPayload, maySkipCheckpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -348,23 +371,13 @@ abstract class FlowLogic<out T> {
|
|||||||
*/
|
*/
|
||||||
@Suspendable
|
@Suspendable
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun sendAll(payloadsPerSession: Map<FlowSession, Any>, maySkipCheckpoint: Boolean = false) {
|
fun sendAllMap(payloadsPerSession: Map<FlowSession, Any>, maySkipCheckpoint: Boolean = false) {
|
||||||
val request = FlowIORequest.Send(
|
val request = FlowIORequest.Send(
|
||||||
sessionToMessage = serializePayloads(payloadsPerSession)
|
sessionToMessage = stateMachine.serialize(payloadsPerSession)
|
||||||
)
|
)
|
||||||
stateMachine.suspend(request, maySkipCheckpoint)
|
stateMachine.suspend(request, maySkipCheckpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suspendable
|
|
||||||
private fun serializePayloads(payloadsPerSession: Map<FlowSession, Any>): Map<FlowSession, SerializedBytes<Any>> {
|
|
||||||
val cachedSerializedPayloads = mutableMapOf<Any, SerializedBytes<Any>>()
|
|
||||||
|
|
||||||
return payloadsPerSession.mapValues { (_, payload) ->
|
|
||||||
cachedSerializedPayloads[payload] ?: payload.serialize(context = SerializationDefaults.P2P_CONTEXT).also { cachedSerializedPayloads[payload] = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes the given subflow. This function returns once the subflow completes successfully with the result
|
* Invokes the given subflow. This function returns once the subflow completes successfully with the result
|
||||||
* returned by that subflow's [call] method. If the subflow has a progress tracker, it is attached to the
|
* returned by that subflow's [call] method. If the subflow has a progress tracker, it is attached to the
|
||||||
@ -380,10 +393,8 @@ abstract class FlowLogic<out T> {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
@Throws(FlowException::class)
|
@Throws(FlowException::class)
|
||||||
open fun <R> subFlow(subLogic: FlowLogic<R>): R {
|
open fun <R> subFlow(subLogic: FlowLogic<R>): R {
|
||||||
subLogic.stateMachine = stateMachine
|
|
||||||
maybeWireUpProgressTracking(subLogic)
|
|
||||||
logger.debug { "Calling subflow: $subLogic" }
|
logger.debug { "Calling subflow: $subLogic" }
|
||||||
val result = stateMachine.subFlow(subLogic)
|
val result = stateMachine.subFlow(this, subLogic)
|
||||||
logger.debug { "Subflow finished with result ${result.toString().abbreviate(300)}" }
|
logger.debug { "Subflow finished with result ${result.toString().abbreviate(300)}" }
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -540,18 +551,6 @@ abstract class FlowLogic<out T> {
|
|||||||
_stateMachine = value
|
_stateMachine = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeWireUpProgressTracking(subLogic: FlowLogic<*>) {
|
|
||||||
val ours = progressTracker
|
|
||||||
val theirs = subLogic.progressTracker
|
|
||||||
if (ours != null && theirs != null && ours != theirs) {
|
|
||||||
if (ours.currentStep == ProgressTracker.UNSTARTED) {
|
|
||||||
logger.debug { "Initializing the progress tracker for flow: ${this::class.java.name}." }
|
|
||||||
ours.nextStep()
|
|
||||||
}
|
|
||||||
ours.setChildProgressTracker(ours.currentStep, theirs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun enforceNoDuplicates(sessions: List<FlowSession>) {
|
private fun enforceNoDuplicates(sessions: List<FlowSession>) {
|
||||||
require(sessions.size == sessions.toSet().size) { "A flow session can only appear once as argument." }
|
require(sessions.size == sessions.toSet().size) { "A flow session can only appear once as argument." }
|
||||||
}
|
}
|
||||||
@ -579,12 +578,7 @@ abstract class FlowLogic<out T> {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
fun <R : Any> await(operation: FlowExternalAsyncOperation<R>): R {
|
fun <R : Any> await(operation: FlowExternalAsyncOperation<R>): R {
|
||||||
// Wraps the passed in [FlowExternalAsyncOperation] so its [CompletableFuture] can be converted into a [CordaFuture]
|
// Wraps the passed in [FlowExternalAsyncOperation] so its [CompletableFuture] can be converted into a [CordaFuture]
|
||||||
val flowAsyncOperation = object : FlowAsyncOperation<R>, WrappedFlowExternalAsyncOperation<R> {
|
val flowAsyncOperation = WrappedFlowExternalAsyncOperation(operation)
|
||||||
override val operation = operation
|
|
||||||
override fun execute(deduplicationId: String): CordaFuture<R> {
|
|
||||||
return this.operation.execute(deduplicationId).asCordaFuture()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation)
|
val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation)
|
||||||
return stateMachine.suspend(request, false)
|
return stateMachine.suspend(request, false)
|
||||||
}
|
}
|
||||||
@ -598,9 +592,74 @@ abstract class FlowLogic<out T> {
|
|||||||
*/
|
*/
|
||||||
@Suspendable
|
@Suspendable
|
||||||
fun <R : Any> await(operation: FlowExternalOperation<R>): R {
|
fun <R : Any> await(operation: FlowExternalOperation<R>): R {
|
||||||
val flowAsyncOperation = object : FlowAsyncOperation<R>, WrappedFlowExternalOperation<R> {
|
val flowAsyncOperation = WrappedFlowExternalOperation(serviceHub as ServiceHubCoreInternal, operation)
|
||||||
override val serviceHub = this@FlowLogic.serviceHub as ServiceHubCoreInternal
|
val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation)
|
||||||
override val operation = operation
|
return stateMachine.suspend(request, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that throws a [KilledFlowException] if the current [FlowLogic] has been killed.
|
||||||
|
*
|
||||||
|
* Call this function in long-running computation loops to exit a flow that has been killed:
|
||||||
|
* ```
|
||||||
|
* for (item in list) {
|
||||||
|
* checkFlowIsNotKilled()
|
||||||
|
* // do some computation
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* See the [isKilled] property for more information.
|
||||||
|
*/
|
||||||
|
fun checkFlowIsNotKilled() {
|
||||||
|
if (isKilled) {
|
||||||
|
throw KilledFlowException(runId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function that throws a [KilledFlowException] if the current [FlowLogic] has been killed. The provided message is added to the
|
||||||
|
* thrown [KilledFlowException].
|
||||||
|
*
|
||||||
|
* Call this function in long-running computation loops to exit a flow that has been killed:
|
||||||
|
* ```
|
||||||
|
* for (item in list) {
|
||||||
|
* checkFlowIsNotKilled { "The flow $runId was killed while iterating through the list of items" }
|
||||||
|
* // do some computation
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* See the [isKilled] property for more information.
|
||||||
|
*/
|
||||||
|
fun checkFlowIsNotKilled(lazyMessage: () -> Any) {
|
||||||
|
if (isKilled) {
|
||||||
|
val message = lazyMessage()
|
||||||
|
throw KilledFlowException(runId, message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WrappedFlowExternalAsyncOperation] is added to allow jackson to properly reference the data stored within the wrapped
|
||||||
|
* [FlowExternalAsyncOperation].
|
||||||
|
*/
|
||||||
|
private class WrappedFlowExternalAsyncOperation<R : Any>(val operation: FlowExternalAsyncOperation<R>) : FlowAsyncOperation<R> {
|
||||||
|
override fun execute(deduplicationId: String): CordaFuture<R> {
|
||||||
|
return operation.execute(deduplicationId).asCordaFuture()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WrappedFlowExternalOperation] is added to allow jackson to properly reference the data stored within the wrapped
|
||||||
|
* [FlowExternalOperation].
|
||||||
|
*
|
||||||
|
* The reference to [ServiceHub] is also needed by Kryo to properly keep a reference to [ServiceHub] so that
|
||||||
|
* [FlowExternalOperation] can be run from the [ServiceHubCoreInternal.externalOperationExecutor] without causing errors when retrying a
|
||||||
|
* flow. A [NullPointerException] is thrown if [FlowLogic.serviceHub] is accessed from [FlowLogic.await] when retrying a flow.
|
||||||
|
*/
|
||||||
|
private class WrappedFlowExternalOperation<R : Any>(
|
||||||
|
val serviceHub: ServiceHubCoreInternal,
|
||||||
|
val operation: FlowExternalOperation<R>
|
||||||
|
) : FlowAsyncOperation<R> {
|
||||||
override fun execute(deduplicationId: String): CordaFuture<R> {
|
override fun execute(deduplicationId: String): CordaFuture<R> {
|
||||||
// Using a [CompletableFuture] allows unhandled exceptions to be thrown inside the background operation
|
// Using a [CompletableFuture] allows unhandled exceptions to be thrown inside the background operation
|
||||||
// the exceptions will be set on the future by [CompletableFuture.AsyncSupply.run]
|
// the exceptions will be set on the future by [CompletableFuture.AsyncSupply.run]
|
||||||
@ -609,31 +668,6 @@ abstract class FlowLogic<out T> {
|
|||||||
serviceHub.externalOperationExecutor
|
serviceHub.externalOperationExecutor
|
||||||
).asCordaFuture()
|
).asCordaFuture()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation)
|
|
||||||
return stateMachine.suspend(request, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [WrappedFlowExternalAsyncOperation] is added to allow jackson to properly reference the data stored within the wrapped
|
|
||||||
* [FlowExternalAsyncOperation].
|
|
||||||
*/
|
|
||||||
private interface WrappedFlowExternalAsyncOperation<R : Any> {
|
|
||||||
val operation: FlowExternalAsyncOperation<R>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [WrappedFlowExternalOperation] is added to allow jackson to properly reference the data stored within the wrapped
|
|
||||||
* [FlowExternalOperation].
|
|
||||||
*
|
|
||||||
* The reference to [ServiceHub] is is also needed by Kryo to properly keep a reference to [ServiceHub] so that
|
|
||||||
* [FlowExternalOperation] can be run from the [ServiceHubCoreInternal.externalOperationExecutor] without causing errors when retrying a
|
|
||||||
* flow. A [NullPointerException] is thrown if [FlowLogic.serviceHub] is accessed from [FlowLogic.await] when retrying a flow.
|
|
||||||
*/
|
|
||||||
private interface WrappedFlowExternalOperation<R : Any> {
|
|
||||||
val serviceHub: ServiceHub
|
|
||||||
val operation: FlowExternalOperation<R>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package net.corda.core.flows
|
||||||
|
|
||||||
|
import net.corda.core.CordaRuntimeException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception that is thrown when a flow has been killed.
|
||||||
|
*
|
||||||
|
* This exception can be returned and thrown to RPC clients waiting for the result of a flow's future.
|
||||||
|
*
|
||||||
|
* It can also be used in conjunction with [FlowLogic.isKilled] to escape long-running computation loops when a flow has been killed.
|
||||||
|
*/
|
||||||
|
class KilledFlowException(val id: StateMachineRunId, message: String) : CordaRuntimeException(message) {
|
||||||
|
constructor(id: StateMachineRunId) : this(id, "The flow $id was killed")
|
||||||
|
}
|
@ -28,7 +28,7 @@ import java.util.jar.JarInputStream
|
|||||||
|
|
||||||
// *Internal* Corda-specific utilities.
|
// *Internal* Corda-specific utilities.
|
||||||
|
|
||||||
const val PLATFORM_VERSION = 6
|
const val PLATFORM_VERSION = 7
|
||||||
|
|
||||||
fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) {
|
fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) {
|
||||||
checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature)
|
checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature)
|
||||||
@ -48,6 +48,20 @@ fun checkMinimumPlatformVersion(minimumPlatformVersion: Int, requiredMinPlatform
|
|||||||
@Throws(NumberFormatException::class)
|
@Throws(NumberFormatException::class)
|
||||||
fun getJavaUpdateVersion(javaVersion: String): Long = javaVersion.substringAfter("_").substringBefore("-").toLong()
|
fun getJavaUpdateVersion(javaVersion: String): Long = javaVersion.substringAfter("_").substringBefore("-").toLong()
|
||||||
|
|
||||||
|
enum class JavaVersion(val versionString: String) {
|
||||||
|
Java_1_8("1.8"),
|
||||||
|
Java_11("11");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isVersionAtLeast(version: JavaVersion): Boolean {
|
||||||
|
return currentVersion.toFloat() >= version.versionString.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val currentVersion: String = System.getProperty("java.specification.version") ?:
|
||||||
|
throw IllegalStateException("Unable to retrieve system property java.specification.version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Provide access to internal method for AttachmentClassLoaderTests. */
|
/** Provide access to internal method for AttachmentClassLoaderTests. */
|
||||||
@DeleteForDJVM
|
@DeleteForDJVM
|
||||||
fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serializationContext: SerializationContext): WireTransaction {
|
fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serializationContext: SerializationContext): WireTransaction {
|
||||||
|
@ -8,6 +8,7 @@ import net.corda.core.context.InvocationContext
|
|||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
|
||||||
/** This is an internal interface that is implemented by code in the node module. You should look at [FlowLogic]. */
|
/** This is an internal interface that is implemented by code in the node module. You should look at [FlowLogic]. */
|
||||||
@ -17,6 +18,8 @@ interface FlowStateMachine<FLOWRETURN> {
|
|||||||
@Suspendable
|
@Suspendable
|
||||||
fun <SUSPENDRETURN : Any> suspend(ioRequest: FlowIORequest<SUSPENDRETURN>, maySkipCheckpoint: Boolean): SUSPENDRETURN
|
fun <SUSPENDRETURN : Any> suspend(ioRequest: FlowIORequest<SUSPENDRETURN>, maySkipCheckpoint: Boolean): SUSPENDRETURN
|
||||||
|
|
||||||
|
fun serialize(payloads: Map<FlowSession, Any>): Map<FlowSession, SerializedBytes<Any>>
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
fun initiateFlow(destination: Destination, wellKnownParty: Party): FlowSession
|
fun initiateFlow(destination: Destination, wellKnownParty: Party): FlowSession
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ interface FlowStateMachine<FLOWRETURN> {
|
|||||||
fun recordAuditEvent(eventType: String, comment: String, extraAuditData: Map<String, String>)
|
fun recordAuditEvent(eventType: String, comment: String, extraAuditData: Map<String, String>)
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
fun <SUBFLOWRETURN> subFlow(subFlow: FlowLogic<SUBFLOWRETURN>): SUBFLOWRETURN
|
fun <SUBFLOWRETURN> subFlow(currentFlow: FlowLogic<*>, subFlow: FlowLogic<SUBFLOWRETURN>): SUBFLOWRETURN
|
||||||
|
|
||||||
@Suspendable
|
@Suspendable
|
||||||
fun flowStackSnapshot(flowClass: Class<out FlowLogic<*>>): FlowStackSnapshot?
|
fun flowStackSnapshot(flowClass: Class<out FlowLogic<*>>): FlowStackSnapshot?
|
||||||
@ -44,4 +47,5 @@ interface FlowStateMachine<FLOWRETURN> {
|
|||||||
val ourIdentity: Party
|
val ourIdentity: Party
|
||||||
val ourSenderUUID: String?
|
val ourSenderUUID: String?
|
||||||
val creationTime: Long
|
val creationTime: Long
|
||||||
|
val isKilled: Boolean
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ package net.corda.core.internal
|
|||||||
|
|
||||||
import net.corda.core.DeleteForDJVM
|
import net.corda.core.DeleteForDJVM
|
||||||
import net.corda.core.KeepForDJVM
|
import net.corda.core.KeepForDJVM
|
||||||
|
import net.corda.core.StubOutForDJVM
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.DigitalSignature
|
import net.corda.core.crypto.DigitalSignature
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
@ -417,6 +418,7 @@ fun <T, U : T> uncheckedCast(obj: T) = obj as U
|
|||||||
fun <K, V> Iterable<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = this.groupBy({ it.first }) { it.second }
|
fun <K, V> Iterable<Pair<K, V>>.toMultiMap(): Map<K, List<V>> = this.groupBy({ it.first }) { it.second }
|
||||||
|
|
||||||
/** Returns the location of this class. */
|
/** Returns the location of this class. */
|
||||||
|
@get:StubOutForDJVM
|
||||||
val Class<*>.location: URL get() = protectionDomain.codeSource.location
|
val Class<*>.location: URL get() = protectionDomain.codeSource.location
|
||||||
|
|
||||||
/** Convenience method to get the package name of a class literal. */
|
/** Convenience method to get the package name of a class literal. */
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package net.corda.core.internal
|
||||||
|
|
||||||
|
/*
|
||||||
|
Constants for new features that can only be switched on at specific platform versions can be specified in this file.
|
||||||
|
The text constant describes the feature and the numeric specifies the platform version the feature is enabled at.
|
||||||
|
*/
|
||||||
|
object PlatformVersionSwitches {
|
||||||
|
const val REMOVE_NO_OVERLAP_RULE_FOR_REFERENCE_DATA_ATTACHMENTS = 7
|
||||||
|
const val ENABLE_P2P_COMPRESSION = 7
|
||||||
|
}
|
@ -2,6 +2,7 @@ package net.corda.core.internal
|
|||||||
|
|
||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.DeleteForDJVM
|
import net.corda.core.DeleteForDJVM
|
||||||
|
import net.corda.core.internal.notary.NotaryService
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.StatesToRecord
|
import net.corda.core.node.StatesToRecord
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
@ -14,6 +15,11 @@ interface ServiceHubCoreInternal : ServiceHub {
|
|||||||
|
|
||||||
val attachmentTrustCalculator: AttachmentTrustCalculator
|
val attachmentTrustCalculator: AttachmentTrustCalculator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional `NotaryService` which will be `null` for all non-Notary nodes.
|
||||||
|
*/
|
||||||
|
val notaryService: NotaryService?
|
||||||
|
|
||||||
fun createTransactionsResolver(flow: ResolveTransactionsFlow): TransactionsResolver
|
fun createTransactionsResolver(flow: ResolveTransactionsFlow): TransactionsResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,12 @@ fun <T : Any> deserialiseComponentGroup(componentGroups: List<ComponentGroup>,
|
|||||||
try {
|
try {
|
||||||
factory.deserialize(component, clazz.java, context)
|
factory.deserialize(component, clazz.java, context)
|
||||||
} catch (e: MissingAttachmentsException) {
|
} catch (e: MissingAttachmentsException) {
|
||||||
throw e
|
/**
|
||||||
|
* [ServiceHub.signInitialTransaction] forgets to declare that
|
||||||
|
* it may throw any checked exceptions. Wrap this one inside
|
||||||
|
* an unchecked version to avoid breaking Java CorDapps.
|
||||||
|
*/
|
||||||
|
throw MissingAttachmentsRuntimeException(e.ids, e.message, e)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw TransactionDeserialisationException(groupEnum, internalIndex, e)
|
throw TransactionDeserialisationException(groupEnum, internalIndex, e)
|
||||||
}
|
}
|
||||||
@ -88,7 +93,7 @@ fun <T : Any> deserialiseComponentGroup(componentGroups: List<ComponentGroup>,
|
|||||||
* Exception raised if an error was encountered while attempting to deserialise a component group in a transaction.
|
* Exception raised if an error was encountered while attempting to deserialise a component group in a transaction.
|
||||||
*/
|
*/
|
||||||
class TransactionDeserialisationException(groupEnum: ComponentGroupEnum, index: Int, cause: Exception):
|
class TransactionDeserialisationException(groupEnum: ComponentGroupEnum, index: Int, cause: Exception):
|
||||||
Exception("Failed to deserialise group $groupEnum at index $index in transaction: ${cause.message}", cause)
|
RuntimeException("Failed to deserialise group $groupEnum at index $index in transaction: ${cause.message}", cause)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to deserialise Commands from its two groups:
|
* Method to deserialise Commands from its two groups:
|
||||||
|
@ -4,7 +4,6 @@ package net.corda.core.internal
|
|||||||
|
|
||||||
import net.corda.core.KeepForDJVM
|
import net.corda.core.KeepForDJVM
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import org.bouncycastle.asn1.ASN1Encodable
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||||
import org.bouncycastle.asn1.x500.AttributeTypeAndValue
|
import org.bouncycastle.asn1.x500.AttributeTypeAndValue
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
|
@ -14,6 +14,19 @@ abstract class NotaryService : SingletonSerializeAsToken() {
|
|||||||
abstract val services: ServiceHub
|
abstract val services: ServiceHub
|
||||||
abstract val notaryIdentityKey: PublicKey
|
abstract val notaryIdentityKey: PublicKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interfaces for the request and result formats of queries supported by notary services. To
|
||||||
|
* implement a new query, you must:
|
||||||
|
*
|
||||||
|
* - Define data classes which implement the [Query.Request] and [Query.Result] interfaces
|
||||||
|
* - Add corresponding handling for the new classes within the notary service implementations
|
||||||
|
* that you want to support the query.
|
||||||
|
*/
|
||||||
|
interface Query {
|
||||||
|
interface Request
|
||||||
|
interface Result
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun start()
|
abstract fun start()
|
||||||
abstract fun stop()
|
abstract fun stop()
|
||||||
|
|
||||||
@ -22,4 +35,18 @@ abstract class NotaryService : SingletonSerializeAsToken() {
|
|||||||
* @param otherPartySession client [Party] making the request
|
* @param otherPartySession client [Party] making the request
|
||||||
*/
|
*/
|
||||||
abstract fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?>
|
abstract fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a [Query.Request] and returns a [Query.Result].
|
||||||
|
*
|
||||||
|
* Note that this always throws an [UnsupportedOperationException] to handle notary
|
||||||
|
* implementations that do not support this functionality. This must be overridden by
|
||||||
|
* notary implementations wishing to support query functionality.
|
||||||
|
*
|
||||||
|
* Overrides of this function may themselves still throw an [UnsupportedOperationException],
|
||||||
|
* if they do not support specific query implementations
|
||||||
|
*/
|
||||||
|
open fun processQuery(query: Query.Request): Query.Result {
|
||||||
|
throw UnsupportedOperationException("Notary has not implemented query support")
|
||||||
|
}
|
||||||
}
|
}
|
@ -252,7 +252,7 @@ interface CordaRPCOps : RPCOps {
|
|||||||
* Note: This operation may be restricted only to node administrators.
|
* Note: This operation may be restricted only to node administrators.
|
||||||
* @param parametersHash hash of network parameters to accept
|
* @param parametersHash hash of network parameters to accept
|
||||||
* @throws IllegalArgumentException if network map advertises update with different parameters hash then the one accepted by node's operator.
|
* @throws IllegalArgumentException if network map advertises update with different parameters hash then the one accepted by node's operator.
|
||||||
* @throws IOException if failed to send the approval to network map
|
* @throws [IOException] if failed to send the approval to network map
|
||||||
*/
|
*/
|
||||||
// TODO This operation should be restricted to just node admins.
|
// TODO This operation should be restricted to just node admins.
|
||||||
fun acceptNewNetworkParameters(parametersHash: SecureHash)
|
fun acceptNewNetworkParameters(parametersHash: SecureHash)
|
||||||
|
@ -380,6 +380,26 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* When used within a flow, this session automatically forms part of the enclosing flow transaction boundary,
|
* When used within a flow, this session automatically forms part of the enclosing flow transaction boundary,
|
||||||
* and thus queryable data will include everything committed as of the last checkpoint.
|
* and thus queryable data will include everything committed as of the last checkpoint.
|
||||||
*
|
*
|
||||||
|
* We want to make sure users have a restricted access to administrative functions, this function will return a [RestrictedConnection] instance.
|
||||||
|
* The following methods are blocked:
|
||||||
|
* - abort(executor: Executor?)
|
||||||
|
* - clearWarnings()
|
||||||
|
* - close()
|
||||||
|
* - commit()
|
||||||
|
* - setSavepoint()
|
||||||
|
* - setSavepoint(name : String?)
|
||||||
|
* - releaseSavepoint(savepoint: Savepoint?)
|
||||||
|
* - rollback()
|
||||||
|
* - rollback(savepoint: Savepoint?)
|
||||||
|
* - setCatalog(catalog : String?)
|
||||||
|
* - setTransactionIsolation(level: Int)
|
||||||
|
* - setTypeMap(map: MutableMap<String, Class<*>>?)
|
||||||
|
* - setHoldability(holdability: Int)
|
||||||
|
* - setSchema(schema: String?)
|
||||||
|
* - setNetworkTimeout(executor: Executor?, milliseconds: Int)
|
||||||
|
* - setAutoCommit(autoCommit: Boolean)
|
||||||
|
* - setReadOnly(readOnly: Boolean)
|
||||||
|
*
|
||||||
* @throws IllegalStateException if called outside of a transaction.
|
* @throws IllegalStateException if called outside of a transaction.
|
||||||
* @return A [Connection]
|
* @return A [Connection]
|
||||||
*/
|
*/
|
||||||
@ -393,6 +413,24 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* NOTE: Suspendable flow operations such as send, receive, subFlow and sleep, cannot be called within the lambda.
|
* NOTE: Suspendable flow operations such as send, receive, subFlow and sleep, cannot be called within the lambda.
|
||||||
*
|
*
|
||||||
* @param block a lambda function with access to an [EntityManager].
|
* @param block a lambda function with access to an [EntityManager].
|
||||||
|
*
|
||||||
|
* We want to make sure users have a restricted access to administrative functions.
|
||||||
|
* The following methods are blocked:
|
||||||
|
* - close()
|
||||||
|
* - unwrap(cls: Class<T>?)
|
||||||
|
* - getDelegate(): Any
|
||||||
|
* - getMetamodel()
|
||||||
|
* - joinTransaction()
|
||||||
|
* - lock(entity: Any?, lockMode: LockModeType?)
|
||||||
|
* - lock(entity: Any?, lockMode: LockModeType?, properties: MutableMap<String, Any>?)
|
||||||
|
* - setProperty(propertyName: String?, value: Any?)
|
||||||
|
*
|
||||||
|
* getTransaction returns a [RestrictedEntityTransaction] to prevent unsafe manipulation of a flow's underlying
|
||||||
|
* database transaction.
|
||||||
|
* The following methods are blocked:
|
||||||
|
* - begin()
|
||||||
|
* - commit()
|
||||||
|
* - rollback()
|
||||||
*/
|
*/
|
||||||
fun <T : Any?> withEntityManager(block: EntityManager.() -> T): T
|
fun <T : Any?> withEntityManager(block: EntityManager.() -> T): T
|
||||||
|
|
||||||
@ -404,6 +442,24 @@ interface ServiceHub : ServicesForResolution {
|
|||||||
* NOTE: Suspendable flow operations such as send, receive, subFlow and sleep, cannot be called within the lambda.
|
* NOTE: Suspendable flow operations such as send, receive, subFlow and sleep, cannot be called within the lambda.
|
||||||
*
|
*
|
||||||
* @param block a lambda function with access to an [EntityManager].
|
* @param block a lambda function with access to an [EntityManager].
|
||||||
|
*
|
||||||
|
* We want to make sure users have a restricted access to administrative functions.
|
||||||
|
* The following methods are blocked:
|
||||||
|
* - close()
|
||||||
|
* - unwrap(cls: Class<T>?)
|
||||||
|
* - getDelegate(): Any
|
||||||
|
* - getMetamodel()
|
||||||
|
* - joinTransaction()
|
||||||
|
* - lock(entity: Any?, lockMode: LockModeType?)
|
||||||
|
* - lock(entity: Any?, lockMode: LockModeType?, properties: MutableMap<String, Any>?)
|
||||||
|
* - setProperty(propertyName: String?, value: Any?)
|
||||||
|
*
|
||||||
|
* getTransaction returns a [RestrictedEntityTransaction] to prevent unsafe manipulation of a flow's underlying
|
||||||
|
* database transaction.
|
||||||
|
* The following methods are blocked:
|
||||||
|
* - begin()
|
||||||
|
* - commit()
|
||||||
|
* - rollback()
|
||||||
*/
|
*/
|
||||||
fun withEntityManager(block: Consumer<EntityManager>)
|
fun withEntityManager(block: Consumer<EntityManager>)
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import net.corda.core.contracts.ContractState
|
|||||||
import net.corda.core.contracts.StateRef
|
import net.corda.core.contracts.StateRef
|
||||||
import net.corda.core.contracts.UniqueIdentifier
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.Party
|
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.schemas.StatePersistable
|
import net.corda.core.schemas.StatePersistable
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
@ -302,7 +302,7 @@ object Builder {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun <R> FieldInfo.notEqual(value: R, exactMatch: Boolean = true) = predicate(Builder.equal(value, exactMatch))
|
fun <R> FieldInfo.notEqual(value: R, exactMatch: Boolean = true) = predicate(Builder.notEqual(value, exactMatch))
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
@Deprecated("Does not support fields from a MappedSuperclass. Use equivalent on a FieldInfo.")
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package net.corda.core.serialization
|
||||||
|
|
||||||
|
import net.corda.core.CordaRuntimeException
|
||||||
|
import net.corda.core.KeepForDJVM
|
||||||
|
import net.corda.core.node.services.AttachmentId
|
||||||
|
|
||||||
|
@KeepForDJVM
|
||||||
|
@CordaSerializable
|
||||||
|
class MissingAttachmentsRuntimeException(val ids: List<AttachmentId>, message: String?, cause: Throwable?)
|
||||||
|
: CordaRuntimeException(message, cause) {
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
constructor(ids: List<AttachmentId>, message: String?) : this(ids, message, null)
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
constructor(ids: List<AttachmentId>) : this(ids, null, null)
|
||||||
|
}
|
@ -18,6 +18,7 @@ import java.io.ByteArrayOutputStream
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.*
|
import java.net.*
|
||||||
|
import java.security.Permission
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -378,6 +379,15 @@ object AttachmentURLStreamHandlerFactory : URLStreamHandlerFactory {
|
|||||||
private class AttachmentURLConnection(url: URL, private val attachment: Attachment) : URLConnection(url) {
|
private class AttachmentURLConnection(url: URL, private val attachment: Attachment) : URLConnection(url) {
|
||||||
override fun getContentLengthLong(): Long = attachment.size.toLong()
|
override fun getContentLengthLong(): Long = attachment.size.toLong()
|
||||||
override fun getInputStream(): InputStream = attachment.open()
|
override fun getInputStream(): InputStream = attachment.open()
|
||||||
|
/**
|
||||||
|
* Define the permissions that [AttachmentsClassLoader] will need to
|
||||||
|
* use this [URL]. The attachment is stored in memory, and so we
|
||||||
|
* don't need any extra permissions here. But if we don't override
|
||||||
|
* [getPermission] then [AttachmentsClassLoader] will assign the
|
||||||
|
* default permission of ALL_PERMISSION to these classes'
|
||||||
|
* [java.security.ProtectionDomain]. This would be a security hole!
|
||||||
|
*/
|
||||||
|
override fun getPermission(): Permission? = null
|
||||||
override fun connect() {
|
override fun connect() {
|
||||||
connected = true
|
connected = true
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package net.corda.core.serialization.internal
|
|||||||
import net.corda.core.DeleteForDJVM
|
import net.corda.core.DeleteForDJVM
|
||||||
import net.corda.core.DoNotImplement
|
import net.corda.core.DoNotImplement
|
||||||
import net.corda.core.KeepForDJVM
|
import net.corda.core.KeepForDJVM
|
||||||
import net.corda.core.crypto.SecureHash
|
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.utilities.ByteSequence
|
import net.corda.core.utilities.ByteSequence
|
||||||
import net.corda.core.utilities.sequence
|
import net.corda.core.utilities.sequence
|
||||||
|
@ -134,7 +134,7 @@ open class TransactionBuilder(
|
|||||||
*
|
*
|
||||||
* @returns A new [WireTransaction] that will be unaffected by further changes to this [TransactionBuilder].
|
* @returns A new [WireTransaction] that will be unaffected by further changes to this [TransactionBuilder].
|
||||||
*
|
*
|
||||||
* @throws ZoneVersionTooLowException if there are reference states and the zone minimum platform version is less than 4.
|
* @throws [ZoneVersionTooLowException] if there are reference states and the zone minimum platform version is less than 4.
|
||||||
*/
|
*/
|
||||||
@Throws(MissingContractAttachments::class)
|
@Throws(MissingContractAttachments::class)
|
||||||
fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services, null)
|
fun toWireTransaction(services: ServicesForResolution): WireTransaction = toWireTransactionWithContext(services, null)
|
||||||
|
@ -317,7 +317,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
|
|||||||
/**
|
/**
|
||||||
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
|
* Checks that the given signature matches one of the commands and that it is a correct signature over the tx.
|
||||||
*
|
*
|
||||||
* @throws SignatureException if the signature didn't match the transaction contents.
|
* @throws [SignatureException] if the signature didn't match the transaction contents.
|
||||||
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
* @throws IllegalArgumentException if the signature key doesn't appear in any command.
|
||||||
*/
|
*/
|
||||||
fun checkSignature(sig: TransactionSignature) {
|
fun checkSignature(sig: TransactionSignature) {
|
||||||
|
@ -471,9 +471,9 @@ class CryptoUtilsTest {
|
|||||||
val privKeyDecoded = Crypto.decodePrivateKey(privKey.encoded)
|
val privKeyDecoded = Crypto.decodePrivateKey(privKey.encoded)
|
||||||
val pubKeyDecoded = Crypto.decodePublicKey(pubKey.encoded)
|
val pubKeyDecoded = Crypto.decodePublicKey(pubKey.encoded)
|
||||||
|
|
||||||
assertEquals(privKeyDecoded.algorithm, "ECDSA")
|
assertEquals(privKeyDecoded.algorithm, "EC")
|
||||||
assertEquals((privKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
assertEquals((privKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||||
assertEquals(pubKeyDecoded.algorithm, "ECDSA")
|
assertEquals(pubKeyDecoded.algorithm, "EC")
|
||||||
assertEquals((pubKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
assertEquals((pubKeyDecoded as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256k1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,9 +481,9 @@ class CryptoUtilsTest {
|
|||||||
fun `ECDSA secp256r1 scheme finder by key type`() {
|
fun `ECDSA secp256r1 scheme finder by key type`() {
|
||||||
val keyPairR1 = Crypto.generateKeyPair(ECDSA_SECP256R1_SHA256)
|
val keyPairR1 = Crypto.generateKeyPair(ECDSA_SECP256R1_SHA256)
|
||||||
val (privR1, pubR1) = keyPairR1
|
val (privR1, pubR1) = keyPairR1
|
||||||
assertEquals(privR1.algorithm, "ECDSA")
|
assertEquals(privR1.algorithm, "EC")
|
||||||
assertEquals((privR1 as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256r1"))
|
assertEquals((privR1 as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256r1"))
|
||||||
assertEquals(pubR1.algorithm, "ECDSA")
|
assertEquals(pubR1.algorithm, "EC")
|
||||||
assertEquals((pubR1 as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256r1"))
|
assertEquals((pubR1 as ECKey).parameters, ECNamedCurveTable.getParameterSpec("secp256r1"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,11 +530,11 @@ class CryptoUtilsTest {
|
|||||||
val encodedPubK1 = pubK1.encoded
|
val encodedPubK1 = pubK1.encoded
|
||||||
|
|
||||||
val decodedPrivK1 = Crypto.decodePrivateKey(encodedPrivK1)
|
val decodedPrivK1 = Crypto.decodePrivateKey(encodedPrivK1)
|
||||||
assertEquals(decodedPrivK1.algorithm, "ECDSA")
|
assertEquals(decodedPrivK1.algorithm, "EC")
|
||||||
assertEquals(decodedPrivK1, privK1)
|
assertEquals(decodedPrivK1, privK1)
|
||||||
|
|
||||||
val decodedPubK1 = Crypto.decodePublicKey(encodedPubK1)
|
val decodedPubK1 = Crypto.decodePublicKey(encodedPubK1)
|
||||||
assertEquals(decodedPubK1.algorithm, "ECDSA")
|
assertEquals(decodedPubK1.algorithm, "EC")
|
||||||
assertEquals(decodedPubK1, pubK1)
|
assertEquals(decodedPubK1, pubK1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,11 +546,11 @@ class CryptoUtilsTest {
|
|||||||
val encodedPubR1 = pubR1.encoded
|
val encodedPubR1 = pubR1.encoded
|
||||||
|
|
||||||
val decodedPrivR1 = Crypto.decodePrivateKey(encodedPrivR1)
|
val decodedPrivR1 = Crypto.decodePrivateKey(encodedPrivR1)
|
||||||
assertEquals(decodedPrivR1.algorithm, "ECDSA")
|
assertEquals(decodedPrivR1.algorithm, "EC")
|
||||||
assertEquals(decodedPrivR1, privR1)
|
assertEquals(decodedPrivR1, privR1)
|
||||||
|
|
||||||
val decodedPubR1 = Crypto.decodePublicKey(encodedPubR1)
|
val decodedPubR1 = Crypto.decodePublicKey(encodedPubR1)
|
||||||
assertEquals(decodedPubR1.algorithm, "ECDSA")
|
assertEquals(decodedPubR1.algorithm, "EC")
|
||||||
assertEquals(decodedPubR1, pubR1)
|
assertEquals(decodedPubR1, pubR1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
package net.corda.core.node.services.vault
|
||||||
|
|
||||||
|
import net.corda.core.node.services.vault.Builder.`in`
|
||||||
|
import net.corda.core.node.services.vault.Builder.equal
|
||||||
|
import net.corda.core.node.services.vault.Builder.greaterThan
|
||||||
|
import net.corda.core.node.services.vault.Builder.greaterThanOrEqual
|
||||||
|
import net.corda.core.node.services.vault.Builder.isNull
|
||||||
|
import net.corda.core.node.services.vault.Builder.lessThan
|
||||||
|
import net.corda.core.node.services.vault.Builder.lessThanOrEqual
|
||||||
|
import net.corda.core.node.services.vault.Builder.like
|
||||||
|
import net.corda.core.node.services.vault.Builder.notEqual
|
||||||
|
import net.corda.core.node.services.vault.Builder.notIn
|
||||||
|
import net.corda.core.node.services.vault.Builder.notLike
|
||||||
|
import net.corda.core.node.services.vault.Builder.notNull
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.AggregateFunction
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.Between
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.BinaryComparison
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.CollectionExpression
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.EqualityComparison
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.Likeness
|
||||||
|
import net.corda.core.node.services.vault.ColumnPredicate.NullExpression
|
||||||
|
import net.corda.core.node.services.vault.CriteriaExpression.ColumnPredicateExpression
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.assertj.core.api.ObjectAssert
|
||||||
|
import org.junit.Test
|
||||||
|
import javax.persistence.Entity
|
||||||
|
|
||||||
|
class QueryCriteriaUtilsBuilderTest {
|
||||||
|
|
||||||
|
/** JPA Entity class needed by `getField` */
|
||||||
|
@Entity
|
||||||
|
private class TestEntity(val field: String)
|
||||||
|
|
||||||
|
/** Returns a `FieldInfo` object to work on */
|
||||||
|
private val fieldInfo: FieldInfo get() = getField("field", TestEntity::class.java)
|
||||||
|
|
||||||
|
/** Thrown for the `ColumnPredicate` types that have no `operator` field */
|
||||||
|
private class ColumnPredicateHasNoOperatorFieldException : Exception("This ColumnPredicate has no operator field")
|
||||||
|
|
||||||
|
/** Returns the `operator` for the given `ColumnPredicate` */
|
||||||
|
private fun ColumnPredicate<out Any?>.getOperator(): Operator = when (this) {
|
||||||
|
is AggregateFunction -> throw ColumnPredicateHasNoOperatorFieldException()
|
||||||
|
is Between -> throw ColumnPredicateHasNoOperatorFieldException()
|
||||||
|
is BinaryComparison<*> -> operator
|
||||||
|
is CollectionExpression -> operator
|
||||||
|
is EqualityComparison<*> -> operator
|
||||||
|
is Likeness -> operator
|
||||||
|
is NullExpression -> operator
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the `operator` for the given `ColumnPredicateExpression` */
|
||||||
|
private fun ColumnPredicateExpression<Any, *>.getOperator(): Operator = this.predicate.getOperator()
|
||||||
|
|
||||||
|
/** Assert that the `ColumnPredicateExpression` uses the given `Operator`. */
|
||||||
|
private fun <T : ColumnPredicateExpression<Any, C>, C> ObjectAssert<T>.usesOperator(operator: Operator) {
|
||||||
|
extracting {
|
||||||
|
assertThat(it.getOperator()).isEqualTo(operator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sample `String` value to pass to the predicate expression */
|
||||||
|
private val stringValue = ""
|
||||||
|
|
||||||
|
/** Sample `List` value to pass to the predicate expression */
|
||||||
|
private val listValue = emptyList<String>()
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `equal predicate uses EQUAL operator`() {
|
||||||
|
assertThat(fieldInfo.equal(stringValue)).usesOperator(EqualityComparisonOperator.EQUAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `equal predicate (exactMatch=false) uses EQUAL_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.equal(stringValue, exactMatch = false)).usesOperator(EqualityComparisonOperator.EQUAL_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notEqual predicate uses NOT_EQUAL operator`() {
|
||||||
|
assertThat(fieldInfo.notEqual(stringValue)).usesOperator(EqualityComparisonOperator.NOT_EQUAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notEqual predicate (exactMatch=false) uses NOT_EQUAL_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.notEqual(stringValue, exactMatch = false)).usesOperator(EqualityComparisonOperator.NOT_EQUAL_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `lessThan predicate uses LESS_THAN operator`() {
|
||||||
|
assertThat(fieldInfo.lessThan(stringValue)).usesOperator(BinaryComparisonOperator.LESS_THAN)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `lessThanOrEqual predicate uses LESS_THAN_OR_EQUAL operator`() {
|
||||||
|
assertThat(fieldInfo.lessThanOrEqual(stringValue)).usesOperator(BinaryComparisonOperator.LESS_THAN_OR_EQUAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `greaterThan predicate uses GREATER_THAN operator`() {
|
||||||
|
assertThat(fieldInfo.greaterThan(stringValue)).usesOperator(BinaryComparisonOperator.GREATER_THAN)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `greaterThanOrEqual predicate uses GREATER_THAN_OR_EQUAL operator`() {
|
||||||
|
assertThat(fieldInfo.greaterThanOrEqual(stringValue)).usesOperator(BinaryComparisonOperator.GREATER_THAN_OR_EQUAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `in predicate uses IN operator`() {
|
||||||
|
assertThat(fieldInfo.`in`(listValue)).usesOperator(CollectionOperator.IN)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `in predicate (exactMatch=false) uses IN_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.`in`(listValue, exactMatch = false)).usesOperator(CollectionOperator.IN_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notIn predicate uses NOT_IN operator`() {
|
||||||
|
assertThat(fieldInfo.notIn(listValue)).usesOperator(CollectionOperator.NOT_IN)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notIn predicate (exactMatch=false) uses NOT_IN_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.notIn(listValue, exactMatch = false)).usesOperator(CollectionOperator.NOT_IN_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `like predicate uses LIKE operator`() {
|
||||||
|
assertThat(fieldInfo.like(stringValue)).usesOperator(LikenessOperator.LIKE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `like predicate (exactMatch=false) uses LIKE_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.like(stringValue, exactMatch = false)).usesOperator(LikenessOperator.LIKE_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notLike predicate uses NOT_LIKE operator`() {
|
||||||
|
assertThat(fieldInfo.notLike(stringValue)).usesOperator(LikenessOperator.NOT_LIKE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notLike predicate (exactMatch=false) uses NOT_LIKE_IGNORE_CASE operator`() {
|
||||||
|
assertThat(fieldInfo.notLike(stringValue, exactMatch = false)).usesOperator(LikenessOperator.NOT_LIKE_IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `isNull predicate uses IS_NULL operator`() {
|
||||||
|
assertThat(fieldInfo.isNull()).usesOperator(NullOperator.IS_NULL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 500)
|
||||||
|
fun `notNull predicate uses NOT_NULL operator`() {
|
||||||
|
assertThat(fieldInfo.notNull()).usesOperator(NullOperator.NOT_NULL)
|
||||||
|
}
|
||||||
|
}
|
@ -87,11 +87,9 @@
|
|||||||
<ID>ComplexCondition:InternalUtils.kt$it.type == this && it.isPublic && it.isStatic && it.isFinal</ID>
|
<ID>ComplexCondition:InternalUtils.kt$it.type == this && it.isPublic && it.isStatic && it.isFinal</ID>
|
||||||
<ID>ComplexCondition:Main.kt$Main$(hostname != null) && (port != null) && (username != null) && (password != null)</ID>
|
<ID>ComplexCondition:Main.kt$Main$(hostname != null) && (port != null) && (username != null) && (password != null)</ID>
|
||||||
<ID>ComplexCondition:Schema.kt$obj == null || obj is DescribedType || obj is Binary || forGenericType(type).run { isPrimitive(this) || this == TopType }</ID>
|
<ID>ComplexCondition:Schema.kt$obj == null || obj is DescribedType || obj is Binary || forGenericType(type).run { isPrimitive(this) || this == TopType }</ID>
|
||||||
<ID>ComplexCondition:TopLevelTransition.kt$TopLevelTransition$currentState.isTransactionTracked && checkpoint.flowState is FlowState.Started && checkpoint.flowState.flowIORequest is FlowIORequest.WaitForLedgerCommit && checkpoint.flowState.flowIORequest.hash == event.transaction.id</ID>
|
|
||||||
<ID>ComplexCondition:WireTransaction.kt$WireTransaction$notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)</ID>
|
<ID>ComplexCondition:WireTransaction.kt$WireTransaction$notary != null && (inputs.isNotEmpty() || references.isNotEmpty() || timeWindow != null)</ID>
|
||||||
<ID>ComplexMethod:AMQPBridgeManager.kt$AMQPBridgeManager.AMQPBridge$private fun clientArtemisMessageHandler(artemisMessage: ClientMessage)</ID>
|
<ID>ComplexMethod:AMQPBridgeManager.kt$AMQPBridgeManager.AMQPBridge$private fun clientArtemisMessageHandler(artemisMessage: ClientMessage)</ID>
|
||||||
<ID>ComplexMethod:AMQPBridgeTest.kt$AMQPBridgeTest$@Test(timeout=300_000) fun `test acked and nacked messages`()</ID>
|
<ID>ComplexMethod:AMQPBridgeTest.kt$AMQPBridgeTest$@Test(timeout=300_000) fun `test acked and nacked messages`()</ID>
|
||||||
<ID>ComplexMethod:AMQPChannelHandler.kt$AMQPChannelHandler$override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any)</ID>
|
|
||||||
<ID>ComplexMethod:AMQPTypeIdentifierParser.kt$AMQPTypeIdentifierParser$// Make sure our inputs aren't designed to blow things up. private fun validate(typeString: String)</ID>
|
<ID>ComplexMethod:AMQPTypeIdentifierParser.kt$AMQPTypeIdentifierParser$// Make sure our inputs aren't designed to blow things up. private fun validate(typeString: String)</ID>
|
||||||
<ID>ComplexMethod:ANSIProgressRenderer.kt$ANSIProgressRenderer$// Returns number of lines rendered. private fun renderLevel(ansi: Ansi, error: Boolean): Int</ID>
|
<ID>ComplexMethod:ANSIProgressRenderer.kt$ANSIProgressRenderer$// Returns number of lines rendered. private fun renderLevel(ansi: Ansi, error: Boolean): Int</ID>
|
||||||
<ID>ComplexMethod:ANSIProgressRenderer.kt$ANSIProgressRenderer$@Synchronized protected fun draw(moveUp: Boolean, error: Throwable? = null)</ID>
|
<ID>ComplexMethod:ANSIProgressRenderer.kt$ANSIProgressRenderer$@Synchronized protected fun draw(moveUp: Boolean, error: Throwable? = null)</ID>
|
||||||
@ -124,13 +122,10 @@
|
|||||||
<ID>ComplexMethod:ConfigUtilities.kt$// For Iterables figure out the type parameter and apply the same logic as above on the individual elements. private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?></ID>
|
<ID>ComplexMethod:ConfigUtilities.kt$// For Iterables figure out the type parameter and apply the same logic as above on the individual elements. private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?></ID>
|
||||||
<ID>ComplexMethod:ConfigUtilities.kt$// TODO Move this to KeyStoreConfigHelpers. fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name, signingCertificateStore: FileBasedCertificateStoreSupplier, certificatesDirectory: Path, cryptoService: CryptoService? = null)</ID>
|
<ID>ComplexMethod:ConfigUtilities.kt$// TODO Move this to KeyStoreConfigHelpers. fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500Name, signingCertificateStore: FileBasedCertificateStoreSupplier, certificatesDirectory: Path, cryptoService: CryptoService? = null)</ID>
|
||||||
<ID>ComplexMethod:ConfigUtilities.kt$@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") // Reflect over the fields of the receiver and generate a value Map that can use to create Config object. private fun Any.toConfigMap(): Map<String, Any></ID>
|
<ID>ComplexMethod:ConfigUtilities.kt$@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") // Reflect over the fields of the receiver and generate a value Map that can use to create Config object. private fun Any.toConfigMap(): Map<String, Any></ID>
|
||||||
<ID>ComplexMethod:ConfigUtilities.kt$private fun Config.getCollectionValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit, nestedPath: String?, baseDirectory: Path?): Collection<Any></ID>
|
|
||||||
<ID>ComplexMethod:ConfigUtilities.kt$private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set<String>, logger: Logger) -> Unit, nestedPath: String?, baseDirectory: Path?): Any?</ID>
|
|
||||||
<ID>ComplexMethod:ConfigUtilities.kt$private fun convertValue(value: Any): Any</ID>
|
<ID>ComplexMethod:ConfigUtilities.kt$private fun convertValue(value: Any): Any</ID>
|
||||||
<ID>ComplexMethod:ConnectionStateMachine.kt$ConnectionStateMachine$override fun onConnectionFinal(event: Event)</ID>
|
<ID>ComplexMethod:ConnectionStateMachine.kt$ConnectionStateMachine$override fun onConnectionFinal(event: Event)</ID>
|
||||||
<ID>ComplexMethod:ConnectionStateMachine.kt$ConnectionStateMachine$override fun onDelivery(event: Event)</ID>
|
<ID>ComplexMethod:ConnectionStateMachine.kt$ConnectionStateMachine$override fun onDelivery(event: Event)</ID>
|
||||||
<ID>ComplexMethod:ConstraintsUtils.kt$ fun AttachmentConstraint.canBeTransitionedFrom(input: AttachmentConstraint, attachment: ContractAttachment): Boolean</ID>
|
<ID>ComplexMethod:ConstraintsUtils.kt$ fun AttachmentConstraint.canBeTransitionedFrom(input: AttachmentConstraint, attachment: ContractAttachment): Boolean</ID>
|
||||||
<ID>ComplexMethod:CordaCliWrapper.kt$fun CordaCliWrapper.start(args: Array<String>)</ID>
|
|
||||||
<ID>ComplexMethod:CordaPersistence.kt$CordaPersistence$private fun <T> inTopLevelTransaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int, recoverAnyNestedSQLException: Boolean, statement: DatabaseTransaction.() -> T): T</ID>
|
<ID>ComplexMethod:CordaPersistence.kt$CordaPersistence$private fun <T> inTopLevelTransaction(isolationLevel: TransactionIsolationLevel, recoverableFailureTolerance: Int, recoverAnyNestedSQLException: Boolean, statement: DatabaseTransaction.() -> T): T</ID>
|
||||||
<ID>ComplexMethod:CordaRPCClient.kt$CordaRPCClientConfiguration$override fun equals(other: Any?): Boolean</ID>
|
<ID>ComplexMethod:CordaRPCClient.kt$CordaRPCClientConfiguration$override fun equals(other: Any?): Boolean</ID>
|
||||||
<ID>ComplexMethod:CordaRPCClientTest.kt$CordaRPCClientTest$@Test(timeout=300_000) fun `shutdown command stops the node`()</ID>
|
<ID>ComplexMethod:CordaRPCClientTest.kt$CordaRPCClientTest$@Test(timeout=300_000) fun `shutdown command stops the node`()</ID>
|
||||||
@ -164,7 +159,6 @@
|
|||||||
<ID>ComplexMethod:MerkleTransaction.kt$FilteredTransaction.Companion$ private fun filterWithFun(wtx: WireTransaction, filtering: Predicate<Any>): List<FilteredComponentGroup></ID>
|
<ID>ComplexMethod:MerkleTransaction.kt$FilteredTransaction.Companion$ private fun filterWithFun(wtx: WireTransaction, filtering: Predicate<Any>): List<FilteredComponentGroup></ID>
|
||||||
<ID>ComplexMethod:NetworkBootstrapper.kt$NetworkBootstrapper$private fun bootstrap( directory: Path, cordappJars: List<Path>, copyCordapps: CopyCordapps, fromCordform: Boolean, networkParametersOverrides: NetworkParametersOverrides = NetworkParametersOverrides() )</ID>
|
<ID>ComplexMethod:NetworkBootstrapper.kt$NetworkBootstrapper$private fun bootstrap( directory: Path, cordappJars: List<Path>, copyCordapps: CopyCordapps, fromCordform: Boolean, networkParametersOverrides: NetworkParametersOverrides = NetworkParametersOverrides() )</ID>
|
||||||
<ID>ComplexMethod:NetworkBootstrapper.kt$NetworkBootstrapper$private fun createNodeDirectoriesIfNeeded(directory: Path, fromCordform: Boolean): Boolean</ID>
|
<ID>ComplexMethod:NetworkBootstrapper.kt$NetworkBootstrapper$private fun createNodeDirectoriesIfNeeded(directory: Path, fromCordform: Boolean): Boolean</ID>
|
||||||
<ID>ComplexMethod:NetworkMapUpdater.kt$NetworkMapUpdater$fun updateNetworkMapCache(): Duration</ID>
|
|
||||||
<ID>ComplexMethod:NetworkParametersReader.kt$NetworkParametersReader$fun read(): NetworkParametersAndSigned</ID>
|
<ID>ComplexMethod:NetworkParametersReader.kt$NetworkParametersReader$fun read(): NetworkParametersAndSigned</ID>
|
||||||
<ID>ComplexMethod:NetworkRegistrationHelper.kt$NetworkRegistrationHelper$ private fun pollServerForCertificates(requestId: String): List<X509Certificate></ID>
|
<ID>ComplexMethod:NetworkRegistrationHelper.kt$NetworkRegistrationHelper$ private fun pollServerForCertificates(requestId: String): List<X509Certificate></ID>
|
||||||
<ID>ComplexMethod:NewTransaction.kt$NewTransaction$fun show(window: Window)</ID>
|
<ID>ComplexMethod:NewTransaction.kt$NewTransaction$fun show(window: Window)</ID>
|
||||||
@ -182,7 +176,6 @@
|
|||||||
<ID>ComplexMethod:RPCClientProxyHandler.kt$RPCClientProxyHandler$// This is the general function that transforms a client side RPC to internal Artemis messages. override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any?</ID>
|
<ID>ComplexMethod:RPCClientProxyHandler.kt$RPCClientProxyHandler$// This is the general function that transforms a client side RPC to internal Artemis messages. override fun invoke(proxy: Any, method: Method, arguments: Array<out Any?>?): Any?</ID>
|
||||||
<ID>ComplexMethod:RPCClientProxyHandler.kt$RPCClientProxyHandler$private fun attemptReconnect()</ID>
|
<ID>ComplexMethod:RPCClientProxyHandler.kt$RPCClientProxyHandler$private fun attemptReconnect()</ID>
|
||||||
<ID>ComplexMethod:RPCServer.kt$RPCServer$private fun clientArtemisMessageHandler(artemisMessage: ClientMessage)</ID>
|
<ID>ComplexMethod:RPCServer.kt$RPCServer$private fun clientArtemisMessageHandler(artemisMessage: ClientMessage)</ID>
|
||||||
<ID>ComplexMethod:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ErrorInterceptingHandler$ private fun doInvoke(method: Method, args: Array<out Any>?, maxNumberOfAttempts: Int): Any?</ID>
|
|
||||||
<ID>ComplexMethod:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ReconnectingRPCConnection$ private tailrec fun establishConnectionWithRetry( retryInterval: Duration, roundRobinIndex: Int = 0, retries: Int = -1 ): CordaRPCConnection?</ID>
|
<ID>ComplexMethod:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ReconnectingRPCConnection$ private tailrec fun establishConnectionWithRetry( retryInterval: Duration, roundRobinIndex: Int = 0, retries: Int = -1 ): CordaRPCConnection?</ID>
|
||||||
<ID>ComplexMethod:RemoteTypeCarpenter.kt$SchemaBuildingRemoteTypeCarpenter$override fun carpent(typeInformation: RemoteTypeInformation): Type</ID>
|
<ID>ComplexMethod:RemoteTypeCarpenter.kt$SchemaBuildingRemoteTypeCarpenter$override fun carpent(typeInformation: RemoteTypeInformation): Type</ID>
|
||||||
<ID>ComplexMethod:RpcReconnectTests.kt$RpcReconnectTests$ @Test(timeout=300_000) fun `test that the RPC client is able to reconnect and proceed after node failure, restart, or connection reset`()</ID>
|
<ID>ComplexMethod:RpcReconnectTests.kt$RpcReconnectTests$ @Test(timeout=300_000) fun `test that the RPC client is able to reconnect and proceed after node failure, restart, or connection reset`()</ID>
|
||||||
@ -215,7 +208,6 @@
|
|||||||
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$AsyncRetryFlow$()</ID>
|
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$AsyncRetryFlow$()</ID>
|
||||||
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$RetryFlow$()</ID>
|
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$RetryFlow$()</ID>
|
||||||
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$ThrowingFlow$()</ID>
|
<ID>EmptyDefaultConstructor:FlowRetryTest.kt$ThrowingFlow$()</ID>
|
||||||
<ID>EmptyElseBlock:CordaCliWrapper.kt${ }</ID>
|
|
||||||
<ID>EmptyIfBlock:ContentSignerBuilder.kt$ContentSignerBuilder.SignatureOutputStream$if (alreadySigned) throw IllegalStateException("Cannot write to already signed object")</ID>
|
<ID>EmptyIfBlock:ContentSignerBuilder.kt$ContentSignerBuilder.SignatureOutputStream$if (alreadySigned) throw IllegalStateException("Cannot write to already signed object")</ID>
|
||||||
<ID>EmptyIfBlock:InMemoryIdentityService.kt$InMemoryIdentityService${ }</ID>
|
<ID>EmptyIfBlock:InMemoryIdentityService.kt$InMemoryIdentityService${ }</ID>
|
||||||
<ID>EmptyKtFile:KryoHook.kt$.KryoHook.kt</ID>
|
<ID>EmptyKtFile:KryoHook.kt$.KryoHook.kt</ID>
|
||||||
@ -327,11 +319,9 @@
|
|||||||
<ID>ForbiddenComment:CustomSerializer.kt$CustomSerializer.SubClass$// TODO: should this be a custom serializer at all, or should it just be a plain AMQPSerializer?</ID>
|
<ID>ForbiddenComment:CustomSerializer.kt$CustomSerializer.SubClass$// TODO: should this be a custom serializer at all, or should it just be a plain AMQPSerializer?</ID>
|
||||||
<ID>ForbiddenComment:CustomSerializer.kt$CustomSerializer.SubClass$// TODO: should this be empty or contain the schema of the super?</ID>
|
<ID>ForbiddenComment:CustomSerializer.kt$CustomSerializer.SubClass$// TODO: should this be empty or contain the schema of the super?</ID>
|
||||||
<ID>ForbiddenComment:DbTransactionsResolver.kt$DbTransactionsResolver$// TODO: This approach has two problems. Analyze and resolve them:</ID>
|
<ID>ForbiddenComment:DbTransactionsResolver.kt$DbTransactionsResolver$// TODO: This approach has two problems. Analyze and resolve them:</ID>
|
||||||
<ID>ForbiddenComment:DefaultKryoCustomizer.kt$DefaultKryoCustomizer$// TODO: re-organise registrations into logical groups before v1.0</ID>
|
|
||||||
<ID>ForbiddenComment:DigitalSignatureWithCert.kt$// TODO: Rename this to DigitalSignature.WithCert once we're happy for it to be public API. The methods will need documentation</ID>
|
<ID>ForbiddenComment:DigitalSignatureWithCert.kt$// TODO: Rename this to DigitalSignature.WithCert once we're happy for it to be public API. The methods will need documentation</ID>
|
||||||
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl$// TODO: Derive name from the full picked name, don't just wrap the common name</ID>
|
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl$// TODO: Derive name from the full picked name, don't just wrap the common name</ID>
|
||||||
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl$//TODO: remove this once we can bundle quasar properly.</ID>
|
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl$//TODO: remove this once we can bundle quasar properly.</ID>
|
||||||
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl.Companion$// TODO: There is pending work to fix this issue without custom blacklisting. See: https://r3-cev.atlassian.net/browse/CORDA-2164.</ID>
|
|
||||||
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl.LocalNetworkMap$// TODO: this object will copy NodeInfo files from started nodes to other nodes additional-node-infos/</ID>
|
<ID>ForbiddenComment:DriverDSLImpl.kt$DriverDSLImpl.LocalNetworkMap$// TODO: this object will copy NodeInfo files from started nodes to other nodes additional-node-infos/</ID>
|
||||||
<ID>ForbiddenComment:DummyFungibleContract.kt$DummyFungibleContract$// TODO: This doesn't work with the trader demo, so use the underlying key instead</ID>
|
<ID>ForbiddenComment:DummyFungibleContract.kt$DummyFungibleContract$// TODO: This doesn't work with the trader demo, so use the underlying key instead</ID>
|
||||||
<ID>ForbiddenComment:E2ETestKeyManagementService.kt$E2ETestKeyManagementService$// TODO: A full KeyManagementService implementation needs to record activity to the Audit Service and to limit</ID>
|
<ID>ForbiddenComment:E2ETestKeyManagementService.kt$E2ETestKeyManagementService$// TODO: A full KeyManagementService implementation needs to record activity to the Audit Service and to limit</ID>
|
||||||
@ -350,7 +340,6 @@
|
|||||||
<ID>ForbiddenComment:FlowLogicRefFactoryImpl.kt$FlowLogicRefFactoryImpl$// TODO: This is used via RPC but it's probably better if we pass in argument names and values explicitly</ID>
|
<ID>ForbiddenComment:FlowLogicRefFactoryImpl.kt$FlowLogicRefFactoryImpl$// TODO: This is used via RPC but it's probably better if we pass in argument names and values explicitly</ID>
|
||||||
<ID>ForbiddenComment:GenerateRpcSslCertsCli.kt$GenerateRpcSslCerts$// TODO: consider adding a password strength policy.</ID>
|
<ID>ForbiddenComment:GenerateRpcSslCertsCli.kt$GenerateRpcSslCerts$// TODO: consider adding a password strength policy.</ID>
|
||||||
<ID>ForbiddenComment:GuiUtilities.kt$// TODO: This is a temporary fix for the UI to show the correct issuer identity, this will break when we start randomizing keys. More work is needed here when the identity work is done.</ID>
|
<ID>ForbiddenComment:GuiUtilities.kt$// TODO: This is a temporary fix for the UI to show the correct issuer identity, this will break when we start randomizing keys. More work is needed here when the identity work is done.</ID>
|
||||||
<ID>ForbiddenComment:HibernateConfiguration.kt$HibernateConfiguration$// TODO: require mechanism to set schemaOptions (databaseSchema, tablePrefix) which are not global to session</ID>
|
|
||||||
<ID>ForbiddenComment:IRS.kt$FloatingRatePaymentEvent$// TODO: Should an uncalculated amount return a zero ? null ? etc.</ID>
|
<ID>ForbiddenComment:IRS.kt$FloatingRatePaymentEvent$// TODO: Should an uncalculated amount return a zero ? null ? etc.</ID>
|
||||||
<ID>ForbiddenComment:IRS.kt$InterestRateSwap$// TODO: Confirm: would someone really enter a swap with a negative fixed rate?</ID>
|
<ID>ForbiddenComment:IRS.kt$InterestRateSwap$// TODO: Confirm: would someone really enter a swap with a negative fixed rate?</ID>
|
||||||
<ID>ForbiddenComment:IRS.kt$InterestRateSwap$// TODO: further tests</ID>
|
<ID>ForbiddenComment:IRS.kt$InterestRateSwap$// TODO: further tests</ID>
|
||||||
@ -388,6 +377,7 @@
|
|||||||
<ID>ForbiddenComment:LegalNameValidator.kt$LegalNameValidator.Rule.Companion$// TODO: Implement confusable character detection if we add more scripts.</ID>
|
<ID>ForbiddenComment:LegalNameValidator.kt$LegalNameValidator.Rule.Companion$// TODO: Implement confusable character detection if we add more scripts.</ID>
|
||||||
<ID>ForbiddenComment:LocalTypeInformationBuilder.kt$// TODO: Revisit this when Kotlin issue is fixed.</ID>
|
<ID>ForbiddenComment:LocalTypeInformationBuilder.kt$// TODO: Revisit this when Kotlin issue is fixed.</ID>
|
||||||
<ID>ForbiddenComment:LoggingBuyerFlow.kt$LoggingBuyerFlow$// TODO: This is potentially very expensive, and requires transaction details we may no longer have once</ID>
|
<ID>ForbiddenComment:LoggingBuyerFlow.kt$LoggingBuyerFlow$// TODO: This is potentially very expensive, and requires transaction details we may no longer have once</ID>
|
||||||
|
<ID>ForbiddenComment:LoopbackBridgeManager.kt$LoopbackBridgeManager.LoopbackBridge$// TODO: refactor MDC support, duplicated in AMQPBridgeManager.</ID>
|
||||||
<ID>ForbiddenComment:MockServices.kt$MockServices.Companion$// TODO: Can we use an X509 principal generator here?</ID>
|
<ID>ForbiddenComment:MockServices.kt$MockServices.Companion$// TODO: Can we use an X509 principal generator here?</ID>
|
||||||
<ID>ForbiddenComment:NetParams.kt$NetParamsSigner$// TODO: not supported</ID>
|
<ID>ForbiddenComment:NetParams.kt$NetParamsSigner$// TODO: not supported</ID>
|
||||||
<ID>ForbiddenComment:NetworkBootstrapper.kt$NetworkBootstrapper$// TODO: pass a commandline parameter to the bootstrapper instead. Better yet, a notary config map</ID>
|
<ID>ForbiddenComment:NetworkBootstrapper.kt$NetworkBootstrapper$// TODO: pass a commandline parameter to the bootstrapper instead. Better yet, a notary config map</ID>
|
||||||
@ -630,8 +620,6 @@
|
|||||||
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_no_metadata()</ID>
|
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_no_metadata()</ID>
|
||||||
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_no_value()</ID>
|
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_no_value()</ID>
|
||||||
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_present()</ID>
|
<ID>FunctionNaming:VersionExtractorTest.kt$VersionExtractorTest$@Test(timeout=300_000) fun version_header_extraction_present()</ID>
|
||||||
<ID>FunctionNaming:VersionedParsingExampleTest.kt$VersionedParsingExampleTest$@Test(timeout=300_000) fun correct_parsing_function_is_used_for_present_version()</ID>
|
|
||||||
<ID>FunctionNaming:VersionedParsingExampleTest.kt$VersionedParsingExampleTest$@Test(timeout=300_000) fun default_value_is_used_for_absent_version()</ID>
|
|
||||||
<ID>LargeClass:AbstractNode.kt$AbstractNode<S> : SingletonSerializeAsToken</ID>
|
<ID>LargeClass:AbstractNode.kt$AbstractNode<S> : SingletonSerializeAsToken</ID>
|
||||||
<ID>LargeClass:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager : StateMachineManagerStateMachineManagerInternal</ID>
|
<ID>LargeClass:SingleThreadedStateMachineManager.kt$SingleThreadedStateMachineManager : StateMachineManagerStateMachineManagerInternal</ID>
|
||||||
<ID>LongMethod:FlowCookbook.kt$InitiatorFlow$@Suppress("RemoveExplicitTypeArguments") @Suspendable override fun call()</ID>
|
<ID>LongMethod:FlowCookbook.kt$InitiatorFlow$@Suppress("RemoveExplicitTypeArguments") @Suspendable override fun call()</ID>
|
||||||
@ -643,8 +631,8 @@
|
|||||||
<ID>LongParameterList:AbstractNode.kt$(databaseConfig: DatabaseConfig, wellKnownPartyFromX500Name: (CordaX500Name) -> Party?, wellKnownPartyFromAnonymous: (AbstractParty) -> Party?, schemaService: SchemaService, hikariProperties: Properties, cacheFactory: NamedCacheFactory, customClassLoader: ClassLoader?)</ID>
|
<ID>LongParameterList:AbstractNode.kt$(databaseConfig: DatabaseConfig, wellKnownPartyFromX500Name: (CordaX500Name) -> Party?, wellKnownPartyFromAnonymous: (AbstractParty) -> Party?, schemaService: SchemaService, hikariProperties: Properties, cacheFactory: NamedCacheFactory, customClassLoader: ClassLoader?)</ID>
|
||||||
<ID>LongParameterList:AbstractNode.kt$(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>, metricRegistry: MetricRegistry? = null, cordappLoader: CordappLoader? = null, currentDir: Path? = null, ourName: CordaX500Name)</ID>
|
<ID>LongParameterList:AbstractNode.kt$(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>, metricRegistry: MetricRegistry? = null, cordappLoader: CordappLoader? = null, currentDir: Path? = null, ourName: CordaX500Name)</ID>
|
||||||
<ID>LongParameterList:ArtemisMessagingServer.kt$ArtemisMessagingServer$(name: String, send: Boolean = false, consume: Boolean = false, createDurableQueue: Boolean = false, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false)</ID>
|
<ID>LongParameterList:ArtemisMessagingServer.kt$ArtemisMessagingServer$(name: String, send: Boolean = false, consume: Boolean = false, createDurableQueue: Boolean = false, deleteDurableQueue: Boolean = false, createNonDurableQueue: Boolean = false, deleteNonDurableQueue: Boolean = false, manage: Boolean = false, browse: Boolean = false)</ID>
|
||||||
<ID>LongParameterList:ArtemisRpcBroker.kt$ArtemisRpcBroker.Companion$(configuration: MutualSslConfiguration, address: NetworkHostAndPort, adminAddress: NetworkHostAndPort, securityManager: RPCSecurityManager, maxMessageSize: Int, jmxEnabled: Boolean, baseDirectory: Path, shouldStartLocalShell: Boolean)</ID>
|
<ID>LongParameterList:ArtemisRpcBroker.kt$ArtemisRpcBroker.Companion$(configuration: MutualSslConfiguration, address: NetworkHostAndPort, adminAddress: NetworkHostAndPort, securityManager: RPCSecurityManager, maxMessageSize: Int, journalBufferTimeout: Int?, jmxEnabled: Boolean, baseDirectory: Path, shouldStartLocalShell: Boolean)</ID>
|
||||||
<ID>LongParameterList:ArtemisRpcBroker.kt$ArtemisRpcBroker.Companion$(configuration: MutualSslConfiguration, address: NetworkHostAndPort, adminAddress: NetworkHostAndPort, sslOptions: BrokerRpcSslOptions, securityManager: RPCSecurityManager, maxMessageSize: Int, jmxEnabled: Boolean, baseDirectory: Path, shouldStartLocalShell: Boolean)</ID>
|
<ID>LongParameterList:ArtemisRpcBroker.kt$ArtemisRpcBroker.Companion$(configuration: MutualSslConfiguration, address: NetworkHostAndPort, adminAddress: NetworkHostAndPort, sslOptions: BrokerRpcSslOptions, securityManager: RPCSecurityManager, maxMessageSize: Int, journalBufferTimeout: Int?, jmxEnabled: Boolean, baseDirectory: Path, shouldStartLocalShell: Boolean)</ID>
|
||||||
<ID>LongParameterList:ArtemisRpcTests.kt$ArtemisRpcTests$(nodeSSlconfig: MutualSslConfiguration, brokerSslOptions: BrokerRpcSslOptions?, useSslForBroker: Boolean, clientSslOptions: ClientRpcSslOptions?, address: NetworkHostAndPort = ports.nextHostAndPort(), adminAddress: NetworkHostAndPort = ports.nextHostAndPort(), baseDirectory: Path = tempFolder.root.toPath() )</ID>
|
<ID>LongParameterList:ArtemisRpcTests.kt$ArtemisRpcTests$(nodeSSlconfig: MutualSslConfiguration, brokerSslOptions: BrokerRpcSslOptions?, useSslForBroker: Boolean, clientSslOptions: ClientRpcSslOptions?, address: NetworkHostAndPort = ports.nextHostAndPort(), adminAddress: NetworkHostAndPort = ports.nextHostAndPort(), baseDirectory: Path = tempFolder.root.toPath() )</ID>
|
||||||
<ID>LongParameterList:AttachmentsClassLoader.kt$AttachmentsClassLoaderBuilder$(attachments: List<Attachment>, params: NetworkParameters, txId: SecureHash, isAttachmentTrusted: (Attachment) -> Boolean, parent: ClassLoader = ClassLoader.getSystemClassLoader(), block: (ClassLoader) -> T)</ID>
|
<ID>LongParameterList:AttachmentsClassLoader.kt$AttachmentsClassLoaderBuilder$(attachments: List<Attachment>, params: NetworkParameters, txId: SecureHash, isAttachmentTrusted: (Attachment) -> Boolean, parent: ClassLoader = ClassLoader.getSystemClassLoader(), block: (ClassLoader) -> T)</ID>
|
||||||
<ID>LongParameterList:BFTSmart.kt$BFTSmart.Replica$( states: List<StateRef>, txId: SecureHash, callerName: CordaX500Name, requestSignature: NotarisationRequestSignature, timeWindow: TimeWindow?, references: List<StateRef> = emptyList() )</ID>
|
<ID>LongParameterList:BFTSmart.kt$BFTSmart.Replica$( states: List<StateRef>, txId: SecureHash, callerName: CordaX500Name, requestSignature: NotarisationRequestSignature, timeWindow: TimeWindow?, references: List<StateRef> = emptyList() )</ID>
|
||||||
@ -655,7 +643,6 @@
|
|||||||
<ID>LongParameterList:CertificateRevocationListNodeTests.kt$CertificateRevocationListNodeTests$(port: Int, name: CordaX500Name = ALICE_NAME, crlCheckSoftFail: Boolean, nodeCrlDistPoint: String = "http://${server.hostAndPort}/crl/node.crl", tlsCrlDistPoint: String? = "http://${server.hostAndPort}/crl/empty.crl", maxMessageSize: Int = MAX_MESSAGE_SIZE)</ID>
|
<ID>LongParameterList:CertificateRevocationListNodeTests.kt$CertificateRevocationListNodeTests$(port: Int, name: CordaX500Name = ALICE_NAME, crlCheckSoftFail: Boolean, nodeCrlDistPoint: String = "http://${server.hostAndPort}/crl/node.crl", tlsCrlDistPoint: String? = "http://${server.hostAndPort}/crl/empty.crl", maxMessageSize: Int = MAX_MESSAGE_SIZE)</ID>
|
||||||
<ID>LongParameterList:CertificateRevocationListNodeTests.kt$CertificateRevocationListNodeTests.Companion$(clrServer: CrlServer, signatureAlgorithm: String, caCertificate: X509Certificate, caPrivateKey: PrivateKey, endpoint: String, indirect: Boolean, vararg serialNumbers: BigInteger)</ID>
|
<ID>LongParameterList:CertificateRevocationListNodeTests.kt$CertificateRevocationListNodeTests.Companion$(clrServer: CrlServer, signatureAlgorithm: String, caCertificate: X509Certificate, caPrivateKey: PrivateKey, endpoint: String, indirect: Boolean, vararg serialNumbers: BigInteger)</ID>
|
||||||
<ID>LongParameterList:CertificateStoreStubs.kt$CertificateStoreStubs.P2P.Companion$(baseDirectory: Path, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, keyPassword: String = keyStorePassword, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD)</ID>
|
<ID>LongParameterList:CertificateStoreStubs.kt$CertificateStoreStubs.P2P.Companion$(baseDirectory: Path, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, keyPassword: String = keyStorePassword, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD)</ID>
|
||||||
<ID>LongParameterList:CertificateStoreStubs.kt$CertificateStoreStubs.P2P.Companion$(certificatesDirectory: Path, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, keyPassword: String = keyStorePassword, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD, trustStoreKeyPassword: String = TrustStore.DEFAULT_KEY_PASSWORD, @Suppress("UNUSED_PARAMETER") useOpenSsl: Boolean = false)</ID>
|
|
||||||
<ID>LongParameterList:ContractAttachment.kt$ContractAttachment.Companion$(attachment: Attachment, contract: ContractClassName, additionalContracts: Set<ContractClassName> = emptySet(), uploader: String? = null, signerKeys: List<PublicKey> = emptyList(), version: Int = DEFAULT_CORDAPP_VERSION)</ID>
|
<ID>LongParameterList:ContractAttachment.kt$ContractAttachment.Companion$(attachment: Attachment, contract: ContractClassName, additionalContracts: Set<ContractClassName> = emptySet(), uploader: String? = null, signerKeys: List<PublicKey> = emptyList(), version: Int = DEFAULT_CORDAPP_VERSION)</ID>
|
||||||
<ID>LongParameterList:ContractFunctions.kt$(expiry: String, notional: BigDecimal, strike: BigDecimal, foreignCurrency: Currency, domesticCurrency: Currency, partyA: Party, partyB: Party)</ID>
|
<ID>LongParameterList:ContractFunctions.kt$(expiry: String, notional: BigDecimal, strike: BigDecimal, foreignCurrency: Currency, domesticCurrency: Currency, partyA: Party, partyB: Party)</ID>
|
||||||
<ID>LongParameterList:ContractFunctions.kt$(expiry: String, notional: Long, strike: Double, foreignCurrency: Currency, domesticCurrency: Currency, partyA: Party, partyB: Party)</ID>
|
<ID>LongParameterList:ContractFunctions.kt$(expiry: String, notional: Long, strike: Double, foreignCurrency: Currency, domesticCurrency: Currency, partyA: Party, partyB: Party)</ID>
|
||||||
@ -925,7 +912,6 @@
|
|||||||
<ID>MagicNumber:IrsDemoWebApplication.kt$IrsDemoWebApplication$1000</ID>
|
<ID>MagicNumber:IrsDemoWebApplication.kt$IrsDemoWebApplication$1000</ID>
|
||||||
<ID>MagicNumber:JarScanningCordappLoader.kt$CordappLoaderTemplate$36</ID>
|
<ID>MagicNumber:JarScanningCordappLoader.kt$CordappLoaderTemplate$36</ID>
|
||||||
<ID>MagicNumber:JarScanningCordappLoader.kt$CordappLoaderTemplate$64</ID>
|
<ID>MagicNumber:JarScanningCordappLoader.kt$CordappLoaderTemplate$64</ID>
|
||||||
<ID>MagicNumber:JarScanningCordappLoader.kt$JarScanningCordappLoader$1000</ID>
|
|
||||||
<ID>MagicNumber:JarSignatureCollector.kt$JarSignatureCollector$1024</ID>
|
<ID>MagicNumber:JarSignatureCollector.kt$JarSignatureCollector$1024</ID>
|
||||||
<ID>MagicNumber:JarSignatureTestUtils.kt$JarSignatureTestUtils$14</ID>
|
<ID>MagicNumber:JarSignatureTestUtils.kt$JarSignatureTestUtils$14</ID>
|
||||||
<ID>MagicNumber:KMSUtils.kt$3650</ID>
|
<ID>MagicNumber:KMSUtils.kt$3650</ID>
|
||||||
@ -1207,7 +1193,6 @@
|
|||||||
<ID>MatchingDeclarationName:ConfigException.kt$net.corda.core.cordapp.ConfigException.kt</ID>
|
<ID>MatchingDeclarationName:ConfigException.kt$net.corda.core.cordapp.ConfigException.kt</ID>
|
||||||
<ID>MatchingDeclarationName:ConfigUtilities.kt$net.corda.node.services.config.ConfigUtilities.kt</ID>
|
<ID>MatchingDeclarationName:ConfigUtilities.kt$net.corda.node.services.config.ConfigUtilities.kt</ID>
|
||||||
<ID>MatchingDeclarationName:ContractsDSL.kt$net.corda.core.contracts.ContractsDSL.kt</ID>
|
<ID>MatchingDeclarationName:ContractsDSL.kt$net.corda.core.contracts.ContractsDSL.kt</ID>
|
||||||
<ID>MatchingDeclarationName:CordaUtils.kt$net.corda.core.internal.CordaUtils.kt</ID>
|
|
||||||
<ID>MatchingDeclarationName:CurrencyParameterSensitivitySerialiser.kt$net.corda.vega.plugin.customserializers.CurrencyParameterSensitivitySerialiser.kt</ID>
|
<ID>MatchingDeclarationName:CurrencyParameterSensitivitySerialiser.kt$net.corda.vega.plugin.customserializers.CurrencyParameterSensitivitySerialiser.kt</ID>
|
||||||
<ID>MatchingDeclarationName:FinanceWorkflowsUtils.kt$net.corda.finance.workflows.utils.FinanceWorkflowsUtils.kt</ID>
|
<ID>MatchingDeclarationName:FinanceWorkflowsUtils.kt$net.corda.finance.workflows.utils.FinanceWorkflowsUtils.kt</ID>
|
||||||
<ID>MatchingDeclarationName:FlowStackSnapshot.kt$net.corda.testing.internal.FlowStackSnapshot.kt</ID>
|
<ID>MatchingDeclarationName:FlowStackSnapshot.kt$net.corda.testing.internal.FlowStackSnapshot.kt</ID>
|
||||||
@ -1229,8 +1214,6 @@
|
|||||||
<ID>MatchingDeclarationName:Query.kt$net.corda.webserver.api.Query.kt</ID>
|
<ID>MatchingDeclarationName:Query.kt$net.corda.webserver.api.Query.kt</ID>
|
||||||
<ID>MatchingDeclarationName:ReceiveAllFlowTests.kt$net.corda.coretests.flows.ReceiveAllFlowTests.kt</ID>
|
<ID>MatchingDeclarationName:ReceiveAllFlowTests.kt$net.corda.coretests.flows.ReceiveAllFlowTests.kt</ID>
|
||||||
<ID>MatchingDeclarationName:ReferenceInputStateTests.kt$net.corda.coretests.transactions.ReferenceInputStateTests.kt</ID>
|
<ID>MatchingDeclarationName:ReferenceInputStateTests.kt$net.corda.coretests.transactions.ReferenceInputStateTests.kt</ID>
|
||||||
<ID>MatchingDeclarationName:RigorousMock.kt$net.corda.testing.internal.RigorousMock.kt</ID>
|
|
||||||
<ID>MatchingDeclarationName:RpcServerCordaFutureSerialiser.kt$net.corda.node.serialization.amqp.RpcServerCordaFutureSerialiser.kt</ID>
|
|
||||||
<ID>MatchingDeclarationName:SSLHelper.kt$net.corda.nodeapi.internal.protonwrapper.netty.SSLHelper.kt</ID>
|
<ID>MatchingDeclarationName:SSLHelper.kt$net.corda.nodeapi.internal.protonwrapper.netty.SSLHelper.kt</ID>
|
||||||
<ID>MatchingDeclarationName:SampleData.kt$net.corda.deterministic.verifier.SampleData.kt</ID>
|
<ID>MatchingDeclarationName:SampleData.kt$net.corda.deterministic.verifier.SampleData.kt</ID>
|
||||||
<ID>MatchingDeclarationName:SerializationHelper.kt$net.corda.networkbuilder.serialization.SerializationHelper.kt</ID>
|
<ID>MatchingDeclarationName:SerializationHelper.kt$net.corda.networkbuilder.serialization.SerializationHelper.kt</ID>
|
||||||
@ -1285,7 +1268,6 @@
|
|||||||
<ID>NestedBlockDepth:RPCClientProxyHandler.kt$RPCClientProxyHandler$// The handler for Artemis messages. private fun artemisMessageHandler(message: ClientMessage)</ID>
|
<ID>NestedBlockDepth:RPCClientProxyHandler.kt$RPCClientProxyHandler$// The handler for Artemis messages. private fun artemisMessageHandler(message: ClientMessage)</ID>
|
||||||
<ID>NestedBlockDepth:ShutdownManager.kt$ShutdownManager$fun shutdown()</ID>
|
<ID>NestedBlockDepth:ShutdownManager.kt$ShutdownManager$fun shutdown()</ID>
|
||||||
<ID>NestedBlockDepth:SpringDriver.kt$SpringBootDriverDSL$private fun queryWebserver(handle: NodeHandle, process: Process, checkUrl: String): WebserverHandle</ID>
|
<ID>NestedBlockDepth:SpringDriver.kt$SpringBootDriverDSL$private fun queryWebserver(handle: NodeHandle, process: Process, checkUrl: String): WebserverHandle</ID>
|
||||||
<ID>NestedBlockDepth:StartedFlowTransition.kt$StartedFlowTransition$private fun TransitionBuilder.sendToSessionsTransition(sourceSessionIdToMessage: Map<SessionId, SerializedBytes<Any>>)</ID>
|
|
||||||
<ID>NestedBlockDepth:StatusTransitions.kt$StatusTransitions$ fun verify(tx: LedgerTransaction)</ID>
|
<ID>NestedBlockDepth:StatusTransitions.kt$StatusTransitions$ fun verify(tx: LedgerTransaction)</ID>
|
||||||
<ID>NestedBlockDepth:ThrowableSerializer.kt$ThrowableSerializer$override fun fromProxy(proxy: ThrowableProxy): Throwable</ID>
|
<ID>NestedBlockDepth:ThrowableSerializer.kt$ThrowableSerializer$override fun fromProxy(proxy: ThrowableProxy): Throwable</ID>
|
||||||
<ID>NestedBlockDepth:TransactionVerifierServiceInternal.kt$Verifier$ private fun verifyConstraintsValidity(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>)</ID>
|
<ID>NestedBlockDepth:TransactionVerifierServiceInternal.kt$Verifier$ private fun verifyConstraintsValidity(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>)</ID>
|
||||||
@ -1316,7 +1298,6 @@
|
|||||||
<ID>SpreadOperator:ConfigUtilities.kt$(*pairs)</ID>
|
<ID>SpreadOperator:ConfigUtilities.kt$(*pairs)</ID>
|
||||||
<ID>SpreadOperator:Configuration.kt$Configuration.Validation.Error$(*(containingPath.toList() + this.containingPath).toTypedArray())</ID>
|
<ID>SpreadOperator:Configuration.kt$Configuration.Validation.Error$(*(containingPath.toList() + this.containingPath).toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:ContractJarTestUtils.kt$ContractJarTestUtils$(jarName, *contractNames.map{ "${it.replace(".", "/")}.class" }.toTypedArray())</ID>
|
<ID>SpreadOperator:ContractJarTestUtils.kt$ContractJarTestUtils$(jarName, *contractNames.map{ "${it.replace(".", "/")}.class" }.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:CordaCliWrapper.kt$(RunLast().useOut(System.out).useAnsi(defaultAnsiMode), DefaultExceptionHandler<List<Any>>().useErr(System.err).useAnsi(defaultAnsiMode).andExit(ExitCodes.FAILURE), *args)</ID>
|
|
||||||
<ID>SpreadOperator:CordaRPCOpsImpl.kt$CordaRPCOpsImpl$(logicType, context(), *args)</ID>
|
<ID>SpreadOperator:CordaRPCOpsImpl.kt$CordaRPCOpsImpl$(logicType, context(), *args)</ID>
|
||||||
<ID>SpreadOperator:CordaX500Name.kt$CordaX500Name.Companion$(*Locale.getISOCountries(), unspecifiedCountry)</ID>
|
<ID>SpreadOperator:CordaX500Name.kt$CordaX500Name.Companion$(*Locale.getISOCountries(), unspecifiedCountry)</ID>
|
||||||
<ID>SpreadOperator:CustomCordapp.kt$CustomCordapp$(*classes.map { it.name }.toTypedArray())</ID>
|
<ID>SpreadOperator:CustomCordapp.kt$CustomCordapp$(*classes.map { it.name }.toTypedArray())</ID>
|
||||||
@ -1326,7 +1307,6 @@
|
|||||||
<ID>SpreadOperator:DockerInstantiator.kt$DockerInstantiator$(*it.toTypedArray())</ID>
|
<ID>SpreadOperator:DockerInstantiator.kt$DockerInstantiator$(*it.toTypedArray())</ID>
|
||||||
<ID>SpreadOperator:DummyContract.kt$DummyContract.Companion$( /* INPUTS */ *priors.toTypedArray(), /* COMMAND */ Command(cmd, priorState.owner.owningKey), /* OUTPUT */ StateAndContract(state, PROGRAM_ID) )</ID>
|
<ID>SpreadOperator:DummyContract.kt$DummyContract.Companion$( /* INPUTS */ *priors.toTypedArray(), /* COMMAND */ Command(cmd, priorState.owner.owningKey), /* OUTPUT */ StateAndContract(state, PROGRAM_ID) )</ID>
|
||||||
<ID>SpreadOperator:DummyContract.kt$DummyContract.Companion$(*items)</ID>
|
<ID>SpreadOperator:DummyContract.kt$DummyContract.Companion$(*items)</ID>
|
||||||
<ID>SpreadOperator:DummyContractV2.kt$DummyContractV2.Companion$( /* INPUTS */ *priors.toTypedArray(), /* COMMAND */ Command(cmd, priorState.owners.map { it.owningKey }), /* OUTPUT */ StateAndContract(state, DummyContractV2.PROGRAM_ID) )</ID>
|
|
||||||
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*fields)</ID>
|
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*fields)</ID>
|
||||||
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*fields, cause.staticLocationBasedHash(hashedFields, visited + cause))</ID>
|
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*fields, cause.staticLocationBasedHash(hashedFields, visited + cause))</ID>
|
||||||
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*hashedFields.invoke(this))</ID>
|
<ID>SpreadOperator:ExceptionsErrorCodeFunctions.kt$(*hashedFields.invoke(this))</ID>
|
||||||
@ -1483,6 +1463,7 @@
|
|||||||
<ID>TooGenericExceptionCaught:AbstractNode.kt$ex: Exception</ID>
|
<ID>TooGenericExceptionCaught:AbstractNode.kt$ex: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:AbstractNodeTests.kt$ColdJVM.Companion$t: Throwable</ID>
|
<ID>TooGenericExceptionCaught:AbstractNodeTests.kt$ColdJVM.Companion$t: Throwable</ID>
|
||||||
<ID>TooGenericExceptionCaught:Amount.kt$Amount.Companion$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:Amount.kt$Amount.Companion$e: Exception</ID>
|
||||||
|
<ID>TooGenericExceptionCaught:ArtemisRpcBroker.kt$ArtemisRpcBroker$th: Throwable</ID>
|
||||||
<ID>TooGenericExceptionCaught:AttachmentDemo.kt$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:AttachmentDemo.kt$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:AttachmentLoadingTests.kt$AttachmentLoadingTests.ConsumeAndBroadcastResponderFlow$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:AttachmentLoadingTests.kt$AttachmentLoadingTests.ConsumeAndBroadcastResponderFlow$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:AttachmentVersionNumberMigration.kt$AttachmentVersionNumberMigration$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:AttachmentVersionNumberMigration.kt$AttachmentVersionNumberMigration$e: Exception</ID>
|
||||||
@ -1491,7 +1472,6 @@
|
|||||||
<ID>TooGenericExceptionCaught:BankOfCordaWebApi.kt$BankOfCordaWebApi$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:BankOfCordaWebApi.kt$BankOfCordaWebApi$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:BlobInspector.kt$BlobInspector$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:BlobInspector.kt$BlobInspector$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:BootstrapperView.kt$BootstrapperView$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:BootstrapperView.kt$BootstrapperView$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:BridgeControlListener.kt$BridgeControlListener$ex: Exception</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:BrokerJaasLoginModule.kt$BrokerJaasLoginModule$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:BrokerJaasLoginModule.kt$BrokerJaasLoginModule$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CertRole.kt$CertRole.Companion$ex: ArrayIndexOutOfBoundsException</ID>
|
<ID>TooGenericExceptionCaught:CertRole.kt$CertRole.Companion$ex: ArrayIndexOutOfBoundsException</ID>
|
||||||
<ID>TooGenericExceptionCaught:CheckpointAgent.kt$CheckpointAgent.Companion$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:CheckpointAgent.kt$CheckpointAgent.Companion$e: Exception</ID>
|
||||||
@ -1506,9 +1486,6 @@
|
|||||||
<ID>TooGenericExceptionCaught:ContractUpgradeTransactions.kt$ContractUpgradeWireTransaction$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:ContractUpgradeTransactions.kt$ContractUpgradeWireTransaction$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CordaAuthenticationPlugin.kt$CordaAuthenticationPlugin$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:CordaAuthenticationPlugin.kt$CordaAuthenticationPlugin$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CordaClassResolver.kt$LoggingWhitelist.Companion$ioEx: Exception</ID>
|
<ID>TooGenericExceptionCaught:CordaClassResolver.kt$LoggingWhitelist.Companion$ioEx: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CordaFutureImpl.kt$CordaFutureImpl$e: Exception</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:CordaFutureImpl.kt$ValueOrException$e: Exception</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:CordaFutureImpl.kt$e: Exception</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:CordaPersistence.kt$CordaPersistence$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:CordaPersistence.kt$CordaPersistence$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CordaRPCClientTest.kt$CordaRPCClientTest$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:CordaRPCClientTest.kt$CordaRPCClientTest$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:CordaRPCOpsImpl.kt$CordaRPCOpsImpl$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:CordaRPCOpsImpl.kt$CordaRPCOpsImpl$e: Exception</ID>
|
||||||
@ -1522,6 +1499,7 @@
|
|||||||
<ID>TooGenericExceptionCaught:DeserializeSimpleTypesTests.kt$DeserializeSimpleTypesTests$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:DeserializeSimpleTypesTests.kt$DeserializeSimpleTypesTests$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:DockerInstantiator.kt$DockerInstantiator$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:DockerInstantiator.kt$DockerInstantiator$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:DriverDSLImpl.kt$DriverDSLImpl$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:DriverDSLImpl.kt$DriverDSLImpl$e: Exception</ID>
|
||||||
|
<ID>TooGenericExceptionCaught:DriverDSLImpl.kt$DriverDSLImpl.Companion$th: Throwable</ID>
|
||||||
<ID>TooGenericExceptionCaught:DriverDSLImpl.kt$exception: Throwable</ID>
|
<ID>TooGenericExceptionCaught:DriverDSLImpl.kt$exception: Throwable</ID>
|
||||||
<ID>TooGenericExceptionCaught:DriverTests.kt$DriverTests$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:DriverTests.kt$DriverTests$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:ErrorCodeLoggingTests.kt$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:ErrorCodeLoggingTests.kt$e: Exception</ID>
|
||||||
@ -1616,7 +1594,7 @@
|
|||||||
<ID>TooGenericExceptionCaught:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ReconnectingRPCConnection$ex: Exception</ID>
|
<ID>TooGenericExceptionCaught:ReconnectingCordaRPCOps.kt$ReconnectingCordaRPCOps.ReconnectingRPCConnection$ex: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:ReconnectingObservable.kt$ReconnectingObservable.ReconnectingSubscriber$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:ReconnectingObservable.kt$ReconnectingObservable.ReconnectingSubscriber$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:RpcServerObservableSerializerTests.kt$RpcServerObservableSerializerTests$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:RpcServerObservableSerializerTests.kt$RpcServerObservableSerializerTests$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:SSLHelper.kt$LoggingTrustManagerWrapper$ex: Exception</ID>
|
<ID>TooGenericExceptionCaught:SSLHelper.kt$ex: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:ScheduledFlowIntegrationTests.kt$ScheduledFlowIntegrationTests$ex: Exception</ID>
|
<ID>TooGenericExceptionCaught:ScheduledFlowIntegrationTests.kt$ScheduledFlowIntegrationTests$ex: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:SerializationOutputTests.kt$SerializationOutputTests$t: Throwable</ID>
|
<ID>TooGenericExceptionCaught:SerializationOutputTests.kt$SerializationOutputTests$t: Throwable</ID>
|
||||||
<ID>TooGenericExceptionCaught:ShutdownManager.kt$ShutdownManager$t: Throwable</ID>
|
<ID>TooGenericExceptionCaught:ShutdownManager.kt$ShutdownManager$t: Throwable</ID>
|
||||||
@ -1644,7 +1622,6 @@
|
|||||||
<ID>TooGenericExceptionCaught:ValidatingNotaryFlow.kt$ValidatingNotaryFlow$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:ValidatingNotaryFlow.kt$ValidatingNotaryFlow$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateIterator$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateIterator$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateMigration$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:VaultStateMigration.kt$VaultStateMigration$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:VersionedParsingExampleTest.kt$VersionedParsingExampleTest.RpcSettingsSpec$e: Exception</ID>
|
|
||||||
<ID>TooGenericExceptionCaught:WebServer.kt$WebServer$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:WebServer.kt$WebServer$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:WebServer.kt$e: Exception</ID>
|
<ID>TooGenericExceptionCaught:WebServer.kt$e: Exception</ID>
|
||||||
<ID>TooGenericExceptionCaught:WebServer.kt$ex: Exception</ID>
|
<ID>TooGenericExceptionCaught:WebServer.kt$ex: Exception</ID>
|
||||||
@ -1699,7 +1676,6 @@
|
|||||||
<ID>TooManyFunctions:CryptoUtils.kt$net.corda.core.crypto.CryptoUtils.kt</ID>
|
<ID>TooManyFunctions:CryptoUtils.kt$net.corda.core.crypto.CryptoUtils.kt</ID>
|
||||||
<ID>TooManyFunctions:Currencies.kt$net.corda.finance.Currencies.kt</ID>
|
<ID>TooManyFunctions:Currencies.kt$net.corda.finance.Currencies.kt</ID>
|
||||||
<ID>TooManyFunctions:Driver.kt$DriverParameters</ID>
|
<ID>TooManyFunctions:Driver.kt$DriverParameters</ID>
|
||||||
<ID>TooManyFunctions:DriverDSLImpl.kt$DriverDSLImpl : InternalDriverDSL</ID>
|
|
||||||
<ID>TooManyFunctions:EncodingUtils.kt$net.corda.core.utilities.EncodingUtils.kt</ID>
|
<ID>TooManyFunctions:EncodingUtils.kt$net.corda.core.utilities.EncodingUtils.kt</ID>
|
||||||
<ID>TooManyFunctions:FlowLogic.kt$FlowLogic<out T></ID>
|
<ID>TooManyFunctions:FlowLogic.kt$FlowLogic<out T></ID>
|
||||||
<ID>TooManyFunctions:FlowStateMachineImpl.kt$FlowStateMachineImpl<R> : FiberFlowStateMachineFlowFiber</ID>
|
<ID>TooManyFunctions:FlowStateMachineImpl.kt$FlowStateMachineImpl<R> : FiberFlowStateMachineFlowFiber</ID>
|
||||||
@ -1761,6 +1737,18 @@
|
|||||||
<ID>TopLevelPropertyNaming:SerializationEnvironment.kt$val _inheritableContextSerializationEnv = InheritableThreadLocalToggleField<SerializationEnvironment>("inheritableContextSerializationEnv") { stack -> stack.fold(false) { isAGlobalThreadBeingCreated, e -> isAGlobalThreadBeingCreated || (e.className == "io.netty.util.concurrent.GlobalEventExecutor" && e.methodName == "startThread") || (e.className == "java.util.concurrent.ForkJoinPool\$DefaultForkJoinWorkerThreadFactory" && e.methodName == "newThread") } }</ID>
|
<ID>TopLevelPropertyNaming:SerializationEnvironment.kt$val _inheritableContextSerializationEnv = InheritableThreadLocalToggleField<SerializationEnvironment>("inheritableContextSerializationEnv") { stack -> stack.fold(false) { isAGlobalThreadBeingCreated, e -> isAGlobalThreadBeingCreated || (e.className == "io.netty.util.concurrent.GlobalEventExecutor" && e.methodName == "startThread") || (e.className == "java.util.concurrent.ForkJoinPool\$DefaultForkJoinWorkerThreadFactory" && e.methodName == "newThread") } }</ID>
|
||||||
<ID>TopLevelPropertyNaming:SerializationEnvironment.kt$val _rpcClientSerializationEnv = SimpleToggleField<SerializationEnvironment>("rpcClientSerializationEnv")</ID>
|
<ID>TopLevelPropertyNaming:SerializationEnvironment.kt$val _rpcClientSerializationEnv = SimpleToggleField<SerializationEnvironment>("rpcClientSerializationEnv")</ID>
|
||||||
<ID>TopLevelPropertyNaming:SerializationFormat.kt$const val encodingNotPermittedFormat = "Encoding not permitted: %s"</ID>
|
<ID>TopLevelPropertyNaming:SerializationFormat.kt$const val encodingNotPermittedFormat = "Encoding not permitted: %s"</ID>
|
||||||
|
<ID>UnusedImports:Amount.kt$import net.corda.core.crypto.CompositeKey</ID>
|
||||||
|
<ID>UnusedImports:Amount.kt$import net.corda.core.identity.Party</ID>
|
||||||
|
<ID>UnusedImports:DummyLinearStateSchemaV1.kt$import net.corda.core.contracts.ContractState</ID>
|
||||||
|
<ID>UnusedImports:FlowsExecutionModeRpcTest.kt$import net.corda.core.internal.packageName</ID>
|
||||||
|
<ID>UnusedImports:FlowsExecutionModeRpcTest.kt$import net.corda.finance.schemas.CashSchemaV1</ID>
|
||||||
|
<ID>UnusedImports:InternalTestUtils.kt$import java.nio.file.Files</ID>
|
||||||
|
<ID>UnusedImports:InternalTestUtils.kt$import net.corda.nodeapi.internal.loadDevCaTrustStore</ID>
|
||||||
|
<ID>UnusedImports:NetworkMap.kt$import net.corda.core.node.NodeInfo</ID>
|
||||||
|
<ID>UnusedImports:NodeParameters.kt$import net.corda.core.identity.Party</ID>
|
||||||
|
<ID>UnusedImports:SerializerFactory.kt$import java.io.NotSerializableException</ID>
|
||||||
|
<ID>UnusedImports:TransformTypes.kt$import net.corda.core.serialization.CordaSerializationTransformEnumDefaults</ID>
|
||||||
|
<ID>UnusedImports:VaultSchema.kt$import net.corda.core.contracts.ContractState</ID>
|
||||||
<ID>VariableNaming:AttachmentsClassLoaderSerializationTests.kt$AttachmentsClassLoaderSerializationTests$val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party</ID>
|
<ID>VariableNaming:AttachmentsClassLoaderSerializationTests.kt$AttachmentsClassLoaderSerializationTests$val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party</ID>
|
||||||
<ID>VariableNaming:AttachmentsClassLoaderSerializationTests.kt$AttachmentsClassLoaderSerializationTests$val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party</ID>
|
<ID>VariableNaming:AttachmentsClassLoaderSerializationTests.kt$AttachmentsClassLoaderSerializationTests$val MEGA_CORP = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")).party</ID>
|
||||||
<ID>VariableNaming:BootstrapperView.kt$BootstrapperView$val YAML_MAPPER = Constants.getContextMapper()</ID>
|
<ID>VariableNaming:BootstrapperView.kt$BootstrapperView$val YAML_MAPPER = Constants.getContextMapper()</ID>
|
||||||
@ -1885,8 +1873,6 @@
|
|||||||
<ID>VariableNaming:VaultQueryTests.kt$VaultQueryTestsBase$// Beware: do not use `MyContractClass::class.qualifiedName` as this returns a fully qualified name using "dot" notation for enclosed class val MYCONTRACT_ID = "net.corda.node.services.vault.VaultQueryTestsBase\$MyContractClass"</ID>
|
<ID>VariableNaming:VaultQueryTests.kt$VaultQueryTestsBase$// Beware: do not use `MyContractClass::class.qualifiedName` as this returns a fully qualified name using "dot" notation for enclosed class val MYCONTRACT_ID = "net.corda.node.services.vault.VaultQueryTestsBase\$MyContractClass"</ID>
|
||||||
<ID>VariableNaming:ZeroCouponBond.kt$ZeroCouponBond$val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")</ID>
|
<ID>VariableNaming:ZeroCouponBond.kt$ZeroCouponBond$val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")</ID>
|
||||||
<ID>WildcardImport:AMQPClient.kt$import io.netty.channel.*</ID>
|
<ID>WildcardImport:AMQPClient.kt$import io.netty.channel.*</ID>
|
||||||
<ID>WildcardImport:AMQPClientSerializationScheme.kt$import net.corda.serialization.internal.*</ID>
|
|
||||||
<ID>WildcardImport:AMQPClientSerializationScheme.kt$import net.corda.serialization.internal.amqp.*</ID>
|
|
||||||
<ID>WildcardImport:AMQPRemoteTypeModel.kt$import net.corda.serialization.internal.model.*</ID>
|
<ID>WildcardImport:AMQPRemoteTypeModel.kt$import net.corda.serialization.internal.model.*</ID>
|
||||||
<ID>WildcardImport:AMQPSerializationScheme.kt$import net.corda.core.serialization.*</ID>
|
<ID>WildcardImport:AMQPSerializationScheme.kt$import net.corda.core.serialization.*</ID>
|
||||||
<ID>WildcardImport:AMQPServerSerializationScheme.kt$import net.corda.serialization.internal.amqp.*</ID>
|
<ID>WildcardImport:AMQPServerSerializationScheme.kt$import net.corda.serialization.internal.amqp.*</ID>
|
||||||
@ -2023,9 +2009,6 @@
|
|||||||
<ID>WildcardImport:CordaModule.kt$import net.corda.core.crypto.*</ID>
|
<ID>WildcardImport:CordaModule.kt$import net.corda.core.crypto.*</ID>
|
||||||
<ID>WildcardImport:CordaModule.kt$import net.corda.core.identity.*</ID>
|
<ID>WildcardImport:CordaModule.kt$import net.corda.core.identity.*</ID>
|
||||||
<ID>WildcardImport:CordaModule.kt$import net.corda.core.transactions.*</ID>
|
<ID>WildcardImport:CordaModule.kt$import net.corda.core.transactions.*</ID>
|
||||||
<ID>WildcardImport:CordaRPCClientTest.kt$import net.corda.core.context.*</ID>
|
|
||||||
<ID>WildcardImport:CordaRPCClientTest.kt$import net.corda.core.messaging.*</ID>
|
|
||||||
<ID>WildcardImport:CordaRPCClientTest.kt$import net.corda.testing.core.*</ID>
|
|
||||||
<ID>WildcardImport:CordaRPCOps.kt$import net.corda.core.node.services.vault.*</ID>
|
<ID>WildcardImport:CordaRPCOps.kt$import net.corda.core.node.services.vault.*</ID>
|
||||||
<ID>WildcardImport:CordaRPCOpsImplTest.kt$import net.corda.core.messaging.*</ID>
|
<ID>WildcardImport:CordaRPCOpsImplTest.kt$import net.corda.core.messaging.*</ID>
|
||||||
<ID>WildcardImport:CordaRPCOpsImplTest.kt$import org.assertj.core.api.Assertions.*</ID>
|
<ID>WildcardImport:CordaRPCOpsImplTest.kt$import org.assertj.core.api.Assertions.*</ID>
|
||||||
@ -2056,8 +2039,6 @@
|
|||||||
<ID>WildcardImport:DBTransactionStorage.kt$import net.corda.core.serialization.*</ID>
|
<ID>WildcardImport:DBTransactionStorage.kt$import net.corda.core.serialization.*</ID>
|
||||||
<ID>WildcardImport:DBTransactionStorage.kt$import net.corda.nodeapi.internal.persistence.*</ID>
|
<ID>WildcardImport:DBTransactionStorage.kt$import net.corda.nodeapi.internal.persistence.*</ID>
|
||||||
<ID>WildcardImport:DBTransactionStorageTests.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:DBTransactionStorageTests.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:DefaultKryoCustomizer.kt$import de.javakaffee.kryoserializers.guava.*</ID>
|
|
||||||
<ID>WildcardImport:DefaultKryoCustomizer.kt$import net.corda.core.transactions.*</ID>
|
|
||||||
<ID>WildcardImport:DeleteForDJVM.kt$import kotlin.annotation.AnnotationTarget.*</ID>
|
<ID>WildcardImport:DeleteForDJVM.kt$import kotlin.annotation.AnnotationTarget.*</ID>
|
||||||
<ID>WildcardImport:DemoBench.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:DemoBench.kt$import tornadofx.*</ID>
|
||||||
<ID>WildcardImport:DemoBenchNodeInfoFilesCopier.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:DemoBenchNodeInfoFilesCopier.kt$import tornadofx.*</ID>
|
||||||
@ -2121,8 +2102,6 @@
|
|||||||
<ID>WildcardImport:FlowStateMachineImpl.kt$import net.corda.core.flows.*</ID>
|
<ID>WildcardImport:FlowStateMachineImpl.kt$import net.corda.core.flows.*</ID>
|
||||||
<ID>WildcardImport:FlowStateMachineImpl.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:FlowStateMachineImpl.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:FlowsDrainingModeContentionTest.kt$import net.corda.core.flows.*</ID>
|
<ID>WildcardImport:FlowsDrainingModeContentionTest.kt$import net.corda.core.flows.*</ID>
|
||||||
<ID>WildcardImport:FxTransactionBuildTutorial.kt$import net.corda.core.contracts.*</ID>
|
|
||||||
<ID>WildcardImport:FxTransactionBuildTutorial.kt$import net.corda.core.flows.*</ID>
|
|
||||||
<ID>WildcardImport:FxTransactionBuildTutorialTest.kt$import net.corda.finance.*</ID>
|
<ID>WildcardImport:FxTransactionBuildTutorialTest.kt$import net.corda.finance.*</ID>
|
||||||
<ID>WildcardImport:GenericsTests.kt$import net.corda.serialization.internal.amqp.testutils.*</ID>
|
<ID>WildcardImport:GenericsTests.kt$import net.corda.serialization.internal.amqp.testutils.*</ID>
|
||||||
<ID>WildcardImport:Gui.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:Gui.kt$import tornadofx.*</ID>
|
||||||
@ -2168,10 +2147,7 @@
|
|||||||
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.node.services.config.*</ID>
|
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.node.services.config.*</ID>
|
||||||
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.testing.node.*</ID>
|
<ID>WildcardImport:InternalMockNetwork.kt$import net.corda.testing.node.*</ID>
|
||||||
<ID>WildcardImport:InternalSerializationTestHelpers.kt$import net.corda.serialization.internal.*</ID>
|
|
||||||
<ID>WildcardImport:InternalTestUtils.kt$import net.corda.core.contracts.*</ID>
|
<ID>WildcardImport:InternalTestUtils.kt$import net.corda.core.contracts.*</ID>
|
||||||
<ID>WildcardImport:InternalUtils.kt$import java.security.cert.*</ID>
|
|
||||||
<ID>WildcardImport:InternalUtils.kt$import net.corda.core.crypto.*</ID>
|
|
||||||
<ID>WildcardImport:IssuerModel.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:IssuerModel.kt$import tornadofx.*</ID>
|
||||||
<ID>WildcardImport:JVMConfig.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:JVMConfig.kt$import tornadofx.*</ID>
|
||||||
<ID>WildcardImport:JacksonSupport.kt$import com.fasterxml.jackson.core.*</ID>
|
<ID>WildcardImport:JacksonSupport.kt$import com.fasterxml.jackson.core.*</ID>
|
||||||
@ -2194,8 +2170,6 @@
|
|||||||
<ID>WildcardImport:KotlinIntegrationTestingTutorial.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:KotlinIntegrationTestingTutorial.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:Kryo.kt$import com.esotericsoftware.kryo.*</ID>
|
<ID>WildcardImport:Kryo.kt$import com.esotericsoftware.kryo.*</ID>
|
||||||
<ID>WildcardImport:Kryo.kt$import net.corda.core.transactions.*</ID>
|
<ID>WildcardImport:Kryo.kt$import net.corda.core.transactions.*</ID>
|
||||||
<ID>WildcardImport:KryoCheckpointSerializer.kt$import net.corda.core.serialization.*</ID>
|
|
||||||
<ID>WildcardImport:KryoCheckpointSerializer.kt$import net.corda.serialization.internal.*</ID>
|
|
||||||
<ID>WildcardImport:KryoStreamsTest.kt$import java.io.*</ID>
|
<ID>WildcardImport:KryoStreamsTest.kt$import java.io.*</ID>
|
||||||
<ID>WildcardImport:KryoTests.kt$import kotlin.test.*</ID>
|
<ID>WildcardImport:KryoTests.kt$import kotlin.test.*</ID>
|
||||||
<ID>WildcardImport:KryoTests.kt$import net.corda.core.crypto.*</ID>
|
<ID>WildcardImport:KryoTests.kt$import net.corda.core.crypto.*</ID>
|
||||||
@ -2249,19 +2223,12 @@
|
|||||||
<ID>WildcardImport:NetworkBootstrapper.kt$import net.corda.nodeapi.internal.*</ID>
|
<ID>WildcardImport:NetworkBootstrapper.kt$import net.corda.nodeapi.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkBootstrapperRunnerTests.kt$import org.junit.*</ID>
|
<ID>WildcardImport:NetworkBootstrapperRunnerTests.kt$import org.junit.*</ID>
|
||||||
<ID>WildcardImport:NetworkBootstrapperTest.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:NetworkBootstrapperTest.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkBootstrapperTest.kt$import net.corda.testing.core.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkBuilder.kt$import net.corda.networkbuilder.nodes.*</ID>
|
<ID>WildcardImport:NetworkBuilder.kt$import net.corda.networkbuilder.nodes.*</ID>
|
||||||
<ID>WildcardImport:NetworkIdentityModel.kt$import net.corda.client.jfx.utils.*</ID>
|
<ID>WildcardImport:NetworkIdentityModel.kt$import net.corda.client.jfx.utils.*</ID>
|
||||||
<ID>WildcardImport:NetworkMapServer.kt$import javax.ws.rs.*</ID>
|
<ID>WildcardImport:NetworkMapServer.kt$import javax.ws.rs.*</ID>
|
||||||
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.testing.node.internal.*</ID>
|
<ID>WildcardImport:NetworkMapTest.kt$import net.corda.testing.node.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkMapUpdater.kt$import net.corda.core.internal.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkMapUpdater.kt$import net.corda.nodeapi.internal.network.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkMapUpdaterTest.kt$import com.nhaarman.mockito_kotlin.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkMapUpdaterTest.kt$import net.corda.core.internal.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkMapUpdaterTest.kt$import net.corda.testing.core.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkMapUpdaterTest.kt$import org.junit.*</ID>
|
|
||||||
<ID>WildcardImport:NetworkParametersReader.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:NetworkParametersReader.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkParametersReaderTest.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:NetworkParametersReaderTest.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:NetworkParametersReaderTest.kt$import net.corda.nodeapi.internal.network.*</ID>
|
<ID>WildcardImport:NetworkParametersReaderTest.kt$import net.corda.nodeapi.internal.network.*</ID>
|
||||||
@ -2362,7 +2329,6 @@
|
|||||||
<ID>WildcardImport:PathUtils.kt$import java.io.*</ID>
|
<ID>WildcardImport:PathUtils.kt$import java.io.*</ID>
|
||||||
<ID>WildcardImport:PathUtils.kt$import java.nio.file.*</ID>
|
<ID>WildcardImport:PathUtils.kt$import java.nio.file.*</ID>
|
||||||
<ID>WildcardImport:PersistentIdentityMigrationNewTableTest.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:PersistentIdentityMigrationNewTableTest.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:PersistentIdentityServiceTests.kt$import net.corda.testing.core.*</ID>
|
|
||||||
<ID>WildcardImport:PersistentNetworkMapCacheTest.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:PersistentNetworkMapCacheTest.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:PersistentStateServiceTests.kt$import net.corda.core.contracts.*</ID>
|
<ID>WildcardImport:PersistentStateServiceTests.kt$import net.corda.core.contracts.*</ID>
|
||||||
<ID>WildcardImport:Portfolio.kt$import net.corda.core.contracts.*</ID>
|
<ID>WildcardImport:Portfolio.kt$import net.corda.core.contracts.*</ID>
|
||||||
@ -2387,8 +2353,6 @@
|
|||||||
<ID>WildcardImport:QueryCriteriaUtils.kt$import net.corda.core.node.services.vault.LikenessOperator.*</ID>
|
<ID>WildcardImport:QueryCriteriaUtils.kt$import net.corda.core.node.services.vault.LikenessOperator.*</ID>
|
||||||
<ID>WildcardImport:RPCMultipleInterfacesTests.kt$import org.junit.Assert.*</ID>
|
<ID>WildcardImport:RPCMultipleInterfacesTests.kt$import org.junit.Assert.*</ID>
|
||||||
<ID>WildcardImport:RPCSecurityManagerImpl.kt$import org.apache.shiro.authc.*</ID>
|
<ID>WildcardImport:RPCSecurityManagerImpl.kt$import org.apache.shiro.authc.*</ID>
|
||||||
<ID>WildcardImport:RPCServer.kt$import net.corda.core.utilities.*</ID>
|
|
||||||
<ID>WildcardImport:RPCServer.kt$import org.apache.activemq.artemis.api.core.client.*</ID>
|
|
||||||
<ID>WildcardImport:ReceiveFinalityFlowTest.kt$import net.corda.node.services.statemachine.StaffedFlowHospital.*</ID>
|
<ID>WildcardImport:ReceiveFinalityFlowTest.kt$import net.corda.node.services.statemachine.StaffedFlowHospital.*</ID>
|
||||||
<ID>WildcardImport:ReceiveFinalityFlowTest.kt$import net.corda.testing.node.internal.*</ID>
|
<ID>WildcardImport:ReceiveFinalityFlowTest.kt$import net.corda.testing.node.internal.*</ID>
|
||||||
<ID>WildcardImport:ReceiveTransactionFlow.kt$import net.corda.core.contracts.*</ID>
|
<ID>WildcardImport:ReceiveTransactionFlow.kt$import net.corda.core.contracts.*</ID>
|
||||||
@ -2427,7 +2391,6 @@
|
|||||||
<ID>WildcardImport:SearchField.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:SearchField.kt$import tornadofx.*</ID>
|
||||||
<ID>WildcardImport:SecureHashTest.kt$import org.junit.Assert.*</ID>
|
<ID>WildcardImport:SecureHashTest.kt$import org.junit.Assert.*</ID>
|
||||||
<ID>WildcardImport:SendTransactionFlow.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:SendTransactionFlow.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:SerializationEnvironmentRule.kt$import net.corda.testing.internal.*</ID>
|
|
||||||
<ID>WildcardImport:SerializationHelper.kt$import java.lang.reflect.*</ID>
|
<ID>WildcardImport:SerializationHelper.kt$import java.lang.reflect.*</ID>
|
||||||
<ID>WildcardImport:SerializationHelper.kt$import net.corda.core.serialization.*</ID>
|
<ID>WildcardImport:SerializationHelper.kt$import net.corda.core.serialization.*</ID>
|
||||||
<ID>WildcardImport:SerializationOutputTests.kt$import java.time.*</ID>
|
<ID>WildcardImport:SerializationOutputTests.kt$import java.time.*</ID>
|
||||||
@ -2572,7 +2535,6 @@
|
|||||||
<ID>WildcardImport:VaultWithCashTest.kt$import net.corda.testing.core.*</ID>
|
<ID>WildcardImport:VaultWithCashTest.kt$import net.corda.testing.core.*</ID>
|
||||||
<ID>WildcardImport:VaultWithCashTest.kt$import net.corda.testing.internal.vault.*</ID>
|
<ID>WildcardImport:VaultWithCashTest.kt$import net.corda.testing.internal.vault.*</ID>
|
||||||
<ID>WildcardImport:VerifyTransactionTest.kt$import net.corda.finance.contracts.asset.Cash.Commands.*</ID>
|
<ID>WildcardImport:VerifyTransactionTest.kt$import net.corda.finance.contracts.asset.Cash.Commands.*</ID>
|
||||||
<ID>WildcardImport:VersionedParsingExampleTest.kt$import net.corda.common.configuration.parsing.internal.*</ID>
|
|
||||||
<ID>WildcardImport:WebServerController.kt$import tornadofx.*</ID>
|
<ID>WildcardImport:WebServerController.kt$import tornadofx.*</ID>
|
||||||
<ID>WildcardImport:WhitelistBasedTypeModelConfiguration.kt$import org.apache.qpid.proton.amqp.*</ID>
|
<ID>WildcardImport:WhitelistBasedTypeModelConfiguration.kt$import org.apache.qpid.proton.amqp.*</ID>
|
||||||
<ID>WildcardImport:WhitelistGenerator.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:WhitelistGenerator.kt$import net.corda.core.internal.*</ID>
|
||||||
@ -2581,8 +2543,6 @@
|
|||||||
<ID>WildcardImport:WireTransaction.kt$import net.corda.core.internal.*</ID>
|
<ID>WildcardImport:WireTransaction.kt$import net.corda.core.internal.*</ID>
|
||||||
<ID>WildcardImport:WithFinality.kt$import net.corda.core.flows.*</ID>
|
<ID>WildcardImport:WithFinality.kt$import net.corda.core.flows.*</ID>
|
||||||
<ID>WildcardImport:WithMockNet.kt$import com.natpryce.hamkrest.*</ID>
|
<ID>WildcardImport:WithMockNet.kt$import com.natpryce.hamkrest.*</ID>
|
||||||
<ID>WildcardImport:WorkflowTransactionBuildTutorial.kt$import net.corda.core.contracts.*</ID>
|
|
||||||
<ID>WildcardImport:WorkflowTransactionBuildTutorial.kt$import net.corda.core.flows.*</ID>
|
|
||||||
<ID>WildcardImport:X509CRLSerializer.kt$import net.corda.serialization.internal.amqp.*</ID>
|
<ID>WildcardImport:X509CRLSerializer.kt$import net.corda.serialization.internal.amqp.*</ID>
|
||||||
<ID>WildcardImport:X509CertificateSerializer.kt$import net.corda.serialization.internal.amqp.*</ID>
|
<ID>WildcardImport:X509CertificateSerializer.kt$import net.corda.serialization.internal.amqp.*</ID>
|
||||||
<ID>WildcardImport:X509EdDSAEngine.kt$import java.security.*</ID>
|
<ID>WildcardImport:X509EdDSAEngine.kt$import java.security.*</ID>
|
||||||
|
@ -194,3 +194,5 @@ style:
|
|||||||
active: true
|
active: true
|
||||||
excludes: "**/buildSrc/**"
|
excludes: "**/buildSrc/**"
|
||||||
excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
|
excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
|
||||||
|
UnusedImports:
|
||||||
|
active: true
|
62
docker/src/docker/Dockerfile-debug
Normal file
62
docker/src/docker/Dockerfile-debug
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
FROM azul/zulu-openjdk:8u192
|
||||||
|
|
||||||
|
## Add packages, clean cache, create dirs, create corda user and change ownership
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get -y upgrade && \
|
||||||
|
apt-get -y install bash curl unzip netstat lsof telnet netcat && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
mkdir -p /opt/corda/cordapps && \
|
||||||
|
mkdir -p /opt/corda/persistence && \
|
||||||
|
mkdir -p /opt/corda/certificates && \
|
||||||
|
mkdir -p /opt/corda/drivers && \
|
||||||
|
mkdir -p /opt/corda/logs && \
|
||||||
|
mkdir -p /opt/corda/bin && \
|
||||||
|
mkdir -p /opt/corda/additional-node-infos && \
|
||||||
|
mkdir -p /etc/corda && \
|
||||||
|
addgroup corda && \
|
||||||
|
useradd corda -g corda -m -d /opt/corda && \
|
||||||
|
chown -R corda:corda /opt/corda && \
|
||||||
|
chown -R corda:corda /etc/corda
|
||||||
|
|
||||||
|
ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \
|
||||||
|
PERSISTENCE_FOLDER="/opt/corda/persistence" \
|
||||||
|
CERTIFICATES_FOLDER="/opt/corda/certificates" \
|
||||||
|
DRIVERS_FOLDER="/opt/corda/drivers" \
|
||||||
|
CONFIG_FOLDER="/etc/corda" \
|
||||||
|
MY_P2P_PORT=10200 \
|
||||||
|
MY_RPC_PORT=10201 \
|
||||||
|
MY_RPC_ADMIN_PORT=10202 \
|
||||||
|
PATH=$PATH:/opt/corda/bin \
|
||||||
|
JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \
|
||||||
|
CORDA_ARGS=""
|
||||||
|
|
||||||
|
##CORDAPPS FOLDER
|
||||||
|
VOLUME ["/opt/corda/cordapps"]
|
||||||
|
##PERSISTENCE FOLDER
|
||||||
|
VOLUME ["/opt/corda/persistence"]
|
||||||
|
##CERTS FOLDER
|
||||||
|
VOLUME ["/opt/corda/certificates"]
|
||||||
|
##OPTIONAL JDBC DRIVERS FOLDER
|
||||||
|
VOLUME ["/opt/corda/drivers"]
|
||||||
|
##LOG FOLDER
|
||||||
|
VOLUME ["/opt/corda/logs"]
|
||||||
|
##ADDITIONAL NODE INFOS FOLDER
|
||||||
|
VOLUME ["/opt/corda/additional-node-infos"]
|
||||||
|
##CONFIG LOCATION
|
||||||
|
VOLUME ["/etc/corda"]
|
||||||
|
|
||||||
|
##CORDA JAR
|
||||||
|
COPY --chown=corda:corda corda.jar /opt/corda/bin/corda.jar
|
||||||
|
##CONFIG MANIPULATOR JAR
|
||||||
|
COPY --chown=corda:corda config-exporter.jar /opt/corda/config-exporter.jar
|
||||||
|
##CONFIG GENERATOR SHELL SCRIPT
|
||||||
|
COPY --chown=corda:corda generate-config.sh /opt/corda/bin/config-generator
|
||||||
|
##CORDA RUN SCRIPT
|
||||||
|
COPY --chown=corda:corda run-corda.sh /opt/corda/bin/run-corda
|
||||||
|
##BASE CONFIG FOR GENERATOR
|
||||||
|
COPY --chown=corda:corda starting-node.conf /opt/corda/starting-node.conf
|
||||||
|
|
||||||
|
USER "corda"
|
||||||
|
EXPOSE ${MY_P2P_PORT} ${MY_RPC_PORT} ${MY_RPC_ADMIN_PORT}
|
||||||
|
WORKDIR /opt/corda
|
||||||
|
CMD ["run-corda"]
|
66
docker/src/docker/DockerfileAL-debug
Normal file
66
docker/src/docker/DockerfileAL-debug
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
FROM amazonlinux:2
|
||||||
|
|
||||||
|
## Add packages, clean cache, create dirs, create corda user and change ownership
|
||||||
|
RUN amazon-linux-extras enable corretto8 && \
|
||||||
|
yum -y install java-1.8.0-amazon-corretto-devel && \
|
||||||
|
yum -y install bash && \
|
||||||
|
yum -y install curl && \
|
||||||
|
yum -y install unzip && \
|
||||||
|
yum -y install lsof telnet net-tools nmap-ncat && \
|
||||||
|
yum clean all && \
|
||||||
|
rm -rf /var/cache/yum && \
|
||||||
|
mkdir -p /opt/corda/cordapps && \
|
||||||
|
mkdir -p /opt/corda/persistence && \
|
||||||
|
mkdir -p /opt/corda/certificates && \
|
||||||
|
mkdir -p /opt/corda/drivers && \
|
||||||
|
mkdir -p /opt/corda/logs && \
|
||||||
|
mkdir -p /opt/corda/bin && \
|
||||||
|
mkdir -p /opt/corda/additional-node-infos && \
|
||||||
|
mkdir -p /etc/corda && \
|
||||||
|
groupadd corda && \
|
||||||
|
useradd corda -g corda -m -d /opt/corda && \
|
||||||
|
chown -R corda:corda /opt/corda && \
|
||||||
|
chown -R corda:corda /etc/corda
|
||||||
|
|
||||||
|
ENV CORDAPPS_FOLDER="/opt/corda/cordapps" \
|
||||||
|
PERSISTENCE_FOLDER="/opt/corda/persistence" \
|
||||||
|
CERTIFICATES_FOLDER="/opt/corda/certificates" \
|
||||||
|
DRIVERS_FOLDER="/opt/corda/drivers" \
|
||||||
|
CONFIG_FOLDER="/etc/corda" \
|
||||||
|
MY_P2P_PORT=10200 \
|
||||||
|
MY_RPC_PORT=10201 \
|
||||||
|
MY_RPC_ADMIN_PORT=10202 \
|
||||||
|
PATH=$PATH:/opt/corda/bin \
|
||||||
|
JVM_ARGS="-XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap " \
|
||||||
|
CORDA_ARGS=""
|
||||||
|
|
||||||
|
##CORDAPPS FOLDER
|
||||||
|
VOLUME ["/opt/corda/cordapps"]
|
||||||
|
##PERSISTENCE FOLDER
|
||||||
|
VOLUME ["/opt/corda/persistence"]
|
||||||
|
##CERTS FOLDER
|
||||||
|
VOLUME ["/opt/corda/certificates"]
|
||||||
|
##OPTIONAL JDBC DRIVERS FOLDER
|
||||||
|
VOLUME ["/opt/corda/drivers"]
|
||||||
|
##LOG FOLDER
|
||||||
|
VOLUME ["/opt/corda/logs"]
|
||||||
|
##ADDITIONAL NODE INFOS FOLDER
|
||||||
|
VOLUME ["/opt/corda/additional-node-infos"]
|
||||||
|
##CONFIG LOCATION
|
||||||
|
VOLUME ["/etc/corda"]
|
||||||
|
|
||||||
|
##CORDA JAR
|
||||||
|
COPY --chown=corda:corda corda.jar /opt/corda/bin/corda.jar
|
||||||
|
##CONFIG MANIPULATOR JAR
|
||||||
|
COPY --chown=corda:corda config-exporter.jar /opt/corda/config-exporter.jar
|
||||||
|
##CONFIG GENERATOR SHELL SCRIPT
|
||||||
|
COPY --chown=corda:corda generate-config.sh /opt/corda/bin/config-generator
|
||||||
|
##CORDA RUN SCRIPT
|
||||||
|
COPY --chown=corda:corda run-corda.sh /opt/corda/bin/run-corda
|
||||||
|
##BASE CONFIG FOR GENERATOR
|
||||||
|
COPY --chown=corda:corda starting-node.conf /opt/corda/starting-node.conf
|
||||||
|
|
||||||
|
USER "corda"
|
||||||
|
EXPOSE ${MY_P2P_PORT} ${MY_RPC_PORT} ${MY_RPC_ADMIN_PORT}
|
||||||
|
WORKDIR /opt/corda
|
||||||
|
CMD ["run-corda"]
|
@ -11,7 +11,6 @@ import net.corda.common.validation.internal.Validated
|
|||||||
import net.corda.node.services.config.NodeConfiguration
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.config.parseAsNodeConfiguration
|
import net.corda.node.services.config.parseAsNodeConfiguration
|
||||||
import net.corda.nodeapi.internal.config.toConfig
|
import net.corda.nodeapi.internal.config.toConfig
|
||||||
import net.corda.nodeapi.internal.config.toConfigValue
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ConfigExporter {
|
class ConfigExporter {
|
||||||
|
197
docs/Makefile
197
docs/Makefile
@ -1,197 +0,0 @@
|
|||||||
# Makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
|
||||||
SPHINXOPTS =
|
|
||||||
SPHINXBUILD = sphinx-build
|
|
||||||
PAPER =
|
|
||||||
BUILDDIR = build
|
|
||||||
|
|
||||||
# User-friendly check for sphinx-build
|
|
||||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
|
||||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Internal variables.
|
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
|
||||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
|
||||||
HTMLSPHINXOPTS = $(ALLSPHINXOPTS) -t htmlmode
|
|
||||||
PDFSPHINXOPTS = $(ALLSPHINXOPTS) -t pdfmode
|
|
||||||
# the i18n builder cannot share the environment and doctrees with the others
|
|
||||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
|
|
||||||
|
|
||||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
|
|
||||||
|
|
||||||
help:
|
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
|
||||||
@echo " html to make standalone HTML files"
|
|
||||||
@echo " dirhtml to make HTML files named index.html in directories"
|
|
||||||
@echo " singlehtml to make a single large HTML file"
|
|
||||||
@echo " pickle to make pickle files"
|
|
||||||
@echo " json to make JSON files"
|
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
|
||||||
@echo " qthelp to make HTML files and a qthelp project"
|
|
||||||
@echo " applehelp to make an Apple Help Book"
|
|
||||||
@echo " devhelp to make HTML files and a Devhelp project"
|
|
||||||
@echo " epub to make an epub"
|
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
|
||||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
|
||||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
|
||||||
@echo " text to make text files"
|
|
||||||
@echo " man to make manual pages"
|
|
||||||
@echo " texinfo to make Texinfo files"
|
|
||||||
@echo " info to make Texinfo files and run them through makeinfo"
|
|
||||||
@echo " gettext to make PO message catalogs"
|
|
||||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
|
||||||
@echo " xml to make Docutils-native XML files"
|
|
||||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
|
||||||
@echo " linkcheck to check all external links for integrity"
|
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
|
||||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BUILDDIR)/*
|
|
||||||
|
|
||||||
html:
|
|
||||||
$(SPHINXBUILD) -b html $(HTMLSPHINXOPTS) $(BUILDDIR)/html
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
|
||||||
|
|
||||||
dirhtml:
|
|
||||||
$(SPHINXBUILD) -b dirhtml $(HTMLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
|
||||||
|
|
||||||
singlehtml:
|
|
||||||
$(SPHINXBUILD) -b singlehtml $(HTMLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
|
||||||
|
|
||||||
pickle:
|
|
||||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the pickle files."
|
|
||||||
|
|
||||||
json:
|
|
||||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can process the JSON files."
|
|
||||||
|
|
||||||
htmlhelp:
|
|
||||||
$(SPHINXBUILD) -b htmlhelp $(HTMLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
|
||||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
|
||||||
|
|
||||||
qthelp:
|
|
||||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
|
||||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
|
||||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Playground.qhcp"
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Playground.qhc"
|
|
||||||
|
|
||||||
applehelp:
|
|
||||||
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
|
||||||
@echo "N.B. You won't be able to view it unless you put it in" \
|
|
||||||
"~/Library/Documentation/Help or install it in your application" \
|
|
||||||
"bundle."
|
|
||||||
|
|
||||||
devhelp:
|
|
||||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
|
||||||
@echo
|
|
||||||
@echo "Build finished."
|
|
||||||
@echo "To view the help file:"
|
|
||||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Playground"
|
|
||||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Playground"
|
|
||||||
@echo "# devhelp"
|
|
||||||
|
|
||||||
epub:
|
|
||||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
|
||||||
|
|
||||||
latex:
|
|
||||||
$(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo
|
|
||||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
|
||||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
|
||||||
"(use \`make latexpdf' here to do that automatically)."
|
|
||||||
|
|
||||||
latexpdf:
|
|
||||||
$(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo "Running LaTeX files through pdflatex..."
|
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
|
||||||
|
|
||||||
latexpdfja:
|
|
||||||
$(SPHINXBUILD) -b latex $(PDFSPHINXOPTS) $(BUILDDIR)/latex
|
|
||||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
|
||||||
|
|
||||||
text:
|
|
||||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
|
||||||
|
|
||||||
man:
|
|
||||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
|
||||||
|
|
||||||
texinfo:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
|
||||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
|
||||||
"(use \`make info' here to do that automatically)."
|
|
||||||
|
|
||||||
info:
|
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
|
||||||
@echo "Running Texinfo files through makeinfo..."
|
|
||||||
make -C $(BUILDDIR)/texinfo info
|
|
||||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
|
||||||
|
|
||||||
gettext:
|
|
||||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
|
||||||
|
|
||||||
changes:
|
|
||||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
|
||||||
@echo
|
|
||||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
|
||||||
|
|
||||||
linkcheck:
|
|
||||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
|
||||||
@echo
|
|
||||||
@echo "Link check complete; look for any errors in the above output " \
|
|
||||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
|
||||||
|
|
||||||
doctest:
|
|
||||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
|
||||||
@echo "Testing of doctests in the sources finished, look at the " \
|
|
||||||
"results in $(BUILDDIR)/doctest/output.txt."
|
|
||||||
|
|
||||||
coverage:
|
|
||||||
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
|
||||||
@echo "Testing of coverage in the sources finished, look at the " \
|
|
||||||
"results in $(BUILDDIR)/coverage/python.txt."
|
|
||||||
|
|
||||||
xml:
|
|
||||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
|
||||||
|
|
||||||
pseudoxml:
|
|
||||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
|
||||||
@echo
|
|
||||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
|
||||||
|
|
||||||
pdf:
|
|
||||||
$(SPHINXBUILD) -b pdf $(PDFSPHINXOPTS) $(BUILDDIR)/pdf
|
|
@ -1,41 +1,23 @@
|
|||||||
# Corda Documentation Build
|
# Docs
|
||||||
|
|
||||||
This Readme describes how to build the Corda documentation for the current version. The output html files will be written to the `corda\docs\build\html` directory.
|
## Released documentation
|
||||||
|
|
||||||
## Prerequisites / First time build
|
All released Corda documentation has now been moved to a standalone public documentation repository where the doc source can be found:
|
||||||
|
|
||||||
Before you begin, you need to:
|
[corda/corda-docs](https://github.com/corda/corda-docs)
|
||||||
1. Install Docker.
|
|
||||||
1. Ensure that Docker is running.
|
|
||||||
1. Select **Expose daemon on tcp://localhost:2375 without TLS** in the Docker Settings (which you can open from the **System Tray** by right-clicking the **Docker symbol** and then selecting **Settings**)
|
|
||||||
|
|
||||||
## Build process
|
See the [readme](https://github.com/corda/corda-docs/blob/master/README.md) and [usage docs](https://github.com/corda/corda-docs/tree/master/usage-docs) pages for instructions on how to use the new repo and build the docs locally.
|
||||||
1. Open a cmd dialogue.
|
|
||||||
1. Navigate to the root location (this is the `\corda` directory)
|
|
||||||
1. Run the documentation build (`gradlew makeDocs` or `./gradlew makeDocs`)
|
|
||||||
|
|
||||||
**Windows users:** *If this task fails because Docker can't find make-docsite.sh, go to Settings > Shared Drives in the Docker system tray
|
You can contribute to the docs source as before via fork & PR. We now use `markdown` to write/edit (instead of `rst`) and `Hugo` to build (instead of `Sphinx`).
|
||||||
agent, make sure the relevant drive is shared, and click 'Reset credentials'.*
|
|
||||||
|
|
||||||
# RST style guide
|
The published documentation is available at https://docs.corda.net.
|
||||||
|
|
||||||
The Corda documentation is described using the ReStructured Text (RST) markup language. For details of the syntax, see [this](http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html).
|
## Documentation for future releases
|
||||||
|
|
||||||
# Version placeholders
|
R3's technical writing team, R3 engineering, and other R3 teams use a separate, private docs repo for working on draft documentation content targeting future releases:
|
||||||
|
|
||||||
We currently support the following placeholders; they get substituted with the correct value at build time:
|
[corda/corda-docs-develop](https://github.com/corda/corda-docs-develop)
|
||||||
|
|
||||||
```groovy
|
These docs are published as part of each quarterly release of Corda. At that point their doc source becomes available and open for contributions in the [public docs repo](https://github.com/corda/corda-docs).
|
||||||
"|corda_version|"
|
|
||||||
"|corda_version_lower|"
|
|
||||||
"|java_version|"
|
|
||||||
"|kotlin_version|"
|
|
||||||
"|gradle_plugins_version|"
|
|
||||||
"|quasar_version|"
|
|
||||||
```
|
|
||||||
|
|
||||||
If you put one of these in an rst file anywhere (including in a code tag), it will be substituted with the value from `constants.properties`
|
The new documentation process is described in the technical writing team's space on [R3's internal confluence wiki](https://r3-cev.atlassian.net/wiki/spaces/EN/pages/1701249087/Technical+Writing).
|
||||||
(which is in the root of the project) at build time. `corda_version_lower` returns the current Corda version in lowercase which is useful
|
|
||||||
for case sensitive artifacts such as docker images.
|
|
||||||
|
|
||||||
The code for this can be found near the top of the conf.py file in the `docs/source` directory.
|
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
import org.apache.tools.ant.taskdefs.condition.Os
|
|
||||||
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
apply plugin: 'org.jetbrains.dokka'
|
|
||||||
apply plugin: 'kotlin'
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile rootProject
|
|
||||||
}
|
|
||||||
|
|
||||||
def internalPackagePrefixes(sourceDirs) {
|
|
||||||
def prefixes = []
|
|
||||||
// Kotlin allows packages to deviate from the directory structure, but let's assume they don't:
|
|
||||||
sourceDirs.collect { sourceDir ->
|
|
||||||
sourceDir.traverse(type: groovy.io.FileType.DIRECTORIES) {
|
|
||||||
if (it.name == 'internal') {
|
|
||||||
prefixes.add sourceDir.toPath().relativize(it.toPath()).toString().replace(File.separator, '.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prefixes
|
|
||||||
}
|
|
||||||
|
|
||||||
ext {
|
|
||||||
// TODO: Add '../client/jfx/src/main/kotlin' and '../client/mock/src/main/kotlin' if we decide to make them into public API
|
|
||||||
dokkaSourceDirs = files('../core/src/main/kotlin', '../client/rpc/src/main/kotlin', '../finance/workflows/src/main/kotlin', '../finance/contracts/src/main/kotlin', '../client/jackson/src/main/kotlin',
|
|
||||||
'../testing/test-utils/src/main/kotlin', '../testing/node-driver/src/main/kotlin')
|
|
||||||
internalPackagePrefixes = internalPackagePrefixes(dokkaSourceDirs)
|
|
||||||
}
|
|
||||||
|
|
||||||
dokka {
|
|
||||||
outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/kotlin")
|
|
||||||
}
|
|
||||||
|
|
||||||
task dokkaJavadoc(type: org.jetbrains.dokka.gradle.DokkaTask) {
|
|
||||||
outputFormat = "javadoc"
|
|
||||||
outputDirectory = file("${rootProject.rootDir}/docs/build/html/api/javadoc")
|
|
||||||
}
|
|
||||||
|
|
||||||
[dokka, dokkaJavadoc].collect {
|
|
||||||
it.configure {
|
|
||||||
moduleName = 'corda'
|
|
||||||
processConfigurations = ['compile']
|
|
||||||
sourceDirs = dokkaSourceDirs
|
|
||||||
includes = ['packages.md']
|
|
||||||
jdkVersion = 8
|
|
||||||
externalDocumentationLink {
|
|
||||||
url = new URL("http://fasterxml.github.io/jackson-core/javadoc/2.9/")
|
|
||||||
}
|
|
||||||
externalDocumentationLink {
|
|
||||||
url = new URL("https://docs.oracle.com/javafx/2/api/")
|
|
||||||
}
|
|
||||||
externalDocumentationLink {
|
|
||||||
url = new URL("http://www.bouncycastle.org/docs/docs1.5on/")
|
|
||||||
}
|
|
||||||
internalPackagePrefixes.collect { packagePrefix ->
|
|
||||||
packageOptions {
|
|
||||||
prefix = packagePrefix
|
|
||||||
suppress = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task buildDocs(dependsOn: ['apidocs', 'makeDocs'])
|
|
||||||
task apidocs(dependsOn: ['dokka', 'dokkaJavadoc'])
|
|
||||||
|
|
||||||
task makeDocs(type: Exec) {
|
|
||||||
// 2 volumes are mounted:
|
|
||||||
// - the docs project to /opt/docs_builder, where docs building is executed
|
|
||||||
// - the rest of the projects in /opt, so that code references to other projects are valid
|
|
||||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
|
||||||
commandLine "docker", "run", "--rm", "-v", "${project.projectDir}:/opt/docs_builder", "-v", "${project.projectDir}/..:/opt", "corda/docs-builder:latest", "bash", "-c", "make-docsite.sh"
|
|
||||||
} else {
|
|
||||||
commandLine "bash", "-c", "docker run --rm --user \$(id -u):\$(id -g) -v ${project.projectDir}:/opt/docs_builder -v ${project.projectDir}/..:/opt corda/docs-builder:latest bash -c make-docsite.sh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apidocs.shouldRunAfter makeDocs
|
|
@ -1,11 +0,0 @@
|
|||||||
FROM python:2-stretch
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get --no-install-recommends install -y texlive preview-latex-style texlive-generic-extra texlive-latex-extra latexmk dos2unix \
|
|
||||||
&& apt-get -y clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
ENV PATH="/opt/docs_builder:${PATH}"
|
|
||||||
WORKDIR /opt/docs_builder
|
|
||||||
COPY requirements.txt requirements.txt
|
|
||||||
RUN pip install -r requirements.txt
|
|
1
docs/docs_builder/lexer-fix/.gitignore
vendored
1
docs/docs_builder/lexer-fix/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
Pygments*.whl
|
|
@ -1,13 +0,0 @@
|
|||||||
FROM python:2-stretch
|
|
||||||
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get --no-install-recommends install -y texlive preview-latex-style texlive-generic-extra texlive-latex-extra latexmk dos2unix \
|
|
||||||
&& apt-get -y clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
ENV PATH="/opt/docs_builder:${PATH}"
|
|
||||||
WORKDIR /opt/docs_builder
|
|
||||||
COPY requirements.txt requirements.txt
|
|
||||||
COPY docs_builder/lexer-fix/Pygments*.whl .
|
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
RUN pip install Pygments*.whl --force-reinstall
|
|
File diff suppressed because it is too large
Load Diff
@ -1,35 +0,0 @@
|
|||||||
# Pygments lexer
|
|
||||||
|
|
||||||
We were getting a lot of warnings in the docs build, and people were unable to see the real warnings due to this. So we're on a mission
|
|
||||||
to sort all of these out.
|
|
||||||
|
|
||||||
A lot of the errors were because the kotlin lexer in Pygments (the syntax highlighter that sphinx uses) didn't cope with a lot of the
|
|
||||||
kotlin syntax that we use.
|
|
||||||
|
|
||||||
We have fixes for the kotlin lexer that we are trying to get checked into Pygments, but while this is taking place we need to maintain a
|
|
||||||
slightly hacked corda/docs-build docker image in which to build the docs.
|
|
||||||
|
|
||||||
## Some notes on building and testing
|
|
||||||
|
|
||||||
The sphinx/pygments brigade have delightfully decided that mercurial is a good idea. So broadly speaking, to build/test a fix:
|
|
||||||
|
|
||||||
* checkout pygments from [here](https://bitbucket.org/birkenfeld/pygments-main/overview)
|
|
||||||
* copy the two python files in (might be worth diffing - they're based on 2.3.1 - nb the kotlin test is entirely new)
|
|
||||||
* build pygments whl file
|
|
||||||
|
|
||||||
```
|
|
||||||
cd /path/to/pygments/
|
|
||||||
python setup.py install
|
|
||||||
pip install wheel
|
|
||||||
wheel convert dist/Pygments-2.3.1.dev20190 # obviously use your version
|
|
||||||
cp Pygments-2.3.1.dev20190401-py27-none-any.whl /path/to/corda/docs/source/docs_builder/lexer-fix
|
|
||||||
```
|
|
||||||
* build the latest docker build (see docs readme)
|
|
||||||
|
|
||||||
```
|
|
||||||
cd docs
|
|
||||||
docker build -t corda/docs-builder:latest -f docs_builder/lexer-fix/Dockerfile .
|
|
||||||
```
|
|
||||||
|
|
||||||
* push the new image up to docker hub (nb you can also test by going to /opt/docs and running `./make-docsite.sh`)
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Basic JavaLexer Test
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
:copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
|
|
||||||
:license: BSD, see LICENSE for details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
|
|
||||||
from pygments.token import Text, Name, Operator, Keyword, Number, Punctuation, String
|
|
||||||
from pygments.lexers import KotlinLexer
|
|
||||||
|
|
||||||
class KotlinTest(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.lexer = KotlinLexer()
|
|
||||||
self.maxDiff = None
|
|
||||||
|
|
||||||
def testCanCopeWithBackTickNamesInFunctions(self):
|
|
||||||
fragment = u'fun `wo bble`'
|
|
||||||
tokens = [
|
|
||||||
(Keyword, u'fun'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Function, u'`wo bble`'),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
def testCanCopeWithCommasAndDashesInBackTickNames(self):
|
|
||||||
fragment = u'fun `wo,-bble`'
|
|
||||||
tokens = [
|
|
||||||
(Keyword, u'fun'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Function, u'`wo,-bble`'),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
def testCanCopeWithDestructuring(self):
|
|
||||||
fragment = u'val (a, b) = '
|
|
||||||
tokens = [
|
|
||||||
(Keyword, u'val'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'('),
|
|
||||||
(Name.Property, u'a'),
|
|
||||||
(Punctuation, u','),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Property, u'b'),
|
|
||||||
(Punctuation, u')'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'='),
|
|
||||||
(Text, u' '),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
def testCanCopeGenericsInDestructuring(self):
|
|
||||||
fragment = u'val (a: List<Something>, b: Set<Wobble>) ='
|
|
||||||
tokens = [
|
|
||||||
(Keyword, u'val'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'('),
|
|
||||||
(Name.Property, u'a'),
|
|
||||||
(Punctuation, u':'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Property, u'List'),
|
|
||||||
(Punctuation, u'<'),
|
|
||||||
(Name, u'Something'),
|
|
||||||
(Punctuation, u'>'),
|
|
||||||
(Punctuation, u','),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Property, u'b'),
|
|
||||||
(Punctuation, u':'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Property, u'Set'),
|
|
||||||
(Punctuation, u'<'),
|
|
||||||
(Name, u'Wobble'),
|
|
||||||
(Punctuation, u'>'),
|
|
||||||
(Punctuation, u')'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'='),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
def testCanCopeWithGenerics(self):
|
|
||||||
fragment = u'inline fun <reified T : ContractState> VaultService.queryBy(): Vault.Page<T> {'
|
|
||||||
tokens = [
|
|
||||||
(Keyword, u'inline fun'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'<'),
|
|
||||||
(Keyword, u'reified'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name, u'T'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u':'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name, u'ContractState'),
|
|
||||||
(Punctuation, u'>'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name.Class, u'VaultService'),
|
|
||||||
(Punctuation, u'.'),
|
|
||||||
(Name.Function, u'queryBy'),
|
|
||||||
(Punctuation, u'('),
|
|
||||||
(Punctuation, u')'),
|
|
||||||
(Punctuation, u':'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Name, u'Vault'),
|
|
||||||
(Punctuation, u'.'),
|
|
||||||
(Name, u'Page'),
|
|
||||||
(Punctuation, u'<'),
|
|
||||||
(Name, u'T'),
|
|
||||||
(Punctuation, u'>'),
|
|
||||||
(Text, u' '),
|
|
||||||
(Punctuation, u'{'),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
def testShouldCopeWithMultilineComments(self):
|
|
||||||
fragment = u'"""\nthis\nis\na\ncomment"""'
|
|
||||||
tokens = [
|
|
||||||
(String, u'"""\nthis\nis\na\ncomment"""'),
|
|
||||||
(Text, u'\n')
|
|
||||||
]
|
|
||||||
self.assertEqual(tokens, list(self.lexer.get_tokens(fragment)))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user