From 7f6cf3266930f5699c66f1b95693976f8f1f89ff Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 16 Apr 2024 11:44:00 -0400 Subject: [PATCH 001/178] Address Joda-Time CVE-2024-23080. Signed-off-by: Ben Smith --- fabric-chaincode-shim/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 5f941259..0725ac75 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -54,8 +54,8 @@ dependencies { implementation 'org.bouncycastle:bcpkix-jdk18on:1.77' implementation 'org.bouncycastle:bcprov-jdk18on:1.77' implementation 'io.github.classgraph:classgraph:4.8.165' - implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.2' - implementation 'org.json:json:20231013' + implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' + implementation 'org.json:json:20240303' implementation 'com.google.protobuf:protobuf-java-util:3.24.4' // Required if using Java 11+ as no longer bundled in the core libraries From 72827bc6cb0c15c2bfb5584254839d364c256f56 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 30 Apr 2024 10:29:32 -0400 Subject: [PATCH 002/178] Move to Bouncy Castle v1.78. As per https://bugzilla.redhat.com/show_bug.cgi?id=2276360. Signed-off-by: Ben Smith --- fabric-chaincode-shim/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 0725ac75..d63384d0 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -51,8 +51,8 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { dependencies { implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.77' - implementation 'org.bouncycastle:bcprov-jdk18on:1.77' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.78' + implementation 'org.bouncycastle:bcprov-jdk18on:1.78' implementation 'io.github.classgraph:classgraph:4.8.165' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' implementation 'org.json:json:20240303' From bce26030576b416ca8ae2226851d4503c0849d8c Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 30 Apr 2024 17:34:49 +0100 Subject: [PATCH 003/178] Configure scheduled weekly build (#340) Signed-off-by: Mark S. Lewis --- .github/workflows/schedule.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/workflows/schedule.yml diff --git a/.github/workflows/schedule.yml b/.github/workflows/schedule.yml new file mode 100644 index 00000000..839c531d --- /dev/null +++ b/.github/workflows/schedule.yml @@ -0,0 +1,10 @@ +name: Scheduled build + +on: + schedule: + - cron: "5 4 * * 0" + workflow_dispatch: + +jobs: + main: + uses: ./.github/workflows/test.yml From 19cfb1c638dc1848db62e3660b7ccfbb9fbe173b Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 30 Apr 2024 19:28:26 +0100 Subject: [PATCH 004/178] Avoid deprecated usage of gradle actions in build (#341) For details, see: github.com/gradle/actions/blob/main/docs/deprecation-upgrade-guide.md Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 11 +++++------ .github/workflows/test.yml | 20 +++++++------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1e9b22e..6b1dd66e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,8 @@ jobs: java-version: '11' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/setup-gradle@v3 - name: Push to registry ${{ matrix.publish_target }} run: | set -xev @@ -67,12 +68,10 @@ jobs: java-version: '11' cache: 'gradle' - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/setup-gradle@v3 - name: Build the dependencies needed for the image - uses: gradle/actions/setup-gradle@v3 - with: - arguments: | - :fabric-chaincode-docker:copyAllDeps + run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1357bf02..d4901013 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,12 +24,10 @@ jobs: distribution: 'temurin' java-version: '11' - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v2 + uses: gradle/actions/wrapper-validation@v3 + - uses: gradle/actions/setup-gradle@v3 - name: Build and Unit test - uses: gradle/actions/setup-gradle@v3 - with: - arguments: | - :fabric-chaincode-shim:build + run: ./gradlew :fabric-chaincode-shim:build intergationtest: runs-on: ubuntu-latest @@ -60,11 +58,9 @@ jobs: run: | peer version weft --version + - uses: gradle/actions/setup-gradle@v3 - name: Integration Tests - uses: gradle/actions/setup-gradle@v3 - with: - arguments: | - :fabric-chaincode-integration-test:build + run: ./gradlew :fabric-chaincode-integration-test:build docker: runs-on: ubuntu-latest @@ -76,8 +72,6 @@ jobs: with: distribution: 'temurin' java-version: '11' + - uses: gradle/actions/setup-gradle@v3 - name: Build Docker image - uses: gradle/actions/setup-gradle@v3 - with: - arguments: | - :fabric-chaincode-docker:buildImage + run: ./gradlew :fabric-chaincode-docker:buildImage From c1a820fa7399eb9fbc53cd937683639feda54799 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 30 Apr 2024 19:29:22 +0100 Subject: [PATCH 005/178] Avoid deprecated usage of Docker action (#342) The `config-inline` option for docker/setup-buildx-action is replaced by `buildkitd-config-inline`. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6b1dd66e..7eed4b6d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: uses: docker/setup-buildx-action@v3 with: buildkitd-flags: --debug - config-inline: | + buildkitd-config-inline: | [worker.oci] max-parallelism = 1 - name: Login to the ${{ matrix.DOCKER_REGISTRY }} Container Registry @@ -96,7 +96,7 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} - - name: Build and push ${{ matrix.COMPONENT }} Image + - name: Build and push image id: push uses: docker/build-push-action@v5 with: From 3f3443c21b8de23ac4b3e41fb8d833f37337825e Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 10 May 2024 12:30:09 +0100 Subject: [PATCH 006/178] Update Docker base image version (#343) Use latest eclipse-termurin:11-jdk image to minimise exposure to security vulnerabilities in the base image. Also: - Change permissions for Gradle publishing workflow to allow publish to GitHub Packages. - Update Bouncy Castle dependency to latest patch release (1.78 to 1.78.1). Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 3 +++ build.gradle | 2 +- .../fabric-contract-example-as-service/build.gradle | 2 +- .../build.gradle.kts | 2 +- .../fabric-contract-example-gradle/build.gradle | 2 +- examples/fabric-contract-example-maven/pom.xml | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-docker/Dockerfile | 13 ++++++------- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 4 ++-- 11 files changed, 19 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7eed4b6d..605c7706 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,6 +25,9 @@ jobs: - publishAllPublicationsToReleaseRepository runs-on: ubuntu-latest needs: test + permissions: + contents: read + packages: write steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 diff --git a/build.gradle b/build.gradle index 4381733c..6aa40d9f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' -version = '2.5.1' +version = '2.5.2' // If the nightly property is set, then this is the scheduled main diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 3f93ce2c..386124a0 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -22,7 +22,7 @@ repositories { } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' compile 'org.json:json:20231013' testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' testImplementation 'org.assertj:assertj-core:3.11.1' diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 2d3baf0f..91173cb6 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -19,7 +19,7 @@ java { dependencies { - implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1") + implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2") implementation("org.json:json:20231013") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index b4747742..07d3dca3 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -22,7 +22,7 @@ repositories { } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' compile 'org.json:json:20231013' testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' testImplementation 'org.assertj:assertj-core:3.11.1' diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 34e4dbde..96473bce 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.1 + 2.5.2 1.3.14 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index b4747742..07d3dca3 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -22,7 +22,7 @@ repositories { } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' compile 'org.json:json:20231013' testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' testImplementation 'org.assertj:assertj-core:3.11.1' diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 515a37ca..878dbba6 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:11.0.22_7-jdk as builder +FROM eclipse-temurin:11-jdk as builder ENV DEBIAN_FRONTEND=noninteractive # Build tools @@ -13,7 +13,7 @@ SHELL ["/bin/bash", "-c"] RUN source /root/.sdkman/bin/sdkman-init.sh; sdk install gradle 8.6 RUN source /root/.sdkman/bin/sdkman-init.sh; sdk install maven 3.9.6 -FROM eclipse-temurin:11.0.22_7-jdk as dependencies +FROM eclipse-temurin:11-jdk as dependencies COPY --from=builder /root/.sdkman/candidates/gradle/current /usr/bin/gradle COPY --from=builder /root/.sdkman/candidates/maven/current /usr/bin/maven @@ -53,12 +53,14 @@ RUN mvn -N io.takari:maven:wrapper # Creating final javaenv image which will include all required # dependencies to build and compile java chaincode -FROM eclipse-temurin:11.0.22_7-jdk +FROM eclipse-temurin:11-jdk RUN apt-get update \ && apt-get -y install zip unzip \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /chaincode/input \ + && mkdir -p /chaincode/output SHELL ["/bin/bash", "-c"] @@ -66,7 +68,4 @@ SHELL ["/bin/bash", "-c"] COPY --from=dependencies /root/chaincode-java /root/chaincode-java COPY --from=dependencies /root/.m2 /root/.m2 -RUN mkdir -p /chaincode/input -RUN mkdir -p /chaincode/output - WORKDIR /root/chaincode-java diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index a2caaf35..ce4f1aab 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -66,6 +66,6 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.1', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.2', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index d1c4d753..63ff0906 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index d63384d0..77bbadbc 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -51,8 +51,8 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { dependencies { implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.78' - implementation 'org.bouncycastle:bcprov-jdk18on:1.78' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.78.1' + implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' implementation 'io.github.classgraph:classgraph:4.8.165' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' implementation 'org.json:json:20240303' From d384208200ea115b456aa4746e4a6fe9c69aeca1 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 10 May 2024 13:35:12 +0100 Subject: [PATCH 007/178] Back-level ledger API integration test dependency (#344) Signed-off-by: Mark S. Lewis --- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 63ff0906..d1c4d753 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } From 6615ebb69a8c5b4e26bce3dea1fef3bd1098dca8 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 23 May 2024 18:41:58 +0100 Subject: [PATCH 008/178] Restore Java 8 compatibility (#349) Build with source and target bytecode compatibility for Java 8. This allows chaincode implementation code that requires Java 8 compatibility to compile against the fabric-chaincode-shim package. Avoid use of mavenLocal() and (deprecated) jcenter() Gradle repositories. Signed-off-by: Mark S. Lewis --- .github/workflows/test.yml | 12 ++++++------ README.md | 2 +- build.gradle | 12 +++++++----- .../fabric-contract-example-as-service/build.gradle | 1 - .../build.gradle.kts | 7 ------- .../fabric-contract-example-gradle/build.gradle | 1 - examples/fabric-contract-example-maven/pom.xml | 2 +- examples/ledger-api/build.gradle | 1 - fabric-chaincode-docker/Dockerfile | 2 +- fabric-chaincode-docker/build.gradle | 4 +--- .../src/contracts/bare-gradle/build.gradle | 7 +++---- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 13 +++++++++---- .../src/contracts/fabric-shim-api/build.gradle | 12 +++++++++--- .../src/contracts/wrapper-maven/pom.xml | 2 +- 15 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d4901013..3e057986 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,8 +21,8 @@ jobs: ref: ${{ inputs.checkout-ref }} - uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '11' + distribution: temurin + java-version: 11 - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@v3 - uses: gradle/actions/setup-gradle@v3 @@ -37,8 +37,8 @@ jobs: ref: ${{ inputs.checkout-ref }} - uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '11' + distribution: temurin + java-version: 11 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -70,8 +70,8 @@ jobs: ref: ${{ inputs.checkout-ref }} - uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '11' + distribution: temurin + java-version: 11 - uses: gradle/actions/setup-gradle@v3 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage diff --git a/README.md b/README.md index 49de9d4b..f6efe4fc 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Make sure you have the following prereqs installed: - [Docker](https://www.docker.com/get-docker) - [Docker Compose](https://docs.docker.com/compose/install/) -- [JDK 8](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) +- [JDK 11](https://adoptium.net/) > **Note:** Java can be installed using [sdkman](https://sdkman.io/). diff --git a/build.gradle b/build.gradle index 6aa40d9f..d2139c1c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ apply plugin: 'idea' apply plugin: 'eclipse-wtp' -version = '2.5.2' +version = '2.5.3' // If the nightly property is set, then this is the scheduled main @@ -23,8 +23,6 @@ if (properties.containsKey('NIGHTLY')) { allprojects { repositories { mavenCentral() - mavenLocal() - jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } } @@ -38,8 +36,12 @@ subprojects { version = rootProject.version java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) + sourceCompatibility = JavaVersion.VERSION_1_8 + } + + compileJava { + if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { + options.release = 8 } } diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 386124a0..d3c01667 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -10,7 +10,6 @@ tasks.compileJava { } repositories { - mavenLocal() mavenCentral() maven { url "https://www.jitpack.io" diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 91173cb6..637587d7 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -13,11 +13,6 @@ plugins { version = "0.0.1" -java { - sourceCompatibility = JavaVersion.VERSION_1_8 -} - - dependencies { implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2") implementation("org.json:json:20231013") @@ -28,9 +23,7 @@ dependencies { } repositories { - mavenLocal() mavenCentral() - jcenter() maven { setUrl("https://jitpack.io") } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 07d3dca3..30b67398 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -10,7 +10,6 @@ tasks.compileJava { } repositories { - mavenLocal() mavenCentral() maven { url "https://www.jitpack.io" diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 96473bce..ae33ca51 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.2 + 2.5.3 1.3.14 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 07d3dca3..30b67398 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -10,7 +10,6 @@ tasks.compileJava { } repositories { - mavenLocal() mavenCentral() maven { url "https://www.jitpack.io" diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 878dbba6..144af895 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -64,7 +64,7 @@ RUN apt-get update \ SHELL ["/bin/bash", "-c"] -# Copy setup scripts, and the cached dependeices +# Copy setup scripts, and the cached dependencies COPY --from=dependencies /root/chaincode-java /root/chaincode-java COPY --from=dependencies /root/.m2 /root/.m2 diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index ce4f1aab..ec5c9c1f 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -6,8 +6,6 @@ buildscript { repositories { - mavenLocal() - jcenter() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } mavenCentral() @@ -66,6 +64,6 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.2', 'hyperledger/fabric-javaenv:amd64-latest'] + tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.3', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 2533859f..2998abc5 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -6,12 +6,11 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' -tasks.compileJava { - sourceCompatibility = '1.8' +java { + sourceCompatibility = JavaVersion.VERSION_1_8 } repositories { - mavenLocal() mavenCentral() maven { url = "https://www.jitpack.io" } maven { @@ -20,7 +19,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index a3a6bebe..d97ce159 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.1 + 2.5.3 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index d1c4d753..b8d92bef 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -6,12 +6,17 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' -tasks.compileJava { - options.release.set(8) +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +compileJava { + if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { + options.release = 8 + } } repositories { - mavenLocal() mavenCentral() maven { url = "https://www.jitpack.io" } maven { @@ -20,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index f4881548..a6643274 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -6,8 +6,14 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' -tasks.compileJava { - options.release.set(8) +java { + sourceCompatibility = JavaVersion.VERSION_1_8 +} + +compileJava { + if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { + options.release = 8 + } } repositories { @@ -19,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.1' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' implementation 'commons-logging:commons-logging:1.2' implementation 'com.google.code.gson:gson:2.10.1' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 50082839..6c5f33a4 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.1 + 2.5.3 From 7ad134231f9bc4dc4b42f041498573eaa47f8dc4 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 28 Jun 2024 15:30:02 +0100 Subject: [PATCH 009/178] Update maintainer email address (#350) Signed-off-by: Mark S. Lewis --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index b0c0797f..afe22827 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,7 +6,7 @@ Maintainers |---------------------------|------------------|-----------------|---------------------------| | Artem Barger | c0rwin | c0rwin | bartem@il.ibm.com | | Matthew B White | mbwhite | mbwhite | whitemat@uk.ibm.com | -| Mark Lewis | bestbeforetoday | bestbeforetoday | mark_lewis@uk.ibm.com | +| Mark Lewis | bestbeforetoday | bestbeforetoday | Mark.S.Lewis@outlook.com | Retired Maintainers =================== From a6453383ad7fa4ec001a10a86b8dae44d6b3023c Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 1 Jul 2024 04:36:40 +0100 Subject: [PATCH 010/178] Use Gradle lockfile instead of CycloneDX SBOM for scan (#351) A CycloneDX SBOM was generated to allow OSV-Scanner to scan all transitive dependencies. A similar result can be achieved using Gradle lockfiles, removing the need to use CycloneDX. Signed-off-by: Mark S. Lewis --- .gitignore | 1 + Makefile | 4 ++-- fabric-chaincode-shim/build.gradle | 24 ++++++++++++++---------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index f96c2308..1e849943 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ repository .gradle /build/ out/ +gradle.lockfile !gradle/wrapper/gradle-wrapper.jar ### STS ### diff --git a/Makefile b/Makefile index 22285adc..f8f60fbf 100644 --- a/Makefile +++ b/Makefile @@ -5,5 +5,5 @@ .PHONEY: scan scan: go install github.com/google/osv-scanner/cmd/osv-scanner@latest - ./gradlew cyclonedxBom - osv-scanner --sbom='fabric-chaincode-shim/build/reports/bom.json' + ./gradlew --quiet resolveAndLockAll --write-locks + osv-scanner scan --lockfile=fabric-chaincode-shim/gradle.lockfile diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 77bbadbc..ea14aabc 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -33,16 +33,20 @@ checkstyleTest { source ='src/test/java' } -cyclonedxBom { - includeConfigs = ["runtimeClasspath"] - skipConfigs = ["compileClasspath", "testCompileClasspath"] - projectType = "library" - schemaVersion = "1.5" - destination = file("build/reports") - outputName = "bom" - outputFormat = "json" - includeBomSerialNumber = false - includeLicenseText = false +configurations { + runtimeClasspath { + resolutionStrategy.activateDependencyLocking() + } +} + +tasks.register('resolveAndLockAll') { + notCompatibleWithConfigurationCache("Filters configurations at execution time") + doFirst { + assert gradle.startParameter.writeDependencyLocks : "$path must be run from the command line with the `--write-locks` flag" + } + doLast { + configurations.findAll { it.canBeResolved }.each { it.resolve() } + } } tasks.withType(org.gradle.api.tasks.testing.Test) { From 086f6b502b83ebbe7c5e6c215a6089b8a1229ce1 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 23 Sep 2024 13:45:55 +0100 Subject: [PATCH 011/178] Update dependencies to address CVE-2024-7254 (#353) Also the following dependency changes: - Remove obsolete JUnit 4. - Replace com.github.stefanbirkner:system-rules with uk.org.webcompere:system-stubs-jupiter since the former appears not to work correctly with JUnit 5. - Update versions following v2.5.3 release. Signed-off-by: Mark S. Lewis --- build.gradle | 30 +-- .../build.gradle | 8 +- .../build.gradle.kts | 4 +- .../build.gradle | 8 +- examples/ledger-api/build.gradle | 8 +- fabric-chaincode-docker/build.gradle | 5 +- .../build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../contracts/fabric-ledger-api/build.gradle | 2 +- .../contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- .../contractinstall/ContractInstallTest.java | 9 +- .../ledgertests/LedgerIntegrationTest.java | 8 +- .../shimtests/SACCIntegrationTest.java | 8 +- .../shimtests/SBECCIntegrationTest.java | 8 +- fabric-chaincode-shim/build.gradle | 32 +-- .../java/ChaincodeWithoutPackageTest.java | 30 +-- .../org/hyperledger/fabric/LoggerTest.java | 7 +- .../org/hyperledger/fabric/LoggingTest.java | 33 ++- .../fabric/contract/ClientIdentityTest.java | 26 +- .../fabric/contract/ContextFactoryTest.java | 12 +- .../fabric/contract/ContextTest.java | 8 +- .../contract/ContractInterfaceTest.java | 22 +- .../fabric/contract/ContractRouterTest.java | 43 ++-- .../contract/TransactionExceptionTest.java | 13 +- .../ContractExecutionServiceTest.java | 24 +- .../JSONTransactionSerializerTest.java | 9 +- .../metadata/MetadataBuilderTest.java | 28 +-- .../contract/metadata/TypeSchemaTest.java | 8 +- .../routing/ContractDefinitionTest.java | 35 +-- .../routing/DataTypeDefinitionTest.java | 24 +- .../routing/ParameterDefinitionTest.java | 20 +- .../routing/PropertyDefinitionTest.java | 20 +- .../contract/routing/TxFunctionTest.java | 31 +-- .../contract/routing/TypeRegistryTest.java | 20 +- ...ePath.java => ContractSimplePathTest.java} | 45 ++-- .../fabric/shim/ChaincodeBaseTest.java | 234 +++++++++--------- .../fabric/shim/ChaincodeServerImplTest.java | 25 +- .../fabric/shim/ChaincodeTest.java | 49 ++-- .../shim/ChatChaincodeWithPeerTest.java | 25 +- .../fabric/shim/NettyGrpcServerTest.java | 25 +- .../ext/sbe/StateBasedEndorsementTest.java | 18 +- .../StateBasedEndorsementFactoryTest.java | 19 +- .../impl/StateBasedEndorsementImplTest.java | 20 +- .../fabric/shim/fvt/ChaincodeFVTest.java | 62 ++--- .../shim/impl/ChaincodeSupportClientTest.java | 28 ++- .../shim/impl/InnvocationTaskManagerTest.java | 23 +- .../shim/impl/InvocationTaskManagerTest.java | 29 +-- .../shim/impl/KeyModificationImplTest.java | 27 +- .../fabric/shim/impl/KeyValueImplTest.java | 19 +- ...ryResultsIteratorWithMetadataImplTest.java | 6 +- .../fabric/shim/ledger/CompositeKeyTest.java | 48 ++-- .../impl/OpenTelemetryPropertiesTest.java | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 55 files changed, 567 insertions(+), 692 deletions(-) rename fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/{ContractSimplePath.java => ContractSimplePathTest.java} (77%) diff --git a/build.gradle b/build.gradle index d2139c1c..762de3e1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,9 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -apply plugin: 'idea' -apply plugin: 'eclipse-wtp' -version = '2.5.3' +plugins { + id "com.github.ben-manes.versions" version "0.51.0" +} + +version = '2.5.4' // If the nightly property is set, then this is the scheduled main @@ -46,18 +48,16 @@ subprojects { } dependencies { - implementation 'commons-cli:commons-cli:1.6.0' - implementation 'commons-logging:commons-logging:1.2' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' - - testImplementation 'org.hamcrest:hamcrest-library:1.3' - testImplementation 'org.mockito:mockito-core:2.23.0' - testImplementation 'com.github.stefanbirkner:system-rules:system-rules-1.17.0' - - testCompileOnly 'junit:junit:4.13.2' - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.10.2' - testImplementation 'org.assertj:assertj-core:3.9.1' + implementation 'commons-cli:commons-cli:1.9.0' + implementation 'commons-logging:commons-logging:1.3.4' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0' + + testImplementation 'org.hamcrest:hamcrest-library:3.0' + testImplementation 'org.mockito:mockito-core:5.13.0' + testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.6' + + testImplementation 'org.assertj:assertj-core:3.26.3' } test { diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index d3c01667..b787d94b 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -22,10 +22,10 @@ repositories { dependencies { compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20231013' - testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' - testImplementation 'org.assertj:assertj-core:3.11.1' - testImplementation 'org.mockito:mockito-core:2.+' + compile 'org.json:json:20240303' + testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' + testImplementation 'org.assertj:assertj-core:3.26.3' + testImplementation 'org.mockito:mockito-core:5.13.0' } shadowJar { diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 637587d7..5cf57def 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -15,10 +15,10 @@ version = "0.0.1" dependencies { implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2") - implementation("org.json:json:20231013") + implementation("org.json:json:20240303") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.junit.jupiter:junit-jupiter:5.4.2") + testImplementation("org.junit.jupiter:junit-jupiter:5.11.0") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0") } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 30b67398..ceb2a9a2 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -22,10 +22,10 @@ repositories { dependencies { compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20231013' - testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' - testImplementation 'org.assertj:assertj-core:3.11.1' - testImplementation 'org.mockito:mockito-core:2.+' + compile 'org.json:json:20240303' + testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' + testImplementation 'org.assertj:assertj-core:3.26.3' + testImplementation 'org.mockito:mockito-core:5.13.0' } shadowJar { diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 30b67398..ceb2a9a2 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -22,10 +22,10 @@ repositories { dependencies { compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20231013' - testImplementation 'org.junit.jupiter:junit-jupiter:5.4.2' - testImplementation 'org.assertj:assertj-core:3.11.1' - testImplementation 'org.mockito:mockito-core:2.+' + compile 'org.json:json:20240303' + testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' + testImplementation 'org.assertj:assertj-core:3.26.3' + testImplementation 'org.mockito:mockito-core:5.13.0' } shadowJar { diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index ec5c9c1f..acba4678 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -9,9 +9,10 @@ buildscript { maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } mavenCentral() + gradlePluginPortal() } dependencies { - classpath 'com.bmuschko:gradle-docker-plugin:5.1.0' + classpath 'com.bmuschko:gradle-docker-plugin:9.4.0' } } @@ -64,6 +65,6 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - tags = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.3', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.4', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 9dec7aa0..08d1524e 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { implementation project(':fabric-chaincode-docker') implementation project(':fabric-chaincode-shim') - implementation 'org.json:json:20231013' + implementation 'org.json:json:20240303' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 2998abc5..a3a4016a 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index d97ce159..72a0feec 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.3 + 2.5.4 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index b8d92bef..84b7f857 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index a6643274..b78f4018 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.3' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' implementation 'commons-logging:commons-logging:1.2' implementation 'com.google.code.gson:gson:2.10.1' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 6c5f33a4..7484f7c1 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.3 + 2.5.4 diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java index d8a0c310..881ac8cd 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java @@ -4,13 +4,14 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.contractinstall; + import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic Java Chaincode Test @@ -18,7 +19,7 @@ */ public class ContractInstallTest { - @BeforeClass + @BeforeAll public static void setUp() throws Exception { FabricState.getState().start(); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java index 6b9ed002..20a1825e 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java @@ -5,12 +5,12 @@ */ package org.hyperleder.fabric.shim.integration.ledgertests; import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic Java Chaincode Test @@ -18,7 +18,7 @@ */ public class LedgerIntegrationTest { - @BeforeClass + @BeforeAll public static void setUp() throws Exception { diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java index f9cae0c3..50b27c45 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java @@ -5,12 +5,12 @@ */ package org.hyperleder.fabric.shim.integration.shimtests; import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; /** * Basic Java Chaincode Test @@ -18,7 +18,7 @@ */ public class SACCIntegrationTest { - @BeforeClass + @BeforeAll public static void setUp() throws Exception { FabricState.getState().start(); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java index d93c3faf..418cdbf7 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java @@ -7,16 +7,16 @@ import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; public class SBECCIntegrationTest { - @BeforeClass + @BeforeAll public static void setUp() throws Exception { FabricState.getState().start(); diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index ea14aabc..ded8f870 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -3,25 +3,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ - buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'org.owasp:dependency-check-gradle:8.4.0' - } -} plugins { id 'maven-publish' id 'jacoco' id 'signing' id 'checkstyle' - id 'org.cyclonedx.bom' version '1.8.1' } checkstyle { - toolVersion '10.12.5' + toolVersion '10.18.1' configFile file("../ci/checkstyle/checkstyle.xml") configProperties = [root_dir: file("..") ] } @@ -54,34 +45,33 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { } dependencies { + implementation platform('com.google.protobuf:protobuf-bom:3.25.5') + implementation platform('io.grpc:grpc-bom:1.68.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.42.1') + implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' implementation 'org.bouncycastle:bcpkix-jdk18on:1.78.1' implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' - implementation 'io.github.classgraph:classgraph:4.8.165' + implementation 'io.github.classgraph:classgraph:4.8.176' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' implementation 'org.json:json:20240303' - implementation 'com.google.protobuf:protobuf-java-util:3.24.4' + implementation 'com.google.protobuf:protobuf-java-util' - // Required if using Java 11+ as no longer bundled in the core libraries - testImplementation 'javax.xml.bind:jaxb-api:2.3.1' - - implementation platform('io.grpc:grpc-bom:1.60.0') implementation 'io.grpc:grpc-netty-shaded' implementation 'io.grpc:grpc-protobuf' implementation 'io.grpc:grpc-stub' - testImplementation 'io.grpc:grpc-inprocess' - - implementation platform("io.opentelemetry:opentelemetry-bom:1.32.0") + // Required if using Java 11+ as no longer bundled in the core libraries + testImplementation 'javax.xml.bind:jaxb-api:2.3.1' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'io.opentelemetry.proto:opentelemetry-proto:1.0.0-alpha' + implementation 'io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:1.32.0-alpha' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.8.0-alpha' } sourceSets { diff --git a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java index c9f711a1..f62b044c 100644 --- a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java +++ b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java @@ -4,31 +4,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -import static org.hamcrest.Matchers.is; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; -import static org.junit.Assert.assertThat; +import org.hyperledger.fabric.shim.ChaincodeBase; +import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; +import org.hyperledger.fabric.shim.mock.peer.RegisterStep; +import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import org.hyperledger.fabric.shim.ChaincodeBase; -import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer; -import org.hyperledger.fabric.shim.mock.peer.RegisterStep; -import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; public final class ChaincodeWithoutPackageTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); - private ChaincodeMockPeer server; - @After + @AfterEach public void afterTest() throws Exception { if (server != null) { server.stop(); @@ -49,8 +43,8 @@ public void testRegisterChaincodeWithoutPackage() throws Exception { ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageSend().getType(), is(READY)); - assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); + assertThat(server.getLastMessageSend().getType()).isEqualTo(READY); + assertThat(server.getLastMessageRcvd().getType()).isEqualTo(REGISTER); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java index 3d500c8d..cd99c74c 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java @@ -7,14 +7,9 @@ package org.hyperledger.fabric; import org.hyperledger.fabric.contract.ContractRuntimeException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; public class LoggerTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void logger() { Logger.getLogger(LoggerTest.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java index c0c7d3f1..6c69de43 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java @@ -5,35 +5,30 @@ */ package org.hyperledger.fabric; -import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.logging.Level; -import org.hamcrest.CoreMatchers; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; public final class LoggingTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testMapLevel() { - assertEquals("Error maps", Level.SEVERE, proxyMapLevel("ERROR")); - assertEquals("Critical maps", Level.SEVERE, proxyMapLevel("critical")); - assertEquals("Warn maps", Level.WARNING, proxyMapLevel("WARNING")); - assertEquals("Info maps", Level.INFO, proxyMapLevel("INFO")); - assertEquals("Config maps", Level.CONFIG, proxyMapLevel(" notice")); - assertEquals("Info maps", Level.INFO, proxyMapLevel(" info")); - assertEquals("Debug maps", Level.FINEST, proxyMapLevel("debug ")); - assertEquals("Info maps", Level.INFO, proxyMapLevel("wibble ")); - assertEquals("Info maps", Level.INFO, proxyMapLevel(new Object[] {null})); + assertEquals(Level.SEVERE, proxyMapLevel("ERROR"), "Error maps"); + assertEquals(Level.SEVERE, proxyMapLevel("critical"), "Critical maps"); + assertEquals(Level.WARNING, proxyMapLevel("WARNING"), "Warn maps"); + assertEquals(Level.INFO, proxyMapLevel("INFO"), "Info maps"); + assertEquals(Level.CONFIG, proxyMapLevel(" notice"), "Config maps"); + assertEquals(Level.INFO, proxyMapLevel(" info"), "Info maps"); + assertEquals(Level.FINEST, proxyMapLevel("debug "), "Debug maps"); + assertEquals(Level.INFO, proxyMapLevel("wibble "), "Info maps"); + assertEquals(Level.INFO, proxyMapLevel(new Object[] {null}), "Info maps"); } public Object proxyMapLevel(final Object... args) { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java index 7c0297c1..f9dae17a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java @@ -6,22 +6,18 @@ package org.hyperledger.fabric.contract; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.hyperledger.fabric.TestUtil; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.jupiter.api.Test; import java.math.BigInteger; -import org.hyperledger.fabric.TestUtil; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ClientIdentityTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - /** * Test client identity can be created using certificate without attributes */ @@ -104,12 +100,12 @@ public void clientIdentityWithLongDNs() throws Exception { */ @Test public void catchInvalidProtocolBufferException() { - thrown.expect(ContractRuntimeException.class); - thrown.expectMessage("Could not create new client identity"); - final ChaincodeStub stub = mock(ChaincodeStub.class); when(stub.getCreator()).thenReturn("somethingInvalid".getBytes()); - ContextFactory.getInstance().createContext(stub); + + assertThatThrownBy(() -> ContextFactory.getInstance().createContext(stub)) + .isInstanceOf(ContractRuntimeException.class) + .hasMessage("Could not create new client identity"); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java index a013a536..a10ef5de 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java @@ -5,15 +5,15 @@ */ package org.hyperledger.fabric.contract; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.sameInstance; -import static org.junit.Assert.assertThat; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.junit.jupiter.api.Test; import java.util.Collections; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.junit.Test; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; public class ContextFactoryTest { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java index ff2dddd3..2d3bf088 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java @@ -5,11 +5,11 @@ */ package org.hyperledger.fabric.contract; -import static org.hamcrest.Matchers.sameInstance; -import static org.junit.Assert.assertThat; - import org.hyperledger.fabric.shim.ChaincodeStub; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.Matchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; public class ContextTest { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java index 3e3879c6..a3b468fe 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java @@ -5,19 +5,15 @@ */ package org.hyperledger.fabric.contract; +import org.hyperledger.fabric.shim.ChaincodeException; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import org.hyperledger.fabric.shim.ChaincodeException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.hamcrest.MatcherAssert.assertThat; public class ContractInterfaceTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void createContext() { assertThat((new ContractInterface() { @@ -26,12 +22,12 @@ public void createContext() { @Test public void unknownTransaction() { - thrown.expect(ChaincodeException.class); - thrown.expectMessage("Undefined contract method called"); - final ContractInterface c = new ContractInterface() { }; - c.unknownTransaction(c.createContext(new ChaincodeStubNaiveImpl())); + + assertThatThrownBy(() -> c.unknownTransaction(c.createContext(new ChaincodeStubNaiveImpl()))) + .isInstanceOf(ChaincodeException.class) + .hasMessage("Undefined contract method called"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java index 4c4d9c87..987922f5 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java @@ -5,19 +5,7 @@ */ package org.hyperledger.fabric.contract; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; - +import contract.SampleContract; import org.hyperledger.fabric.contract.annotation.Contract; import org.hyperledger.fabric.contract.execution.ExecutionFactory; import org.hyperledger.fabric.contract.execution.InvocationRequest; @@ -26,23 +14,28 @@ import org.hyperledger.fabric.shim.ChaincodeServerProperties; import org.hyperledger.fabric.shim.ChaincodeStub; import org.hyperledger.fabric.shim.NettyChaincodeServer; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -import contract.SampleContract; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; -public class ContractRouterTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +public class ContractRouterTest { @Test public void testCreateFailsWithoutValidOptions() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(containsString( - "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable.")); - - @SuppressWarnings("unused") final ContractRouter r = new ContractRouter(new String[]{}); + assertThatThrownBy(() -> new ContractRouter(new String[]{})) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("The chaincode id must be specified using either the -i or --i command " + + "line options or the CORE_CHAINCODE_ID_NAME environment variable."); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java index b16adcf3..edd4e799 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java @@ -5,14 +5,12 @@ */ package org.hyperledger.fabric.contract; +import org.hyperledger.fabric.shim.ChaincodeException; +import org.junit.jupiter.api.Test; + import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - -import org.hyperledger.fabric.shim.ChaincodeException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.hamcrest.MatcherAssert.assertThat; public class TransactionExceptionTest { @@ -34,9 +32,6 @@ public byte[] getPayload() { } } - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testNoArgConstructor() { final ChaincodeException e = new ChaincodeException(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java index 97ceb5fc..cbf1f2ce 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java @@ -18,11 +18,8 @@ import org.hyperledger.fabric.contract.routing.TxFunction; import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl; import org.hyperledger.fabric.contract.routing.impl.SerializerRegistryImpl; -import org.hyperledger.fabric.shim.Chaincode.Response; import org.hyperledger.fabric.shim.ChaincodeStub; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -30,19 +27,14 @@ import java.util.ArrayList; import java.util.Collections; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -public class ContractExecutionServiceTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @SuppressWarnings({ "serial" }) +public final class ContractExecutionServiceTest { @Test public void noReturnValue() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException { @@ -68,7 +60,6 @@ public void noReturnValue() } - @SuppressWarnings({ "serial" }) @Test() public void failureToInvoke() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException { @@ -92,14 +83,11 @@ public void failureToInvoke() when(routing.toString()).thenReturn("MockMethodName:MockClassName"); when(serializerRegistry.getSerializer(any(), any())).thenReturn(jts); - thrown.expect(ContractRuntimeException.class); - thrown.expectMessage("Could not execute contract method: MockMethodName:MockClassName"); - - Response resp = ces.executeRequest(txFn, req, stub); - assertThat(resp.getStatusCode(), equalTo(500)); + assertThatThrownBy(() -> ces.executeRequest(txFn, req, stub)) + .isInstanceOf(ContractRuntimeException.class) + .hasMessage("Could not execute contract method: MockMethodName:MockClassName"); } - @SuppressWarnings({ "serial" }) @Test() public void invokeWithDifferentSerializers() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java index ba4bb55b..169ad41f 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java @@ -7,8 +7,8 @@ package org.hyperledger.fabric.contract.execution; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.charset.StandardCharsets; @@ -18,16 +18,11 @@ import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.TypeRegistry; import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; -import org.junit.Rule; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.rules.ExpectedException; public class JSONTransactionSerializerTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void toBuffer() { final TypeRegistry tr = TypeRegistry.getRegistry(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java index 7b44ca5d..8204b343 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java @@ -5,11 +5,7 @@ */ package org.hyperledger.fabric.contract.metadata; -import java.io.InputStream; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.util.HashMap; - +import contract.SampleContract; import org.everit.json.schema.loader.SchemaClient; import org.everit.json.schema.loader.internal.DefaultSchemaClient; import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl; @@ -18,18 +14,16 @@ import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; import org.hyperledger.fabric.contract.systemcontract.SystemContract; import org.hyperledger.fabric.shim.ChaincodeStub; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import contract.SampleContract; - -public class MetadataBuilderTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.io.InputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.HashMap; +public final class MetadataBuilderTest { private final String expectedMetadataString = " {\n" + " \"components\": {\"schemas\": {}},\n" + " \"$schema\": \"https://fabric-shim.github.io/contract-schema.json\",\n" + " \"contracts\": {\"SampleContract\": {\n" + " \"name\": \"SampleContract\",\n" + " \"transactions\": [],\n" + " \"info\": {\n" @@ -51,8 +45,8 @@ private void setMetadataBuilderField(final String name, final Object value) { } } - @Before - @After + @BeforeEach + @AfterEach public void beforeAndAfterEach() { setMetadataBuilderField("componentMap", new HashMap()); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java index 77dbb8de..d06e6d6d 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java @@ -6,7 +6,7 @@ package org.hyperledger.fabric.contract.metadata; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import org.hyperledger.fabric.contract.annotation.DataType; @@ -15,12 +15,12 @@ import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class TypeSchemaTest { - @Before + @BeforeEach public void beforeEach() { } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java index ee7b84a8..0a564013 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java @@ -5,34 +5,24 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertThat; - -import java.lang.reflect.Method; -import java.security.Permission; - +import contract.SampleContract; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.annotation.Contract; import org.hyperledger.fabric.contract.annotation.Info; import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import contract.SampleContract; +import org.junit.jupiter.api.Test; -public class ContractDefinitionTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.lang.reflect.Method; +import java.security.Permission; - @Before - public void beforeEach() { - } +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.startsWith; +public class ContractDefinitionTest { @Test public void constructor() throws NoSuchMethodException, SecurityException { @@ -92,10 +82,9 @@ public void duplicateTransaction() throws NoSuchMethodException, SecurityExcepti final ContractInterface contract = new SampleContract(); final Method m = contract.getClass().getMethod("t2", new Class[] {Context.class}); - thrown.expect(ContractRuntimeException.class); - thrown.expectMessage("Duplicate transaction method t2"); - - cf.addTxFunction(m); cf.addTxFunction(m); + assertThatThrownBy(() -> cf.addTxFunction(m)) + .isInstanceOf(ContractRuntimeException.class) + .hasMessage("Duplicate transaction method t2"); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java index b2589ea3..015357ec 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java @@ -5,28 +5,18 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasKey; -import static org.junit.Assert.assertThat; - -import java.util.Map; - import org.hyperledger.fabric.contract.MyType2; import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -public class DataTypeDefinitionTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.util.Map; - @Before - public void beforeEach() { - } +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +public class DataTypeDefinitionTest { @Test public void constructor() { final DataTypeDefinitionImpl dtd = new DataTypeDefinitionImpl(MyType2.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java index dd5cdd75..823dd06f 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java @@ -5,26 +5,16 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - -import java.lang.reflect.Parameter; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -public class ParameterDefinitionTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.lang.reflect.Parameter; - @Before - public void beforeEach() { - } +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +public class ParameterDefinitionTest { @Test public void constructor() throws NoSuchMethodException, SecurityException { final Parameter[] params = String.class.getMethod("concat", String.class).getParameters(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java index 115d517b..28cd785e 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java @@ -5,26 +5,16 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - -import java.lang.reflect.Field; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.impl.PropertyDefinitionImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -public class PropertyDefinitionTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.lang.reflect.Field; - @Before - public void beforeEach() { - } +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +public class PropertyDefinitionTest { @Test public void constructor() throws NoSuchMethodException, SecurityException { final Field[] props = String.class.getFields(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java index b2749ea1..1096ceac 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java @@ -5,13 +5,6 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; @@ -20,16 +13,18 @@ import org.hyperledger.fabric.contract.annotation.Transaction; import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.impl.TxFunctionImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class TxFunctionTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +public class TxFunctionTest { @Contract() class TestObject implements ContractInterface { @@ -49,10 +44,6 @@ public void wibble(final String arg1) { } } - @Before - public void beforeEach() { - } - @Test public void constructor() throws NoSuchMethodException, SecurityException { final TestObject test = new TestObject(); @@ -93,9 +84,9 @@ public void invaldtxfn() throws NoSuchMethodException, SecurityException { final TestObject test = new TestObject(); final ContractDefinition cd = mock(ContractDefinition.class); Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class)); - thrown.expect(ContractRuntimeException.class); - new TxFunctionImpl(test.getClass().getMethod("wibble", String.class), cd); + assertThatThrownBy(() -> new TxFunctionImpl(test.getClass().getMethod("wibble", String.class), cd)) + .isInstanceOf(ContractRuntimeException.class); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java index 553c66f6..0fc5f419 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java @@ -5,26 +5,16 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; - -import java.util.Collection; - import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -public class TypeRegistryTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import java.util.Collection; - @Before - public void beforeEach() { - } +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +public class TypeRegistryTest { @Test public void addDataType() { final TypeRegistryImpl tr = new TypeRegistryImpl(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java similarity index 77% rename from fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java rename to fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java index 6868429c..2286435d 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePath.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java @@ -5,16 +5,7 @@ */ package org.hyperledger.fabric.contract.simplepath; -import static org.hamcrest.Matchers.is; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION; -import static org.junit.Assert.assertThat; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - +import com.google.protobuf.ByteString; import org.hyperledger.fabric.contract.ContractRouter; import org.hyperledger.fabric.protos.peer.ChaincodeInput; import org.hyperledger.fabric.protos.peer.ChaincodeInput.Builder; @@ -24,24 +15,30 @@ import org.hyperledger.fabric.shim.mock.peer.RegisterStep; import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; import org.hyperledger.fabric.shim.utils.MessageUtil; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; -import com.google.protobuf.ByteString; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; -public final class ContractSimplePath { - @Rule - public ExpectedException thrown = ExpectedException.none(); +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION; - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); +@ExtendWith(SystemStubsExtension.class) +public final class ContractSimplePathTest { + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); private ChaincodeMockPeer server; - @After + @AfterEach public void afterTest() throws Exception { if (server != null) { server.stop(); @@ -65,8 +62,8 @@ public void testContract() throws Exception { ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS); - assertThat(server.getLastMessageSend().getType(), is(READY)); - assertThat(server.getLastMessageRcvd().getType(), is(REGISTER)); + assertThat(server.getLastMessageSend().getType()).isEqualTo(READY); + assertThat(server.getLastMessageRcvd().getType()).isEqualTo(REGISTER); setLogLevel("INFO"); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java index 8dd90234..6fd7ef03 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java @@ -6,137 +6,128 @@ package org.hyperledger.fabric.shim; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.logging.Handler; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - +import io.grpc.ManagedChannelBuilder; import io.grpc.stub.StreamObserver; -import org.hamcrest.Matchers; import org.hyperledger.fabric.metrics.Metrics; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.traces.Traces; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.jupiter.api.Assertions; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; -import io.grpc.ManagedChannelBuilder; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Properties; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; -public class ChaincodeBaseTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; - @Rule - public ExpectedException thrown = ExpectedException.none(); +@ExtendWith(SystemStubsExtension.class) +public class ChaincodeBaseTest { + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @Test public void testNewSuccessResponseEmpty() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); - assertNull("Response message in not null", response.getMessage()); - assertNull("Response payload in not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + assertThat(response.getMessage()).as("Response message").isNull(); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testNewSuccessResponseWithMessage() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message"); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); - assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertNull("Response payload in not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message"); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testNewSuccessResponseWithPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); - assertNull("Response message in not null", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + assertThat(response.getMessage()).as("Response message").isNull(); + assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewSuccessResponseWithMessageAndPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); - assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS); + assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message"); + assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseEmpty() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertNull("Response message in not null", response.getMessage()); - assertNull("Response payload in not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isNull(); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testNewErrorResponseWithMessage() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message"); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertNull("Response payload in not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message"); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testNewErrorResponseWithPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertNull("Response message in not null", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isNull(); + assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseWithMessageAndPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertEquals("Response message in not correct", "Simple message", response.getMessage()); - assertArrayEquals("Response payload in not null", response.getPayload(), "Simple payload".getBytes(Charset.defaultCharset())); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message"); + assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset())); } @Test public void testNewErrorResponseWithException() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new Exception("Simple exception")); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertEquals("Response message is not correct", "Unexpected error", response.getMessage()); - assertNull("Response payload is not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isEqualTo("Unexpected error"); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testNewErrorResponseWithChaincodeException() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new ChaincodeException("Chaincode exception")); - assertEquals("Response status is incorrect", response.getStatus(), org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); - assertEquals("Response message is not correct", "Chaincode exception", response.getMessage()); - assertNull("Response payload is not null", response.getPayload()); + assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR); + assertThat(response.getMessage()).as("Response message").isEqualTo("Chaincode exception"); + assertThat(response.getPayload()).as("Response payload").isNull(); } @Test public void testOptions() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); - assertEquals("Host incorrect", ChaincodeBase.DEFAULT_HOST, cb.getHost()); - assertEquals("Port incorrect", ChaincodeBase.DEFAULT_PORT, cb.getPort()); - assertFalse("TLS should not be enabled", cb.isTlsEnabled()); + assertThat(cb.getHost()).as("Host incorrect").isEqualTo(ChaincodeBase.DEFAULT_HOST); + assertThat(cb.getPort()).as("Port incorrect").isEqualTo(ChaincodeBase.DEFAULT_PORT); + assertThat(cb.isTlsEnabled()).as("TLS should not be enabled").isFalse(); environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); environmentVariables.set("CORE_PEER_ADDRESS", "localhost:7052"); @@ -145,47 +136,39 @@ public void testOptions() throws Exception { environmentVariables.set("CORE_TLS_CLIENT_KEY_PATH", "non_exist_path2"); environmentVariables.set("CORE_PEER_TLS_ROOTCERT_FILE", "non_exist_path1"); cb.processEnvironmentOptions(); - assertEquals("CCId incorrect", cb.getId(), "mycc"); - assertEquals("Host incorrect", cb.getHost(), "localhost"); - assertEquals("Port incorrect", cb.getPort(), 7052); - assertTrue("TLS should be enabled", cb.isTlsEnabled()); - assertEquals("Root certificate file", "non_exist_path1", cb.getTlsClientRootCertPath()); - assertEquals("Client key file", "non_exist_path2", cb.getTlsClientKeyPath()); - assertEquals("Client certificate file", "non_exist_path3", cb.getTlsClientCertPath()); + assertThat(cb.getId()).as("CCId incorrect").isEqualTo("mycc"); + assertThat(cb.getHost()).as("Host incorrect").isEqualTo("localhost"); + assertThat(cb.getPort()).as("Port incorrect").isEqualTo(7052); + assertThat(cb.isTlsEnabled()).as("TLS should be enabled").isTrue(); + assertThat(cb.getTlsClientRootCertPath()).as("Root certificate file").isEqualTo("non_exist_path1"); + assertThat(cb.getTlsClientKeyPath()).as("Client key file").isEqualTo("non_exist_path2"); + assertThat(cb.getTlsClientCertPath()).as("Client certificate file").isEqualTo("non_exist_path3"); environmentVariables.set("CORE_PEER_ADDRESS", "localhost1"); cb.processEnvironmentOptions(); - assertEquals("Host incorrect", cb.getHost(), "localhost"); - assertEquals("Port incorrect", cb.getPort(), 7052); + assertThat(cb.getHost()).as("Host incorrect").isEqualTo("localhost"); + assertThat(cb.getPort()).as("Port incorrect").isEqualTo(7052); - try { - cb.validateOptions(); - } catch (final IllegalArgumentException e) { - fail("Wrong arguments"); - } + assertThatCode(cb::validateOptions).as("Wrong arguments").doesNotThrowAnyException(); cb.processCommandLineOptions(new String[] {"-i", "mycc1", "--peerAddress", "localhost.org:7053"}); - assertEquals("CCId incorrect", cb.getId(), "mycc1"); - assertEquals("Host incorrect", cb.getHost(), "localhost.org"); - assertEquals("Port incorrect", cb.getPort(), 7053); + assertThat(cb.getId()).as("CCId incorrect").isEqualTo("mycc1"); + assertThat(cb.getHost()).as("Host incorrect").isEqualTo("localhost.org"); + assertThat(cb.getPort()).as("Port incorrect").isEqualTo(7053); - try { - cb.validateOptions(); - } catch (final IllegalArgumentException e) { - fail("Wrong arguments"); - } + assertThatCode(cb::validateOptions).as("Wrong arguments").doesNotThrowAnyException(); cb.processCommandLineOptions(new String[] {"-i", "mycc1", "--peerAddress", "localhost1.org.7054"}); - assertEquals("Host incorrect", cb.getHost(), "localhost.org"); - assertEquals("Port incorrect", cb.getPort(), 7053); + assertThat(cb.getHost()).as("Host incorrect").isEqualTo("localhost.org"); + assertThat(cb.getPort()).as("Port incorrect").isEqualTo(7053); } @Test public void testUnsetOptionId() { final ChaincodeBase cb = new EmptyChaincode(); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(Matchers.containsString("The chaincode id must be specified")); - cb.validateOptions(); + assertThatThrownBy(cb::validateOptions) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("The chaincode id must be specified"); } @Test @@ -194,9 +177,9 @@ public void testUnsetOptionClientCertPath() { environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); environmentVariables.set("CORE_PEER_TLS_ENABLED", "true"); cb.processEnvironmentOptions(); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(Matchers.containsString("Client key certificate chain")); - cb.validateOptions(); + assertThatThrownBy(cb::validateOptions) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Client key certificate chain"); } @Test @@ -206,13 +189,13 @@ public void testUnsetOptionClientKeyPath() { environmentVariables.set("CORE_PEER_TLS_ENABLED", "true"); environmentVariables.set("CORE_TLS_CLIENT_CERT_PATH", "non_exist_path3"); cb.processEnvironmentOptions(); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(Matchers.containsString("Client key (")); - cb.validateOptions(); + assertThatThrownBy(cb::validateOptions) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Client key ("); } @Test - @Ignore + @Disabled public void testNewChannelBuilder() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); @@ -225,7 +208,7 @@ public void testNewChannelBuilder() throws Exception { cb.processEnvironmentOptions(); cb.validateOptions(); - assertTrue("Not correct builder", cb.newChannelBuilder() instanceof ManagedChannelBuilder); + assertThat(cb.newChannelBuilder()).isInstanceOf(ManagedChannelBuilder.class); } @Test @@ -234,29 +217,44 @@ public void testInitializeLogging() { cb.processEnvironmentOptions(); cb.initializeLogging(); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.INFO, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertThat(Logger.getLogger("org.hyperledger.fabric.shim").getLevel()) + .as("Wrong log level for org.hyperledger.fabric.shim") + .isEqualTo(Level.INFO); + assertThat(Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()) + .as("Wrong log level for " + cb.getClass().getPackage().getName()) + .isEqualTo(Level.INFO); setLogLevelForChaincode(environmentVariables, cb, "WRONG", "WRONG"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.INFO, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertThat(Logger.getLogger("org.hyperledger.fabric.shim").getLevel()) + .as("Wrong log level for org.hyperledger.fabric.shim") + .isEqualTo(Level.INFO); + assertThat(Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()) + .as("Wrong log level for " + cb.getClass().getPackage().getName()) + .isEqualTo(Level.INFO); setLogLevelForChaincode(environmentVariables, cb, "DEBUG", "NOTICE"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.FINEST, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.CONFIG, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertThat(Logger.getLogger("org.hyperledger.fabric.shim").getLevel()) + .as("Wrong log level for org.hyperledger.fabric.shim") + .isEqualTo(Level.FINEST); + assertThat(Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()) + .as("Wrong log level for " + cb.getClass().getPackage().getName()) + .isEqualTo(Level.CONFIG); setLogLevelForChaincode(environmentVariables, cb, "INFO", "WARNING"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.INFO, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.WARNING, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertThat(Logger.getLogger("org.hyperledger.fabric.shim").getLevel()) + .as("Wrong log level for org.hyperledger.fabric.shim") + .isEqualTo(Level.INFO); + assertThat(Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()) + .as("Wrong log level for " + cb.getClass().getPackage().getName()) + .isEqualTo(Level.WARNING); setLogLevelForChaincode(environmentVariables, cb, "CRITICAL", "ERROR"); - assertEquals("Wrong log level for org.hyperledger.fabric.shim ", Level.SEVERE, Logger.getLogger("org.hyperledger.fabric.shim").getLevel()); - assertEquals("Wrong log level for " + cb.getClass().getPackage().getName(), Level.SEVERE, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); + assertThat(Logger.getLogger("org.hyperledger.fabric.shim").getLevel()) + .as("Wrong log level for org.hyperledger.fabric.shim") + .isEqualTo(Level.SEVERE); + assertThat(Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()) + .as("Wrong log level for " + cb.getClass().getPackage().getName()) + .isEqualTo(Level.SEVERE); } @Test @@ -274,9 +272,9 @@ public void testStartFailsWithoutValidOptions() { LogRecord lr = argumentCaptor.getValue(); String msg = lr.getMessage(); - assertThat(msg, not(containsString("java.lang.NullPointerException"))); - assertThat(msg, containsString( - "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable.")); + assertThat(msg).doesNotContain("java.lang.NullPointerException"); + assertThat(msg).contains( + "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable."); } public static void setLogLevelForChaincode(final EnvironmentVariables environmentVariables, final ChaincodeBase cb, final String shimLevel, @@ -319,7 +317,9 @@ public void onCompleted() { } }); - environmentVariables.clear("CORE_CHAINCODE_ID_NAME", "CORE_PEER_ADDRESS", "CORE_PEER_TLS_ENABLED"); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); + environmentVariables.remove("CORE_PEER_ADDRESS"); + environmentVariables.remove("CORE_PEER_TLS_ENABLED"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java index 913b6bef..8b52bbfd 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java @@ -7,18 +7,21 @@ import org.hyperledger.fabric.contract.ContractRouter; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; -import org.junit.Rule; -import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.io.IOException; import java.net.URISyntaxException; +@ExtendWith(SystemStubsExtension.class) class ChaincodeServerImplTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeEach void setEnv() { @@ -33,13 +36,13 @@ void setEnv() { @AfterEach void clearEnv() { - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); - environmentVariables.clear("CORE_PEER_ADDRESS"); - environmentVariables.clear("CORE_PEER_TLS_ENABLED"); - environmentVariables.clear("CORE_PEER_TLS_ROOTCERT_FILE"); - environmentVariables.clear("CORE_TLS_CLIENT_KEY_PATH"); - environmentVariables.clear("CORE_TLS_CLIENT_CERT_PATH"); - environmentVariables.clear("CHAINCODE_SERVER_ADDRESS"); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); + environmentVariables.remove("CORE_PEER_ADDRESS"); + environmentVariables.remove("CORE_PEER_TLS_ENABLED"); + environmentVariables.remove("CORE_PEER_TLS_ROOTCERT_FILE"); + environmentVariables.remove("CORE_TLS_CLIENT_KEY_PATH"); + environmentVariables.remove("CORE_TLS_CLIENT_CERT_PATH"); + environmentVariables.remove("CHAINCODE_SERVER_ADDRESS"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java index b974601a..800ec670 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java @@ -5,54 +5,49 @@ */ package org.hyperledger.fabric.shim; -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ChaincodeTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testResponse() { final Chaincode.Response resp = new Chaincode.Response(Chaincode.Response.Status.SUCCESS, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); - assertEquals("Incorrect status", Chaincode.Response.Status.SUCCESS, resp.getStatus()); - assertEquals("Incorrect message", "No message", resp.getMessage()); - assertEquals("Incorrect payload", "no payload", resp.getStringPayload()); + assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus()); + assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage()); + assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload()); } @Test public void testResponseWithCode() { Chaincode.Response resp = new Chaincode.Response(200, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); - assertEquals("Incorrect status", Chaincode.Response.Status.SUCCESS, resp.getStatus()); - assertEquals("Incorrect status", 200, resp.getStatusCode()); - assertEquals("Incorrect message", "No message", resp.getMessage()); - assertEquals("Incorrect payload", "no payload", resp.getStringPayload()); + assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus()); + assertThat(200).as("Incorrect status").isEqualTo(resp.getStatusCode()); + assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage()); + assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload()); resp = new Chaincode.Response(404, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); - assertEquals("Incorrect status", 404, resp.getStatusCode()); - assertEquals("Incorrect message", "No message", resp.getMessage()); - assertEquals("Incorrect payload", "no payload", resp.getStringPayload()); + assertThat(404).as("Incorrect status").isEqualTo(resp.getStatusCode()); + assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage()); + assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload()); resp = new Chaincode.Response(Chaincode.Response.Status.ERROR_THRESHOLD, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); - assertEquals("Incorrect status", Chaincode.Response.Status.ERROR_THRESHOLD, resp.getStatus()); - assertEquals("Incorrect status", 400, resp.getStatusCode()); - assertEquals("Incorrect message", "No message", resp.getMessage()); - assertEquals("Incorrect payload", "no payload", resp.getStringPayload()); + assertThat(Chaincode.Response.Status.ERROR_THRESHOLD).as("Incorrect status").isEqualTo(resp.getStatus()); + assertThat(400).as("Incorrect status").isEqualTo(resp.getStatusCode()); + assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage()); + assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload()); } @Test public void testStatus() { - assertEquals("Wrong status", Chaincode.Response.Status.SUCCESS, Chaincode.Response.Status.forCode(200)); - assertEquals("Wrong status", Chaincode.Response.Status.ERROR_THRESHOLD, Chaincode.Response.Status.forCode(400)); - assertEquals("Wrong status", Chaincode.Response.Status.INTERNAL_SERVER_ERROR, Chaincode.Response.Status.forCode(500)); + assertThat(Chaincode.Response.Status.SUCCESS).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(200)); + assertThat(Chaincode.Response.Status.ERROR_THRESHOLD).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(400)); + assertThat(Chaincode.Response.Status.INTERNAL_SERVER_ERROR).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(500)); - thrown.expect(IllegalArgumentException.class); - Chaincode.Response.Status.forCode(501); + assertThatThrownBy(() -> Chaincode.Response.Status.forCode(501)) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java index b78d8d07..5e7108f3 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java @@ -8,19 +8,21 @@ import com.google.protobuf.ByteString; import io.grpc.stub.StreamObserver; import org.hyperledger.fabric.metrics.Metrics; -import org.hyperledger.fabric.protos.peer.ChaincodeSpec; import org.hyperledger.fabric.protos.peer.ChaincodeID; import org.hyperledger.fabric.protos.peer.ChaincodeInput; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeSpec; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.shim.utils.MessageUtil; import org.hyperledger.fabric.traces.Traces; -import org.junit.Rule; -import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.io.IOException; import java.util.List; @@ -40,10 +42,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@ExtendWith(SystemStubsExtension.class) class ChatChaincodeWithPeerTest { private static final String TEST_CHANNEL = "testChannel"; - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeEach void setEnv() { @@ -57,12 +60,12 @@ void setEnv() { @AfterEach void clearEnv() { - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); - environmentVariables.clear("CORE_PEER_ADDRESS"); - environmentVariables.clear("CORE_PEER_TLS_ENABLED"); - environmentVariables.clear("CORE_PEER_TLS_ROOTCERT_FILE"); - environmentVariables.clear("CORE_TLS_CLIENT_KEY_PATH"); - environmentVariables.clear("CORE_TLS_CLIENT_CERT_PATH"); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); + environmentVariables.remove("CORE_PEER_ADDRESS"); + environmentVariables.remove("CORE_PEER_TLS_ENABLED"); + environmentVariables.remove("CORE_PEER_TLS_ROOTCERT_FILE"); + environmentVariables.remove("CORE_TLS_CLIENT_KEY_PATH"); + environmentVariables.remove("CORE_TLS_CLIENT_CERT_PATH"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java index 7bc9a9f2..c14163e7 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java @@ -8,20 +8,23 @@ import org.hyperledger.fabric.metrics.Metrics; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.traces.Traces; -import org.junit.Rule; -import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.io.IOException; import java.net.URISyntaxException; import java.util.Properties; +@ExtendWith(SystemStubsExtension.class) class NettyGrpcServerTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeEach void setEnv() { @@ -36,13 +39,13 @@ void setEnv() { @AfterEach void clearEnv() { - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); - environmentVariables.clear("CORE_PEER_ADDRESS"); - environmentVariables.clear("CORE_PEER_TLS_ENABLED"); - environmentVariables.clear("CORE_PEER_TLS_ROOTCERT_FILE"); - environmentVariables.clear("CORE_TLS_CLIENT_KEY_PATH"); - environmentVariables.clear("CORE_TLS_CLIENT_CERT_PATH"); - environmentVariables.clear("CHAINCODE_SERVER_ADDRESS"); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); + environmentVariables.remove("CORE_PEER_ADDRESS"); + environmentVariables.remove("CORE_PEER_TLS_ENABLED"); + environmentVariables.remove("CORE_PEER_TLS_ROOTCERT_FILE"); + environmentVariables.remove("CORE_TLS_CLIENT_KEY_PATH"); + environmentVariables.remove("CORE_TLS_CLIENT_CERT_PATH"); + environmentVariables.remove("CHAINCODE_SERVER_ADDRESS"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java index 23364682..d1d23adb 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java @@ -5,23 +5,19 @@ */ package org.hyperledger.fabric.shim.ext.sbe; -import static org.junit.Assert.assertEquals; +import org.junit.jupiter.api.Test; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class StateBasedEndorsementTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void testRoleType() { - assertEquals("Wrong role", StateBasedEndorsement.RoleType.RoleTypeMember, StateBasedEndorsement.RoleType.forVal("MEMBER")); - assertEquals("Wrong role", StateBasedEndorsement.RoleType.RoleTypePeer, StateBasedEndorsement.RoleType.forVal("PEER")); + assertThat(StateBasedEndorsement.RoleType.forVal("MEMBER")).isEqualTo(StateBasedEndorsement.RoleType.RoleTypeMember); + assertThat(StateBasedEndorsement.RoleType.forVal("PEER")).isEqualTo(StateBasedEndorsement.RoleType.RoleTypePeer); - thrown.expect(IllegalArgumentException.class); - StateBasedEndorsement.RoleType.forVal("NONEXIST"); + assertThatThrownBy(() -> StateBasedEndorsement.RoleType.forVal("NONEXIST")) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java index c3e41802..08896e60 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java @@ -5,27 +5,24 @@ */ package org.hyperledger.fabric.shim.ext.sbe.impl; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import org.junit.jupiter.api.Test; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; -public class StateBasedEndorsementFactoryTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); +public class StateBasedEndorsementFactoryTest { @Test public void getInstance() { assertNotNull(StateBasedEndorsementFactory.getInstance()); - assertTrue(StateBasedEndorsementFactory.getInstance() instanceof StateBasedEndorsementFactory); + assertInstanceOf(StateBasedEndorsementFactory.class, StateBasedEndorsementFactory.getInstance()); } @Test public void newStateBasedEndorsement() { assertNotNull(StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(new byte[] {})); - thrown.expect(IllegalArgumentException.class); - StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(new byte[] {0}); + assertThatThrownBy(() -> StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(new byte[] {0})) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java index ba8b16ef..332fa347 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java @@ -5,21 +5,21 @@ */ package org.hyperledger.fabric.shim.ext.sbe.impl; +import org.hyperledger.fabric.protos.common.MSPRole.MSPRoleType; +import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; +import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement.RoleType; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.util.List; - -import org.hyperledger.fabric.protos.common.MSPRole.MSPRoleType; -import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; -import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement.RoleType; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class StateBasedEndorsementImplTest { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java index 4c26b5f5..0ebd3c6b 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java @@ -5,27 +5,7 @@ */ package org.hyperledger.fabric.shim.fvt; -import static org.hamcrest.Matchers.is; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.COMPLETED; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.RESPONSE; -import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - import com.google.protobuf.ByteString; - import org.hyperledger.fabric.protos.peer.ChaincodeInput; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.Response; @@ -55,19 +35,41 @@ import org.hyperledger.fabric.shim.mock.peer.RegisterStep; import org.hyperledger.fabric.shim.mock.peer.ScenarioStep; import org.hyperledger.fabric.shim.utils.MessageUtil; -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.COMPLETED; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.RESPONSE; +import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +@ExtendWith(SystemStubsExtension.class) public final class ChaincodeFVTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); private ChaincodeMockPeer server; - @After + @AfterEach public void afterTest() throws Exception { if (server != null) { server.stop(); @@ -624,9 +626,9 @@ public void testChaincodeLogLevel() throws Exception { cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" }); - assertEquals("Wrong debug level for " + cb.getClass().getPackage().getName(), Level.FINEST, - Logger.getLogger(cb.getClass().getPackage().getName()).getLevel()); - + assertEquals(Level.FINEST, + Logger.getLogger(cb.getClass().getPackage().getName()).getLevel(), + "Wrong debug level for " + cb.getClass().getPackage().getName()); } public void setLogLevel(final String logLevel) { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java index a8fac963..c3cf24d8 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java @@ -13,17 +13,21 @@ import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.traces.Traces; -import org.junit.Rule; -import org.junit.contrib.java.lang.system.EnvironmentVariables; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.io.IOException; import java.util.Properties; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@ExtendWith(SystemStubsExtension.class) class ChaincodeSupportClientTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @Test void testStartInvocationTaskManagerAndRequestObserverNull() throws IOException { @@ -39,8 +43,7 @@ void testStartInvocationTaskManagerAndRequestObserverNull() throws IOException { final ManagedChannelBuilder managedChannelBuilder = chaincodeBase.newChannelBuilder(); ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(managedChannelBuilder); - Assertions.assertThrows( - IOException.class, + assertThatThrownBy( () -> { final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build(); final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId); @@ -49,8 +52,8 @@ void testStartInvocationTaskManagerAndRequestObserverNull() throws IOException { chaincodeSupportClient.start(itm, requestObserver); }, "StreamObserver 'requestObserver' for chat with peer can't be null" - ); - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); + ).isInstanceOf(IOException.class); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); } @Test @@ -67,8 +70,7 @@ void testStartInvocationTaskManagerNullAndRequestObserver() throws IOException { final ManagedChannelBuilder managedChannelBuilder = chaincodeBase.newChannelBuilder(); ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(managedChannelBuilder); - Assertions.assertThrows( - IOException.class, + assertThatThrownBy( () -> { chaincodeSupportClient.start(null, new StreamObserver() { @Override @@ -88,7 +90,7 @@ public void onCompleted() { }); }, "InvocationTaskManager 'itm' can't be null" - ); - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); + ).isInstanceOf(IOException.class); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java index 11efee79..6ef01199 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java @@ -13,12 +13,14 @@ import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.chaincode.EmptyChaincode; import org.hyperledger.fabric.traces.Traces; -import org.junit.Rule; -import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; +import uk.org.webcompere.systemstubs.jupiter.SystemStub; +import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; import java.io.IOException; import java.util.Properties; @@ -26,9 +28,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +@ExtendWith(SystemStubsExtension.class) class InnvocationTaskManagerTest { - @Rule - public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + @SystemStub + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeEach void setEnv() { @@ -42,12 +45,12 @@ void setEnv() { @AfterEach void clearEnv() { - environmentVariables.clear("CORE_CHAINCODE_ID_NAME"); - environmentVariables.clear("CORE_PEER_ADDRESS"); - environmentVariables.clear("CORE_PEER_TLS_ENABLED"); - environmentVariables.clear("CORE_PEER_TLS_ROOTCERT_FILE"); - environmentVariables.clear("CORE_TLS_CLIENT_KEY_PATH"); - environmentVariables.clear("CORE_TLS_CLIENT_CERT_PATH"); + environmentVariables.remove("CORE_CHAINCODE_ID_NAME"); + environmentVariables.remove("CORE_PEER_ADDRESS"); + environmentVariables.remove("CORE_PEER_TLS_ENABLED"); + environmentVariables.remove("CORE_PEER_TLS_ROOTCERT_FILE"); + environmentVariables.remove("CORE_TLS_CLIENT_KEY_PATH"); + environmentVariables.remove("CORE_TLS_CLIENT_CERT_PATH"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java index ef13ddd3..ae4ee29a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java @@ -5,14 +5,7 @@ */ package org.hyperledger.fabric.shim.impl; -import static org.mockito.Mockito.when; - -import java.io.UnsupportedEncodingException; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.Logger; - +import com.google.protobuf.ByteString; import org.hyperledger.fabric.metrics.Metrics; import org.hyperledger.fabric.protos.peer.ChaincodeID; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; @@ -23,7 +16,13 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import com.google.protobuf.ByteString; +import java.io.UnsupportedEncodingException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + +import static org.mockito.Mockito.when; public final class InvocationTaskManagerTest { @@ -65,8 +64,7 @@ public void onMessageTestTx() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); - when(chaincode.getChaincodeConfig()).thenReturn(new Properties()); - chaincode.setState(ChaincodeBase.CCState.READY); + when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.READY); itm.onChaincodeMessage(msg); @@ -79,8 +77,7 @@ public void onWrongCreatedState() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); - when(chaincode.getChaincodeConfig()).thenReturn(new Properties()); - chaincode.setState(ChaincodeBase.CCState.CREATED); + when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.CREATED); itm.onChaincodeMessage(msg); @@ -92,8 +89,7 @@ public void onWrongEstablishedState() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); - when(chaincode.getChaincodeConfig()).thenReturn(new Properties()); - chaincode.setState(ChaincodeBase.CCState.ESTABLISHED); + when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.ESTABLISHED); // final InvocationTaskManager itm = // InvocationTaskManager.getManager(chaincode, id); @@ -107,8 +103,7 @@ public void onErrorResponse() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.ERROR, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); - when(chaincode.getChaincodeConfig()).thenReturn(new Properties()); - chaincode.setState(ChaincodeBase.CCState.READY); + when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.READY); itm.onChaincodeMessage(msg); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java index f5d39f0d..51fc0193 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java @@ -6,23 +6,22 @@ package org.hyperledger.fabric.shim.impl; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import com.google.protobuf.ByteString; +import com.google.protobuf.Timestamp; +import org.hyperledger.fabric.shim.ledger.KeyModification; +import org.junit.jupiter.api.Test; import java.time.Instant; import java.util.stream.Stream; -import org.hyperledger.fabric.shim.ledger.KeyModification; -import org.junit.Test; - -import com.google.protobuf.ByteString; -import com.google.protobuf.Timestamp; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class KeyModificationImplTest { @@ -96,7 +95,7 @@ public void testHashCode() { expectedHashCode = expectedHashCode * 31 + "".hashCode(); expectedHashCode = expectedHashCode * 31 + ByteString.copyFromUtf8("").hashCode(); - assertEquals("Wrong hash code", expectedHashCode, km.hashCode()); + assertEquals(expectedHashCode, km.hashCode(), "Wrong hash code"); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java index 122e94cc..216398d6 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java @@ -6,18 +6,17 @@ package org.hyperledger.fabric.shim.impl; +import com.google.protobuf.ByteString; +import org.hyperledger.fabric.protos.ledger.queryresult.KV; +import org.junit.jupiter.api.Test; + import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import org.hyperledger.fabric.protos.ledger.queryresult.KV; -import org.junit.Test; - -import com.google.protobuf.ByteString; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; public class KeyValueImplTest { @@ -65,7 +64,7 @@ public void testHashCode() { expectedHashCode = expectedHashCode + "".hashCode(); expectedHashCode = expectedHashCode * 31 + ByteString.copyFromUtf8("").hashCode(); - assertEquals("Wrong hashcode", expectedHashCode, kv.hashCode()); + assertEquals(expectedHashCode, kv.hashCode(), "Wrong hashcode"); } @Test diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java index 21040a55..9f312564 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java @@ -7,15 +7,15 @@ package org.hyperledger.fabric.shim.impl; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.fail; import java.util.function.Function; import org.hyperledger.fabric.protos.peer.QueryResponse; import org.hyperledger.fabric.protos.peer.QueryResultBytes; import org.hyperledger.fabric.protos.peer.QueryResponseMetadata; -import org.junit.Test; +import org.junit.jupiter.api.Test; import com.google.protobuf.ByteString; diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java index 9825ff64..2fce7d4f 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java @@ -6,15 +6,16 @@ package org.hyperledger.fabric.shim.ledger; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import java.util.Arrays; - -import org.junit.Test; public class CompositeKeyTest { @Test @@ -22,9 +23,10 @@ public void testValidateSimpleKeys() { CompositeKey.validateSimpleKeys("abc", "def", "ghi"); } - @Test(expected = CompositeKeyFormatException.class) - public void testValidateSimpleKeysException() throws Exception { - CompositeKey.validateSimpleKeys("\u0000abc"); + @Test + public void testValidateSimpleKeysException() { + assertThatThrownBy(() -> CompositeKey.validateSimpleKeys("\u0000abc")) + .isInstanceOf(CompositeKeyFormatException.class); } @Test @@ -51,24 +53,28 @@ public void testEmptyAttributes() { assertThat(key.toString(), is(equalTo("\u0000abc\u0000"))); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testCompositeKeyWithInvalidObjectTypeDelimiter() { - new CompositeKey("ab\u0000c", Arrays.asList("def", "ghi", "jkl", "mno")); + assertThatThrownBy(() -> new CompositeKey("ab\u0000c", Arrays.asList("def", "ghi", "jkl", "mno"))) + .isInstanceOf(CompositeKeyFormatException.class); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testCompositeKeyWithInvalidAttributeDelimiter() { - new CompositeKey("abc", Arrays.asList("def", "ghi", "j\u0000kl", "mno")); + assertThatThrownBy(() -> new CompositeKey("abc", Arrays.asList("def", "ghi", "j\u0000kl", "mno"))) + .isInstanceOf(CompositeKeyFormatException.class); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testCompositeKeyWithInvalidObjectTypeMaxCodePoint() { - new CompositeKey("ab\udbff\udfffc", Arrays.asList("def", "ghi", "jkl", "mno")); + assertThatThrownBy(() -> new CompositeKey("ab\udbff\udfffc", Arrays.asList("def", "ghi", "jkl", "mno"))) + .isInstanceOf(CompositeKeyFormatException.class); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testCompositeKeyWithInvalidAttributeMaxCodePoint() { - new CompositeKey("abc", Arrays.asList("def", "ghi", "jk\udbff\udfffl", "mno")); + assertThatThrownBy(() -> new CompositeKey("abc", Arrays.asList("def", "ghi", "jk\udbff\udfffl", "mno"))) + .isInstanceOf(CompositeKeyFormatException.class); } @Test @@ -100,14 +106,16 @@ public void testParseCompositeKey() { assertThat(key.toString(), is(equalTo("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testParseCompositeKeyInvalidObjectType() { - CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"); + assertThatThrownBy(() -> CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")) + .isInstanceOf(CompositeKeyFormatException.class); } - @Test(expected = CompositeKeyFormatException.class) + @Test public void testParseCompositeKeyInvalidAttribute() { - CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000"); + assertThatThrownBy(() -> CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000")) + .isInstanceOf(CompositeKeyFormatException.class); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java index 603f9810..fca985db 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java @@ -6,7 +6,7 @@ package org.hyperledger.fabric.traces.impl; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.Arrays; diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a80b22ce..0aaefbca 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From bb8cd6b7618d31e78a011bef24fd6358afb0ea8a Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 23 Sep 2024 15:55:54 +0100 Subject: [PATCH 012/178] Update versions following v2.5.4 release Signed-off-by: Mark S. Lewis --- build.gradle | 2 +- examples/fabric-contract-example-maven/pom.xml | 2 +- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 762de3e1..094a38f0 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { id "com.github.ben-manes.versions" version "0.51.0" } -version = '2.5.4' +version = '2.5.5' // If the nightly property is set, then this is the scheduled main diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index ae33ca51..b022d5aa 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.3 + 2.5.4 1.3.14 diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index acba4678..f65f9468 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -65,6 +65,6 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.4', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.5', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index a3a4016a..4162e3ae 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 72a0feec..fc475a98 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.4 + 2.5.5 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 84b7f857..7d5ec564 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index b78f4018..a57bef8b 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.4' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' implementation 'commons-logging:commons-logging:1.2' implementation 'com.google.code.gson:gson:2.10.1' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 7484f7c1..e70ceed1 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.4 + 2.5.5 From 33f3ba8895b126b0662eb6537952755475fefc95 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 14 Oct 2024 14:40:51 +0100 Subject: [PATCH 013/178] Run vulnerability scan on latest release version (#355) Previously the scan ran on the current state of the codebase. This fails to identify vulnerabilities in dependencies for the latest release version if those dependencies have already been updated in the development codebase. The gating factor for whether a new release is required should be whether the previous release contains vulnerabilities. This change runs the scheduled vulnerability scan on the latest release tag. It also adds vulnerability scanning to pull request builds. This is purely informational. A scan failure does not fail the pull request build. Signed-off-by: Mark S. Lewis --- .github/workflows/pull_request.yml | 3 +++ .github/workflows/release.yml | 10 ++------- .github/workflows/scan.yml | 33 ++++++++++++++++++++++++++++ .github/workflows/scheduled-scan.yml | 21 +++++++++++------- .github/workflows/test.yml | 16 ++++++-------- 5 files changed, 58 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/scan.yml diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 22777bbd..ff79cf71 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -17,6 +17,9 @@ jobs: test: uses: ./.github/workflows/test.yml + scan: + uses: ./.github/workflows/scan.yml + pull-request: needs: test name: Pull request success diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 605c7706..d64500d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,10 +34,7 @@ jobs: with: distribution: 'temurin' java-version: '11' - cache: 'gradle' - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v3 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 - name: Push to registry ${{ matrix.publish_target }} run: | set -xev @@ -69,10 +66,7 @@ jobs: with: distribution: 'temurin' java-version: '11' - cache: 'gradle' - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v3 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Set up QEMU diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml new file mode 100644 index 00000000..e87983eb --- /dev/null +++ b/.github/workflows/scan.yml @@ -0,0 +1,33 @@ +name: "Scheduled vulnerability scan" + +on: + workflow_call: + inputs: + ref: + description: Branch, tag or SHA to scan. + type: string + required: false + default: "" + +permissions: + contents: read + +jobs: + osv-scanner: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 11 + - uses: gradle/actions/setup-gradle@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: stable + cache: false + - name: Scan + run: make scan diff --git a/.github/workflows/scheduled-scan.yml b/.github/workflows/scheduled-scan.yml index c303b270..cfbe5687 100644 --- a/.github/workflows/scheduled-scan.yml +++ b/.github/workflows/scheduled-scan.yml @@ -9,13 +9,18 @@ permissions: contents: read jobs: - osv-scanner: + latest-release-version: + name: Get latest release tag runs-on: ubuntu-latest + outputs: + tag_name: ${{ steps.tag-name.outputs.value }} steps: - - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: stable - - name: Scan - run: make scan + - id: tag-name + run: echo "value=$(curl --location --silent --fail "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest" | jq --raw-output '.tag_name')" >> "${GITHUB_OUTPUT}" + + scan: + name: Scan ${{ needs.latest-release-version.outputs.tag_name }} + needs: latest-release-version + uses: ./.github/workflows/scan.yml + with: + ref: ${{ needs.latest-release-version.outputs.tag_name }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e057986..7ae6e959 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ name: Test on: workflow_call: inputs: - checkout-ref: + ref: default: '' required: false type: string @@ -18,14 +18,12 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.checkout-ref }} + ref: ${{ inputs.ref }} - uses: actions/setup-java@v4 with: distribution: temurin java-version: 11 - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v3 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -34,11 +32,12 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.checkout-ref }} + ref: ${{ inputs.ref }} - uses: actions/setup-java@v4 with: distribution: temurin java-version: 11 + - uses: gradle/actions/setup-gradle@v4 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -58,7 +57,6 @@ jobs: run: | peer version weft --version - - uses: gradle/actions/setup-gradle@v3 - name: Integration Tests run: ./gradlew :fabric-chaincode-integration-test:build @@ -67,11 +65,11 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.checkout-ref }} + ref: ${{ inputs.ref }} - uses: actions/setup-java@v4 with: distribution: temurin java-version: 11 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 4895f92d4f94149d55a64c3bb9f03ea10d628e99 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 25 Oct 2024 04:30:46 +0100 Subject: [PATCH 014/178] Use Spotless for code formatting (#358) Spotless is widely used opinionated Java code formatter. It will also fix incorrect formatting using `./gradlew spotlessApply`, avoiding the need for contributors to manually correct any formatting violations flagged by Checkstyle. Formatting rules defined by Checkstyle that would otherwise cause conflicts with the formatting applied by Spotless are removed. This change also updates the Gradle version to 8.10.2. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 4 +- .gitignore | 1 + CONTRIBUTING.md | 2 +- build.gradle | 23 +- ci/checkstyle/checkstyle.xml | 17 - fabric-chaincode-docker/build.gradle | 1 - .../build.gradle | 4 +- .../chaincodebootstrap.gradle | 2 +- .../contractinstall/ContractInstallTest.java | 29 +- .../ledgertests/LedgerIntegrationTest.java | 21 +- .../shimtests/SACCIntegrationTest.java | 22 +- .../shimtests/SBECCIntegrationTest.java | 13 +- .../fabric/shim/integration/util/Bash.java | 32 +- .../fabric/shim/integration/util/Command.java | 31 +- .../fabric/shim/integration/util/Docker.java | 46 +- .../shim/integration/util/DockerCompose.java | 47 +- .../shim/integration/util/FabricState.java | 12 +- .../shim/integration/util/InvokeHelper.java | 36 +- .../fabric/shim/integration/util/Peer.java | 63 +- fabric-chaincode-shim/build.gradle | 6 +- .../java/org/hyperledger/fabric/Logger.java | 22 +- .../java/org/hyperledger/fabric/Logging.java | 69 +- .../fabric/contract/ClientIdentity.java | 61 +- .../hyperledger/fabric/contract/Context.java | 37 +- .../fabric/contract/ContextFactory.java | 12 +- .../fabric/contract/ContractInterface.java | 85 +-- .../fabric/contract/ContractRouter.java | 26 +- .../contract/ContractRuntimeException.java | 24 +- .../fabric/contract/annotation/Contact.java | 18 +- .../fabric/contract/annotation/Contract.java | 22 +- .../fabric/contract/annotation/DataType.java | 21 +- .../fabric/contract/annotation/Default.java | 8 +- .../fabric/contract/annotation/Info.java | 26 +- .../fabric/contract/annotation/License.java | 16 +- .../fabric/contract/annotation/Property.java | 12 +- .../contract/annotation/Serializer.java | 24 +- .../contract/annotation/Transaction.java | 42 +- .../contract/execution/ExecutionFactory.java | 4 +- .../contract/execution/ExecutionService.java | 4 +- .../contract/execution/InvocationRequest.java | 24 +- .../execution/JSONTransactionSerializer.java | 156 +++-- .../execution/SerializerInterface.java | 16 +- .../impl/ContractExecutionService.java | 35 +- .../impl/ContractInvocationRequest.java | 29 +- .../contract/execution/impl/package-info.java | 4 +- .../contract/execution/package-info.java | 4 +- .../contract/metadata/MetadataBuilder.java | 34 +- .../fabric/contract/metadata/TypeSchema.java | 187 +++--- .../contract/metadata/package-info.java | 4 +- .../fabric/contract/package-info.java | 11 +- .../contract/routing/ContractDefinition.java | 45 +- .../contract/routing/DataTypeDefinition.java | 21 +- .../contract/routing/ParameterDefinition.java | 18 +- .../contract/routing/PropertyDefinition.java | 18 +- .../contract/routing/RoutingRegistry.java | 2 - .../contract/routing/TransactionType.java | 26 +- .../fabric/contract/routing/TxFunction.java | 53 +- .../fabric/contract/routing/TypeRegistry.java | 18 +- .../routing/impl/ContractDefinitionImpl.java | 13 +- .../routing/impl/DataTypeDefinitionImpl.java | 38 +- .../routing/impl/ParameterDefinitionImpl.java | 5 +- .../routing/impl/PropertyDefinitionImpl.java | 3 - .../routing/impl/RoutingRegistryImpl.java | 26 +- .../routing/impl/SerializerRegistryImpl.java | 29 +- .../contract/routing/impl/TxFunctionImpl.java | 31 +- .../routing/impl/TypeRegistryImpl.java | 7 +- .../contract/routing/impl/package-info.java | 4 +- .../fabric/contract/routing/package-info.java | 4 +- .../systemcontract/SystemContract.java | 22 +- .../contract/systemcontract/package-info.java | 4 +- .../hyperledger/fabric/ledger/Collection.java | 8 +- .../org/hyperledger/fabric/ledger/Ledger.java | 36 +- .../fabric/ledger/impl/CollectionImpl.java | 7 +- .../fabric/ledger/impl/LedgerImpl.java | 1 - .../fabric/ledger/impl/package-info.java | 12 +- .../fabric/ledger/package-info.java | 6 +- .../hyperledger/fabric/metrics/Metrics.java | 31 +- .../fabric/metrics/MetricsProvider.java | 30 +- .../fabric/metrics/TaskMetricsCollector.java | 6 +- .../fabric/metrics/impl/DefaultProvider.java | 45 +- .../fabric/metrics/impl/NullProvider.java | 14 +- .../fabric/metrics/impl/package-info.java | 4 +- .../fabric/metrics/package-info.java | 26 +- .../org/hyperledger/fabric/package-info.java | 4 +- .../hyperledger/fabric/shim/Chaincode.java | 44 +- .../fabric/shim/ChaincodeBase.java | 156 ++--- .../fabric/shim/ChaincodeException.java | 52 +- .../fabric/shim/ChaincodeServer.java | 9 +- .../shim/ChaincodeServerProperties.java | 93 ++- .../fabric/shim/ChaincodeStub.java | 616 ++++++++---------- .../fabric/shim/ChatChaincodeWithPeer.java | 12 +- .../hyperledger/fabric/shim/GrpcServer.java | 8 +- .../fabric/shim/NettyChaincodeServer.java | 14 +- .../fabric/shim/NettyGrpcServer.java | 52 +- .../fabric/shim/ResponseUtils.java | 13 +- .../shim/ext/sbe/StateBasedEndorsement.java | 39 +- .../impl/StateBasedEndorsementFactory.java | 13 +- .../sbe/impl/StateBasedEndorsementImpl.java | 31 +- .../sbe/impl/StateBasedEndorsementUtils.java | 39 +- .../shim/ext/sbe/impl/package-info.java | 12 +- .../fabric/shim/ext/sbe/package-info.java | 4 +- .../shim/impl/ChaincodeInvocationTask.java | 89 ++- .../shim/impl/ChaincodeMessageFactory.java | 186 ++++-- .../shim/impl/ChaincodeSupportClient.java | 25 +- .../fabric/shim/impl/InvocationStubImpl.java | 316 +++++---- .../shim/impl/InvocationTaskExecutor.java | 20 +- .../shim/impl/InvocationTaskManager.java | 80 +-- .../fabric/shim/impl/KeyModificationImpl.java | 8 +- .../fabric/shim/impl/KeyValueImpl.java | 4 +- .../shim/impl/QueryResultsIteratorImpl.java | 36 +- .../QueryResultsIteratorWithMetadataImpl.java | 25 +- .../fabric/shim/impl/package-info.java | 4 +- .../fabric/shim/ledger/CompositeKey.java | 28 +- .../ledger/CompositeKeyFormatException.java | 8 +- .../fabric/shim/ledger/KeyModification.java | 8 +- .../fabric/shim/ledger/KeyValue.java | 5 +- .../shim/ledger/QueryResultsIterator.java | 7 +- .../QueryResultsIteratorWithMetadata.java | 11 +- .../fabric/shim/ledger/package-info.java | 1 - .../hyperledger/fabric/shim/package-info.java | 6 +- .../org/hyperledger/fabric/traces/Traces.java | 33 +- .../fabric/traces/TracesProvider.java | 32 +- .../traces/impl/DefaultTracesProvider.java | 3 +- .../fabric/traces/impl/NullProvider.java | 3 +- .../traces/impl/OpenTelemetryProperties.java | 55 +- .../impl/OpenTelemetryTracesProvider.java | 6 +- .../fabric/traces/impl/package-info.java | 12 +- .../fabric/traces/package-info.java | 22 +- .../java/ChaincodeWithoutPackageTest.java | 18 +- .../src/test/java/contract/Greeting.java | 2 - .../test/java/contract/SampleContract.java | 27 +- .../org/hyperledger/fabric/LoggerTest.java | 1 - .../org/hyperledger/fabric/LoggingTest.java | 17 +- .../java/org/hyperledger/fabric/TestUtil.java | 76 ++- .../fabric/contract/AllTypesAsset.java | 13 +- .../contract/ChaincodeStubNaiveImpl.java | 58 +- .../fabric/contract/ClientIdentityTest.java | 78 ++- .../fabric/contract/ContextFactoryTest.java | 21 +- .../fabric/contract/ContextTest.java | 15 +- .../contract/ContractInterfaceTest.java | 22 +- .../fabric/contract/ContractRouterTest.java | 91 ++- .../hyperledger/fabric/contract/MyType.java | 4 +- .../hyperledger/fabric/contract/MyType2.java | 16 +- .../contract/TransactionExceptionTest.java | 11 +- .../ContractExecutionServiceTest.java | 39 +- .../JSONTransactionSerializerTest.java | 9 +- .../metadata/MetadataBuilderTest.java | 30 +- .../contract/metadata/TypeSchemaTest.java | 11 +- .../routing/ContractDefinitionTest.java | 19 +- .../routing/DataTypeDefinitionTest.java | 13 +- .../routing/ParameterDefinitionTest.java | 12 +- .../routing/PropertyDefinitionTest.java | 9 +- .../contract/routing/TxFunctionTest.java | 36 +- .../contract/routing/TypeRegistryTest.java | 10 +- .../simplepath/ContractSimplePathTest.java | 20 +- .../hyperledger/fabric/ledger/LedgerTest.java | 1 - .../fabric/metrics/MetricsTest.java | 24 +- .../metrics/impl/DefaultProviderTest.java | 6 +- .../fabric/shim/ChaincodeBaseTest.java | 138 ++-- .../fabric/shim/ChaincodeServerImplTest.java | 31 +- .../fabric/shim/ChaincodeStubTest.java | 30 +- .../fabric/shim/ChaincodeTest.java | 37 +- .../shim/ChatChaincodeWithPeerTest.java | 226 +++---- .../fabric/shim/NettyGrpcServerTest.java | 229 ++++--- .../ext/sbe/StateBasedEndorsementTest.java | 11 +- .../StateBasedEndorsementFactoryTest.java | 3 +- .../impl/StateBasedEndorsementImplTest.java | 38 +- .../fabric/shim/fvt/ChaincodeFVTest.java | 237 ++++--- .../impl/ChaincodeMessageFactoryTest.java | 9 +- .../shim/impl/ChaincodeSupportClientTest.java | 64 +- .../shim/impl/InnvocationTaskManagerTest.java | 68 +- .../shim/impl/InvocationStubImplTest.java | 15 +- .../shim/impl/InvocationTaskManagerTest.java | 38 +- .../shim/impl/KeyModificationImplTest.java | 92 +-- .../fabric/shim/impl/KeyValueImplTest.java | 15 +- ...ryResultsIteratorWithMetadataImplTest.java | 22 +- .../fabric/shim/ledger/CompositeKeyTest.java | 14 +- .../shim/mock/peer/ChaincodeMockPeer.java | 82 +-- .../fabric/shim/mock/peer/CompleteStep.java | 5 +- .../fabric/shim/mock/peer/DelValueStep.java | 5 +- .../shim/mock/peer/ErrorResponseStep.java | 5 +- .../shim/mock/peer/GetHistoryForKeyStep.java | 21 +- .../shim/mock/peer/GetQueryResultStep.java | 7 +- .../shim/mock/peer/GetStateByRangeStep.java | 6 +- .../shim/mock/peer/GetStateMetadata.java | 20 +- .../fabric/shim/mock/peer/GetValueStep.java | 14 +- .../shim/mock/peer/InvokeChaincodeStep.java | 18 +- .../fabric/shim/mock/peer/PurgeValueStep.java | 5 +- .../shim/mock/peer/PutStateMetadata.java | 19 +- .../fabric/shim/mock/peer/PutValueStep.java | 13 +- .../fabric/shim/mock/peer/QueryCloseStep.java | 10 +- .../fabric/shim/mock/peer/QueryNextStep.java | 7 +- .../shim/mock/peer/QueryResultStep.java | 27 +- .../fabric/shim/mock/peer/RegisterStep.java | 5 +- .../fabric/shim/mock/peer/ScenarioStep.java | 1 - .../fabric/shim/utils/MessageUtil.java | 15 +- .../fabric/shim/utils/TimeoutUtil.java | 11 +- .../hyperledger/fabric/traces/TracesTest.java | 31 +- .../traces/impl/DefaultProviderTest.java | 4 +- .../impl/OpenTelemetryPropertiesTest.java | 28 +- .../impl/OpenTelemetryTracesProviderTest.java | 45 +- .../traces/impl/TestSpanExporterProvider.java | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 +- gradlew.bat | 2 + settings.gradle | 2 +- 207 files changed, 3119 insertions(+), 3631 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d64500d8..8ed4a411 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: 11 - uses: gradle/actions/setup-gradle@v4 - name: Push to registry ${{ matrix.publish_target }} run: | @@ -65,7 +65,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: 11 - uses: gradle/actions/setup-gradle@v4 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps diff --git a/.gitignore b/.gitignore index 1e849943..78211b3e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ **/bin/ /build/ build/* +settings-gradle.lockfile _cfg repository diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f624836..d872b5bc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ We use our own forks and [Github Flow](https://guides.github.com/introduction/fl ## Coding Style -Please to try to be consistent with the rest of the code and conform to checkstyle rules where they are provided. +Please to try to be consistent with the rest of the code and conform to checkstyle rules where they are provided. [Spotless](https://github.com/diffplug/spotless) is used to enforce code formatting. You can run `./gradlew spotlessApply` to apply the mandated code formatting to the codebase before submitting changes to avoid failing the build with formatting violations. ## Code of Conduct Guidelines diff --git a/build.gradle b/build.gradle index 094a38f0..ec45db35 100644 --- a/build.gradle +++ b/build.gradle @@ -6,12 +6,13 @@ plugins { id "com.github.ben-manes.versions" version "0.51.0" + id "com.diffplug.spotless" version "6.25.0" } version = '2.5.5' -// If the nightly property is set, then this is the scheduled main +// If the nightly property is set, then this is the scheduled main // build - and we should publish this to artifactory // // Use the .dev. format to match Maven convention @@ -23,16 +24,27 @@ if (properties.containsKey('NIGHTLY')) { } allprojects { + apply plugin: "com.diffplug.spotless" + repositories { mavenCentral() maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://www.jitpack.io" } } + + spotless { + format 'misc', { + target '*.gradle', '.gitattributes', '.gitignore' + trimTrailingWhitespace() + indentWithSpaces() + endWithNewline() + } + } } subprojects { apply plugin: 'java' - apply plugin: 'maven-publish' + apply plugin: "maven-publish" group = 'org.hyperledger.fabric-chaincode-java' version = rootProject.version @@ -64,6 +76,13 @@ subprojects { useJUnitPlatform() } + spotless { + java { + removeUnusedImports() + palantirJavaFormat('2.50.0').formatJavadoc(true) + formatAnnotations() + } + } } task printVersionName() { diff --git a/ci/checkstyle/checkstyle.xml b/ci/checkstyle/checkstyle.xml index 14ee8c15..92b99a49 100644 --- a/ci/checkstyle/checkstyle.xml +++ b/ci/checkstyle/checkstyle.xml @@ -41,20 +41,8 @@ - - - - - - - - - - - - @@ -108,11 +96,6 @@ - - - - - diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index f65f9468..e5ba5d6c 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -67,4 +67,3 @@ task buildImage(type: DockerBuildImage) { inputDir = project.file('Dockerfile').parentFile images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.5', 'hyperledger/fabric-javaenv:amd64-latest'] } - diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 08d1524e..9d2b1fc7 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -8,7 +8,7 @@ dependencies { test { // Always run tests, even when nothing changed. dependsOn 'cleanTest' - + // Show test results. testLogging { events "passed", "skipped", "failed" @@ -16,7 +16,7 @@ dependencies { showCauses true showStandardStreams true exceptionFormat "full" - + } } diff --git a/fabric-chaincode-integration-test/chaincodebootstrap.gradle b/fabric-chaincode-integration-test/chaincodebootstrap.gradle index 67b9b238..fce50a3e 100644 --- a/fabric-chaincode-integration-test/chaincodebootstrap.gradle +++ b/fabric-chaincode-integration-test/chaincodebootstrap.gradle @@ -9,4 +9,4 @@ allprojects { } } } -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java index 881ac8cd..b05dbf81 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java @@ -5,40 +5,35 @@ */ package org.hyperleder.fabric.shim.integration.contractinstall; -import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * Basic Java Chaincode Test - * - */ +/** Basic Java Chaincode Test */ public class ContractInstallTest { - @BeforeAll + @BeforeAll public static void setUp() throws Exception { FabricState.getState().start(); - } - @Test - public void TestInstall(){ + @Test + public void TestInstall() { - InvokeHelper helper = InvokeHelper.newHelper("baregradlecc","sachannel"); + InvokeHelper helper = InvokeHelper.newHelper("baregradlecc", "sachannel"); String text = helper.invoke("org1", "whoami"); assertThat(text, containsString("BareGradle")); - - helper = InvokeHelper.newHelper("baremaven","sachannel"); + + helper = InvokeHelper.newHelper("baremaven", "sachannel"); text = helper.invoke("org1", "whoami"); assertThat(text, containsString("BareMaven")); - - helper = InvokeHelper.newHelper("wrappermaven","sachannel"); + + helper = InvokeHelper.newHelper("wrappermaven", "sachannel"); text = helper.invoke("org1", "whoami"); - assertThat(text, containsString("WrapperMaven")); + assertThat(text, containsString("WrapperMaven")); } - -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java index 20a1825e..ad856978 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java @@ -4,34 +4,29 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.ledgertests; -import static org.hamcrest.core.StringContains.containsString; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * Basic Java Chaincode Test - * - */ +/** Basic Java Chaincode Test */ public class LedgerIntegrationTest { - @BeforeAll + @BeforeAll public static void setUp() throws Exception { - FabricState.getState().start(); } - @Test - public void TestLedgers(){ - InvokeHelper helper = InvokeHelper.newHelper("ledgercc","sachannel"); - + @Test + public void TestLedgers() { + InvokeHelper helper = InvokeHelper.newHelper("ledgercc", "sachannel"); + String text = helper.invoke("org1", "accessLedgers"); assertThat(text, containsString("success")); - } - } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java index 50b27c45..94ebb378 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java @@ -4,37 +4,34 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.shimtests; -import static org.hamcrest.core.StringContains.containsString; + import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * Basic Java Chaincode Test - * - */ +/** Basic Java Chaincode Test */ public class SACCIntegrationTest { @BeforeAll public static void setUp() throws Exception { - FabricState.getState().start(); - + FabricState.getState().start(); } - @Test - public void TestLedger(){ + @Test + public void TestLedger() { InvokeHelper helper = InvokeHelper.newHelper("shimcc", "sachannel"); String text = helper.invoke("org1", "putBulkStates"); assertThat(text, containsString("success")); - - text = helper.invoke("org1", "getByRange","key120","key170"); + + text = helper.invoke("org1", "getByRange", "key120", "key170"); assertThat(text, containsString("50")); - text = helper.invoke("org1", "getByRangePaged","key120","key170","10",""); + text = helper.invoke("org1", "getByRangePaged", "key120", "key170", "10", ""); System.out.println(text); assertThat(text, containsString("key130")); @@ -42,5 +39,4 @@ public void TestLedger(){ System.out.println(text); assertThat(text, containsString("org.hyperledger.fabric.metrics.impl.DefaultProvider")); } - } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java index 418cdbf7..32e8ec56 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java @@ -5,9 +5,9 @@ */ package org.hyperleder.fabric.shim.integration.shimtests; -import static org.hamcrest.core.StringContains.containsString; -import static org.hamcrest.Matchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.core.StringContains.containsString; import org.hyperleder.fabric.shim.integration.util.FabricState; import org.hyperleder.fabric.shim.integration.util.InvokeHelper; @@ -19,8 +19,6 @@ public class SBECCIntegrationTest { @BeforeAll public static void setUp() throws Exception { FabricState.getState().start(); - - } @Test @@ -61,7 +59,6 @@ public void RunSBE_pub_setget() { assertThat(text, containsString("org2MSP")); assertThat(text, containsString("org1MSP")); - text = helper.invoke("org1", "EndorsementCC:setval", mode, "val3"); assertThat(text, containsString("success")); @@ -85,10 +82,9 @@ public void RunSBE_pub_setget() { assertThat(text, containsString("success")); text = helper.invoke("org1", "EndorsementCC:recordExists", mode); assertThat(text, containsString("false")); - } - @Test + @Test public void RunSBE_priv() { final String mode = "priv"; @@ -126,7 +122,6 @@ public void RunSBE_priv() { text = helper.invoke("org1", "EndorsementCC:listorgs", mode); assertThat(text, containsString("org2MSP")); assertThat(text, containsString("org1MSP")); - text = helper.invoke("org1", "EndorsementCC:setval", mode, "val3"); assertThat(text, containsString("success")); @@ -151,7 +146,5 @@ public void RunSBE_priv() { assertThat(text, containsString("success")); text = helper.invoke("org1", "EndorsementCC:recordExists", mode); assertThat(text, containsString("false")); - } - } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Bash.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Bash.java index b135a48b..2440e224 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Bash.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Bash.java @@ -4,23 +4,20 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.util; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -/** Represents the 'peer' cli command - * - * - * - */ +/** Represents the 'peer' cli command */ public final class Bash extends Command { - public static BashBuilder newBuilder(){ + public static BashBuilder newBuilder() { return new BashBuilder(); } - static public class BashBuilder extends Command.Builder { + public static class BashBuilder extends Command.Builder { String cmd; String orderer; String channel; @@ -28,7 +25,7 @@ static public class BashBuilder extends Command.Builder { boolean evaluate = false; int waitForEventTimeout; List args = new ArrayList(); - Map transientData; + Map transientData; public BashBuilder duplicate() { try { @@ -40,26 +37,25 @@ public BashBuilder duplicate() { } } - public BashBuilder cmd(String cmd){ + public BashBuilder cmd(String cmd) { this.cmd = cmd; return this; } - public BashBuilder cmdargs(String argsArray[]){ + public BashBuilder cmdargs(String argsArray[]) { this.args = Arrays.asList(argsArray); return this; } - public Bash build(Map additionalEnv){ + public Bash build(Map additionalEnv) { ArrayList list = new ArrayList<>(); list.add(cmd); - return new Bash(list,additionalEnv); + return new Bash(list, additionalEnv); } - - public Bash build(){ + public Bash build() { ArrayList list = new ArrayList<>(); list.add(cmd); @@ -71,9 +67,9 @@ public Bash build(){ Bash(List cmd) { super(cmd); - } + } - Bash(List cmd, Map env) { - super(cmd, env); + Bash(List cmd, Map env) { + super(cmd, env); } -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Command.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Command.java index a18a282e..a4a759e8 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Command.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Command.java @@ -25,7 +25,7 @@ public class Command { protected final List cmd; protected final Map env = new HashMap<>(); - Command(List cmd, Map additionalEnv){ + Command(List cmd, Map additionalEnv) { this.cmd = cmd; this.env.putAll(additionalEnv); } @@ -40,16 +40,14 @@ public static final class Result { public int exitcode; } - /** - * Run but don't suppress the output being printed directly - */ + /** Run but don't suppress the output being printed directly */ public Result run() { return this.run(false); } /** * Run the command, and process the output to arrays for later parsing and checking - * + * * @param quiet true if the output should NOT be printed directly to System.out/System.err */ public Result run(boolean quiet) { @@ -60,22 +58,24 @@ public Result run(boolean quiet) { System.out.println("Running:" + this); try { - + processBuilder.redirectInput(Redirect.INHERIT); processBuilder.redirectErrorStream(true); - + Process process = processBuilder.start(); System.out.println("Started..... "); - CompletableFuture> soutFut = readOutStream(process.getInputStream(),quiet?null:System.out); - CompletableFuture> serrFut = readOutStream(process.getErrorStream(),quiet?null:System.err); + CompletableFuture> soutFut = + readOutStream(process.getInputStream(), quiet ? null : System.out); + CompletableFuture> serrFut = + readOutStream(process.getErrorStream(), quiet ? null : System.err); CompletableFuture resultFut = soutFut.thenCombine(serrFut, (stdout, stderr) -> { - // print to current stderr the stderr of process and return the stdout + // print to current stderr the stderr of process and return the stdout result.stderr = stderr; result.stdout = stdout; return result; - }); + }); result.exitcode = process.waitFor(); // get stdout once ready, blocking @@ -91,18 +91,19 @@ public Result run(boolean quiet) { /** * Collect the information from the executed process and add them to a result object - * + * * @param is * @param stream * @return Completable Future with the array list of the stdout/stderr */ CompletableFuture> readOutStream(InputStream is, PrintStream stream) { return CompletableFuture.supplyAsync(() -> { - try (InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr);) { + try (InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); ) { ArrayList res = new ArrayList<>(); String inputLine; while ((inputLine = br.readLine()) != null) { - if (stream!=null) stream.println(inputLine); + if (stream != null) stream.println(inputLine); res.add(inputLine); } return res; @@ -116,7 +117,7 @@ public String toString() { return "[" + String.join(" ", cmd) + "]"; } - static public class Builder implements Cloneable { + public static class Builder implements Cloneable { @SuppressWarnings("unchecked") public Builder duplicate() { try { diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Docker.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Docker.java index f500d333..e24bed82 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Docker.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Docker.java @@ -4,17 +4,14 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.util; + import java.util.ArrayList; import java.util.List; -/** Represents the 'docker' cli command - * - * - * - */ +/** Represents the 'docker' cli command */ public final class Docker extends Command { - public static DockerBuilder newBuilder(){ + public static DockerBuilder newBuilder() { return new DockerBuilder(); } @@ -32,58 +29,55 @@ public DockerBuilder duplicate() { return null; } } - - public DockerBuilder script(String script){ + + public DockerBuilder script(String script) { this.script = script; return this; } - - public DockerBuilder channel(String channel){ + + public DockerBuilder channel(String channel) { this.channel = channel; return this; } - public DockerBuilder container(String container){ + public DockerBuilder container(String container) { this.container = container; return this; } - public DockerBuilder exec(){ + public DockerBuilder exec() { this.exec = true; return this; } - public Docker build(){ + public Docker build() { ArrayList list = new ArrayList<>(); list.add("docker"); - if(exec){ + if (exec) { list.add("exec"); - } - - if (container == null || container.isEmpty()){ + + if (container == null || container.isEmpty()) { throw new RuntimeException("container should be set"); } list.add(container); - - if (script == null || script.isEmpty()){ + + if (script == null || script.isEmpty()) { throw new RuntimeException("script should be set"); } list.add(script); - - if (channel == null || channel.isEmpty()){ + + if (channel == null || channel.isEmpty()) { throw new RuntimeException("channel should be set"); } list.add(channel); - return new Docker(list); } } - + Docker(List cmd) { - super(cmd); + super(cmd); } - -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/DockerCompose.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/DockerCompose.java index 3beaac55..50a2e8eb 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/DockerCompose.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/DockerCompose.java @@ -4,71 +4,66 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.util; + import java.util.ArrayList; import java.util.List; -/** Represents the 'peer' cli command - * - * - * - */ +/** Represents the 'peer' cli command */ public final class DockerCompose extends Command { - public static DockerComposeBuilder newBuilder(){ + public static DockerComposeBuilder newBuilder() { return new DockerComposeBuilder(); } - - public static final class DockerComposeBuilder extends Command.Builder{ + + public static final class DockerComposeBuilder extends Command.Builder { String composeFile; boolean up = true; boolean detach = false; - public DockerComposeBuilder file(String composeFile){ + public DockerComposeBuilder file(String composeFile) { this.composeFile = composeFile; return this; } - + public DockerComposeBuilder duplicate() { return (DockerComposeBuilder) super.duplicate(); } - public DockerComposeBuilder up(){ + public DockerComposeBuilder up() { this.up = true; return this; } - - public DockerComposeBuilder detach(){ + + public DockerComposeBuilder detach() { this.detach = true; return this; } - - public DockerComposeBuilder down(){ + + public DockerComposeBuilder down() { this.up = false; return this; } - - public DockerCompose build(){ + + public DockerCompose build() { ArrayList list = new ArrayList<>(); list.add("docker-compose"); - if (composeFile!=null && !composeFile.isEmpty()) { + if (composeFile != null && !composeFile.isEmpty()) { list.add("-f"); list.add(composeFile); } - list.add(up?"up":"down"); - if (detach){ + list.add(up ? "up" : "down"); + if (detach) { list.add("-d"); } - return new DockerCompose(list); } } - + DockerCompose(List cmd) { - super(cmd); - super.env.put("COMPOSE_PROJECT_NAME","first-network"); + super(cmd); + super.env.put("COMPOSE_PROJECT_NAME", "first-network"); } - -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java index 59909a2a..8483446e 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java @@ -10,7 +10,6 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; - import org.hyperleder.fabric.shim.integration.util.Bash.BashBuilder; public final class FabricState { @@ -49,15 +48,14 @@ public Map orgEnv(String org) { Map env = new HashMap<>(); - env.put("CORE_PEER_MSPCONFIGPATH", - Paths.get(s, "src/test/resources/_cfg/_msp/" + org, org + "admin/msp").toString()); + env.put( + "CORE_PEER_MSPCONFIGPATH", + Paths.get(s, "src/test/resources/_cfg/_msp/" + org, org + "admin/msp") + .toString()); env.put("CORE_PEER_LOCALMSPID", org + "MSP"); env.put("CORE_PEER_ADDRESS", org + "peer-api.127-0-0-1.nip.io:8080"); - System.out.println(env); return env; - } - -} \ No newline at end of file +} diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/InvokeHelper.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/InvokeHelper.java index 971cb252..6d4915f8 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/InvokeHelper.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/InvokeHelper.java @@ -1,49 +1,47 @@ package org.hyperleder.fabric.shim.integration.util; -import org.hyperleder.fabric.shim.integration.util.Command.Result; -import org.hyperleder.fabric.shim.integration.util.Peer.PeerBuilder; - import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; +import org.hyperleder.fabric.shim.integration.util.Command.Result; +import org.hyperleder.fabric.shim.integration.util.Peer.PeerBuilder; public class InvokeHelper { - + private String ccname; private String channel; - + public static InvokeHelper newHelper(String ccname, String channel) { - + InvokeHelper ih = new InvokeHelper(); - + ih.ccname = ccname; ih.channel = channel; - + return ih; } - - public String invoke(String org, String... args){ - Map orgEnv = FabricState.getState().orgEnv(org); + + public String invoke(String org, String... args) { + Map orgEnv = FabricState.getState().orgEnv(org); PeerBuilder coreBuilder = Peer.newBuilder().ccname(ccname).channel(channel); Result r = coreBuilder.argsTx(args).build(orgEnv).run(); System.out.println(r.stdout); String text = r.stdout.stream() - .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) - .collect(Collectors.joining(System.lineSeparator())) - .trim(); + .filter(line -> line.matches(".*chaincodeInvokeOrQuery.*")) + .collect(Collectors.joining(System.lineSeparator())) + .trim(); - if (!text.contains("result: status:200")){ + if (!text.contains("result: status:200")) { Command logsCommand = new Command(Arrays.asList("docker", "logs", "microfab"), orgEnv); logsCommand.run(); throw new RuntimeException(text); - } + } int payloadIndex = text.indexOf("payload:"); - if (payloadIndex>1){ - return text.substring(payloadIndex+9,text.length()-1); + if (payloadIndex > 1) { + return text.substring(payloadIndex + 9, text.length() - 1); } return "success"; } - } diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java index 99c19111..65f045b3 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java @@ -4,22 +4,18 @@ SPDX-License-Identifier: Apache-2.0 */ package org.hyperleder.fabric.shim.integration.util; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; - import org.json.JSONArray; import org.json.JSONObject; -/** Represents the 'peer' cli command - * - * - * - */ +/** Represents the 'peer' cli command */ public final class Peer extends Command { - public static PeerBuilder newBuilder(){ + public static PeerBuilder newBuilder() { return new PeerBuilder(); } @@ -31,7 +27,7 @@ public static final class PeerBuilder extends Command.Builder { boolean evaluate = false; int waitForEventTimeout; List args = new ArrayList(); - Map transientData; + Map transientData; public PeerBuilder duplicate() { try { @@ -43,64 +39,64 @@ public PeerBuilder duplicate() { } } - public PeerBuilder tlsArgs(String tlsArgs){ + public PeerBuilder tlsArgs(String tlsArgs) { this.tlsArgs = tlsArgs; return this; } - public PeerBuilder orderer(String orderer){ + public PeerBuilder orderer(String orderer) { this.orderer = orderer; return this; } - public PeerBuilder channel(String channel){ + public PeerBuilder channel(String channel) { this.channel = channel; return this; } - public PeerBuilder ccname(String ccname){ + public PeerBuilder ccname(String ccname) { this.ccname = ccname; return this; } - public PeerBuilder evaluate(){ + public PeerBuilder evaluate() { this.evaluate = true; return this; } - public PeerBuilder invoke(){ + public PeerBuilder invoke() { this.evaluate = false; return this; } - public PeerBuilder argsTx(List args){ + public PeerBuilder argsTx(List args) { this.args = args; return this; } - public PeerBuilder argsTx(String[] argsArray){ + public PeerBuilder argsTx(String[] argsArray) { this.args = Arrays.asList(argsArray); return this; } - public PeerBuilder transientData(Map transientData){ + public PeerBuilder transientData(Map transientData) { this.transientData = transientData; return this; } - public PeerBuilder waitForEvent(int seconds){ + public PeerBuilder waitForEvent(int seconds) { this.waitForEventTimeout = seconds; return this; } - public PeerBuilder waitForEvent(){ + public PeerBuilder waitForEvent() { this.waitForEvent(0); return this; } private String transientToString() { JSONObject json = new JSONObject(this.transientData); - return "'"+json.toString()+"'"; + return "'" + json.toString() + "'"; } private String argsToString() { @@ -110,43 +106,43 @@ private String argsToString() { return json.toString(); } - public Peer build(Map additionalEnv){ + public Peer build(Map additionalEnv) { ArrayList list = new ArrayList<>(); list.add("peer"); list.add("chaincode"); - list.add(evaluate?"query":"invoke"); + list.add(evaluate ? "query" : "invoke"); if (tlsArgs != null && !tlsArgs.isEmpty()) { list.add(tlsArgs); } - if (channel == null || channel.isEmpty()){ + if (channel == null || channel.isEmpty()) { throw new RuntimeException("Channel should be set"); } list.add("-C"); list.add(channel); - if (ccname == null || ccname.isEmpty()){ + if (ccname == null || ccname.isEmpty()) { throw new RuntimeException("Chaincode name should be set"); } list.add("-n"); list.add(ccname); - if (args == null || args.isEmpty()){ + if (args == null || args.isEmpty()) { throw new RuntimeException("Args should be set"); } list.add("-c"); list.add(argsToString()); - if (transientData != null && !transientData.isEmpty()){ + if (transientData != null && !transientData.isEmpty()) { list.add("--transient"); list.add(transientToString()); } - if (waitForEventTimeout>0){ + if (waitForEventTimeout > 0) { list.add("--waitForEvent --waitForEventTimeout"); - list.add(waitForEventTimeout+"s"); - } else if (waitForEventTimeout == 0 ){ + list.add(waitForEventTimeout + "s"); + } else if (waitForEventTimeout == 0) { list.add("--waitForEvent"); } @@ -155,12 +151,11 @@ public Peer build(Map additionalEnv){ list.add("--peerAddresses"); list.add("org2peer-api.127-0-0-1.nip.io:8080"); - return new Peer(list,additionalEnv); + return new Peer(list, additionalEnv); } } - - Peer(List cmd, Map additionalEnv) { - super(cmd,additionalEnv); + Peer(List cmd, Map additionalEnv) { + super(cmd, additionalEnv); } -} \ No newline at end of file +} diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index ded8f870..b4c50500 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -56,7 +56,7 @@ dependencies { implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' implementation 'org.json:json:20240303' implementation 'com.google.protobuf:protobuf-java-util' - + implementation 'io.grpc:grpc-netty-shaded' implementation 'io.grpc:grpc-protobuf' implementation 'io.grpc:grpc-stub' @@ -226,7 +226,7 @@ javadoc { source = sourceSets.main.allJava classpath = sourceSets.main.runtimeClasspath - + javadoc.options.addStringOption('Xdoclint:none', '-quiet') options.overview = "src/main/java/org/hyperledger/fabric/overview.html" } @@ -297,7 +297,7 @@ publishing { username = project.findProperty('ossrhUsername') password = project.findProperty('ossrhPassword') } - + } maven { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java index c8b0f9d6..e1a55c90 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java @@ -11,10 +11,7 @@ import java.util.logging.Level; import java.util.logging.LogManager; -/** - * Logger class to use throughout the Contract Implementation. - * - */ +/** Logger class to use throughout the Contract Implementation. */ public class Logger extends java.util.logging.Logger { protected Logger(final String name) { @@ -32,16 +29,12 @@ public static Logger getLogger(final String name) { return new Logger(name); } - /** - * @param msgSupplier - */ + /** @param msgSupplier */ public void debug(final Supplier msgSupplier) { log(Level.FINEST, msgSupplier); } - /** - * @param msg - */ + /** @param msg */ public void debug(final String msg) { log(Level.FINEST, msg); } @@ -57,16 +50,12 @@ public static Logger getLogger(final Class class1) { return l; } - /** - * @param message - */ + /** @param message */ public void error(final String message) { log(Level.SEVERE, message); } - /** - * @param msgSupplier - */ + /** @param msgSupplier */ public void error(final Supplier msgSupplier) { log(Level.SEVERE, msgSupplier); } @@ -92,5 +81,4 @@ public String formatError(final Throwable throwable) { return buffer.toString(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java index b6369056..1d26eaf4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -15,31 +15,22 @@ /** * Assistance class to use when logging. * - * For chaincode/contract implementations please use java.util.logging or your - * own framework. All the Hyperledger Fabric code here is logged in loggers with - * names starting org.hyperledger + *

For chaincode/contract implementations please use java.util.logging or your own framework. All the Hyperledger + * Fabric code here is logged in loggers with names starting org.hyperledger * - * Control of this is via the environment variables - * 'CORE_CHAINCODE_LOGGING_LEVEL' this takes a string that matches the following - * Java.util.logging levels (case insensitive) - * - * CRITICAL, ERROR == Level.SEVERE, WARNING == Level.WARNING, INFO == Level.INFO - * NOTICE == Level.CONFIG, DEBUG == Level.FINEST + *

Control of this is via the environment variables 'CORE_CHAINCODE_LOGGING_LEVEL' this takes a string that matches + * the following Java.util.logging levels (case insensitive) * + *

CRITICAL, ERROR == Level.SEVERE, WARNING == Level.WARNING, INFO == Level.INFO NOTICE == Level.CONFIG, DEBUG == + * Level.FINEST */ public final class Logging { - /** - * Name of the Performance logger. - */ + /** Name of the Performance logger. */ public static final String PERFLOGGER = "org.hyperledger.Performance"; - /** Private Constructor. - * - */ - private Logging() { - - } + /** Private Constructor. */ + private Logging() {} /** * Formats a Throwable to a string with details of all the causes. @@ -63,7 +54,6 @@ public static String formatError(final Throwable throwable) { } return buffer.toString(); - } /** @@ -79,30 +69,33 @@ public static void setLogLevel(final String newLevel) { // so find those that have the correct stem. final ArrayList allLoggers = Collections.list(logManager.getLoggerNames()); allLoggers.add("org.hyperledger"); - allLoggers.stream().filter(name -> name.startsWith("org.hyperledger")).map(name -> logManager.getLogger(name)).forEach(logger -> { - if (logger != null) { - logger.setLevel(l); - } - }); + allLoggers.stream() + .filter(name -> name.startsWith("org.hyperledger")) + .map(name -> logManager.getLogger(name)) + .forEach(logger -> { + if (logger != null) { + logger.setLevel(l); + } + }); } private static Level mapLevel(final String level) { if (level != null) { switch (level.toUpperCase().trim()) { - case "ERROR": - case "CRITICAL": - return Level.SEVERE; - case "WARNING": - case "WARN": - return Level.WARNING; - case "INFO": - return Level.INFO; - case "NOTICE": - return Level.CONFIG; - case "DEBUG": - return Level.FINEST; - default: - return Level.INFO; + case "ERROR": + case "CRITICAL": + return Level.SEVERE; + case "WARNING": + case "WARN": + return Level.WARNING; + case "INFO": + return Level.INFO; + case "NOTICE": + return Level.CONFIG; + case "DEBUG": + return Level.FINEST; + default: + return Level.INFO; } } return Level.INFO; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java index 078e0657..4c10f704 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java @@ -15,7 +15,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; - import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DEROctetString; @@ -26,12 +25,9 @@ import org.json.JSONObject; /** - * ClientIdentity represents information about the identity that submitted a - * transaction. Chaincodes can use this class to obtain information about the - * submitting identity including a unique ID, the MSP (Membership Service - * Provider) ID, and attributes. Such information is useful in enforcing access - * control by the chaincode. - * + * ClientIdentity represents information about the identity that submitted a transaction. Chaincodes can use this class + * to obtain information about the submitting identity including a unique ID, the MSP (Membership Service Provider) ID, + * and attributes. Such information is useful in enforcing access control by the chaincode. */ public final class ClientIdentity { private static Logger logger = Logger.getLogger(ContractRouter.class.getName()); @@ -60,7 +56,8 @@ public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSO final byte[] idBytes = si.getIdBytes().toByteArray(); - final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(idBytes)); + final X509Certificate cert = (X509Certificate) + CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(idBytes)); this.cert = cert; this.attrs = new HashMap(); @@ -71,12 +68,12 @@ public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSO } // Populate identity - this.id = "x509::" + cert.getSubjectDN().getName() + "::" + cert.getIssuerDN().getName(); + this.id = "x509::" + cert.getSubjectDN().getName() + "::" + + cert.getIssuerDN().getName(); } /** - * getId returns the ID associated with the invoking identity. This ID is - * guaranteed to be unique within the MSP. + * getId returns the ID associated with the invoking identity. This ID is guaranteed to be unique within the MSP. * * @return {String} A string in the format: "x509::{subject DN}::{issuer DN}" */ @@ -96,10 +93,9 @@ public String getMSPID() { /** * parseAttributes returns a map of the attributes associated with an identity. * - * @param extensionValue DER-encoded Octet string stored in the attributes - * extension of the certificate, as a byte array - * @return attrMap {Map} a map of identity attributes as key - * value pair strings + * @param extensionValue DER-encoded Octet string stored in the attributes extension of the certificate, as a byte + * array + * @return attrMap {Map} a map of identity attributes as key value pair strings * @throws IOException */ private Map parseAttributes(final byte[] extensionValue) throws IOException { @@ -107,7 +103,8 @@ private Map parseAttributes(final byte[] extensionValue) throws final Map attrMap = new HashMap(); // Create ASN1InputStream from extensionValue - try (ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { + try (ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); + ASN1InputStream asn1InputStream = new ASN1InputStream(inStream)) { // Read the DER object final ASN1Primitive derObject = asn1InputStream.readObject(); @@ -136,16 +133,13 @@ private Map parseAttributes(final byte[] extensionValue) throws } /** - * getAttributeValue returns the value of the client's attribute named - * `attrName`. If the invoking identity possesses the attribute, returns the - * value of the attribute. If the invoking identity does not possess the + * getAttributeValue returns the value of the client's attribute named `attrName`. If the invoking identity + * possesses the attribute, returns the value of the attribute. If the invoking identity does not possess the * attribute, returns null. * - * @param attrName Name of the attribute to retrieve the value from the - * identity's credentials (such as x.509 certificate for - * PKI-based MSPs). - * @return {String | null} Value of the attribute or null if the invoking - * identity does not possess the attribute. + * @param attrName Name of the attribute to retrieve the value from the identity's credentials (such as x.509 + * certificate for PKI-based MSPs). + * @return {String | null} Value of the attribute or null if the invoking identity does not possess the attribute. */ public String getAttributeValue(final String attrName) { if (this.attrs.containsKey(attrName)) { @@ -156,16 +150,14 @@ public String getAttributeValue(final String attrName) { } /** - * assertAttributeValue verifies that the invoking identity has the attribute - * named `attrName` with a value of `attrValue`. + * assertAttributeValue verifies that the invoking identity has the attribute named `attrName` with a value of + * `attrValue`. * - * @param attrName Name of the attribute to retrieve the value from the - * identity's credentials (such as x.509 certificate for - * PKI-based MSPs) + * @param attrName Name of the attribute to retrieve the value from the identity's credentials (such as x.509 + * certificate for PKI-based MSPs) * @param attrValue Expected value of the attribute - * @return {boolean} True if the invoking identity possesses the attribute and - * the attribute value matches the expected value. Otherwise, returns - * false. + * @return {boolean} True if the invoking identity possesses the attribute and the attribute value matches the + * expected value. Otherwise, returns false. */ public boolean assertAttributeValue(final String attrName, final String attrValue) { if (!this.attrs.containsKey(attrName)) { @@ -176,9 +168,8 @@ public boolean assertAttributeValue(final String attrName, final String attrValu } /** - * getX509Certificate returns the X509 certificate associated with the invoking - * identity, or null if it was not identified by an X509 certificate, for - * instance if the MSP is implemented with an alternative to PKI such as + * getX509Certificate returns the X509 certificate associated with the invoking identity, or null if it was not + * identified by an X509 certificate, for instance if the MSP is implemented with an alternative to PKI such as * [Identity Mixer](https://jira.hyperledger.org/browse/FAB-5673). * * @return {X509Certificate | null} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java index c11f17f9..ea0b4d36 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/Context.java @@ -8,22 +8,17 @@ import java.io.IOException; import java.security.cert.CertificateException; - import org.hyperledger.fabric.shim.ChaincodeStub; import org.json.JSONException; /** + * This context is available to all 'transaction functions' and provides the transaction context. It also provides + * access to the APIs for the world state using {@link #getStub()} * - * This context is available to all 'transaction functions' and provides the - * transaction context. It also provides access to the APIs for the world state - * using {@link #getStub()} - *

- * Applications can implement their own versions if they wish to add - * functionality. All subclasses MUST implement a constructor, for example - * - *

- * {@code
+ * 

Applications can implement their own versions if they wish to add functionality. All subclasses MUST implement a + * constructor, for example * + *

{@code
  * public MyContext extends Context {
  *
  *     public MyContext(ChaincodeStub stub) {
@@ -31,19 +26,13 @@
  *     }
  * }
  *
- *}
- * 
- * + * }
*/ public class Context { - /** - * - */ + /** */ protected ChaincodeStub stub; - /** - * - */ + /** */ protected ClientIdentity clientIdentity; /** @@ -60,18 +49,12 @@ public Context(final ChaincodeStub stub) { } } - /** - * - * @return ChaincodeStub instance to use - */ + /** @return ChaincodeStub instance to use */ public ChaincodeStub getStub() { return this.stub; } - /** - * - * @return ClientIdentity object to use - */ + /** @return ClientIdentity object to use */ public ClientIdentity getClientIdentity() { return this.clientIdentity; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java index b282dc2d..64e12a1b 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java @@ -8,17 +8,11 @@ import org.hyperledger.fabric.shim.ChaincodeStub; -/** - * Factory to create {@link Context} from {@link ChaincodeStub} by wrapping stub - * with dynamic proxy. - */ +/** Factory to create {@link Context} from {@link ChaincodeStub} by wrapping stub with dynamic proxy. */ public final class ContextFactory { private static ContextFactory cf; - /** - * - * @return ContextFactory - */ + /** @return ContextFactory */ public static synchronized ContextFactory getInstance() { if (cf == null) { cf = new ContextFactory(); @@ -27,7 +21,6 @@ public static synchronized ContextFactory getInstance() { } /** - * * @param stub * @return Context */ @@ -35,5 +28,4 @@ public Context createContext(final ChaincodeStub stub) { final Context newContext = new Context(stub); return newContext; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java index 9ef0352e..c9bea5fc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java @@ -12,52 +12,44 @@ /** * All Contracts should implement this interface, in addition to the * {@linkplain org.hyperledger.fabric.contract.annotation.Contract} annotation. - *

- * All methods on this interface have default implementations; for - * many contracts it may not be needed to sub-class these. - *

- * Each method on the Contract that is marked with the {@link org.hyperledger.fabric.contract.annotation.Transaction} - * annotation is considered a Transaction Function. This is eligible for - * calling. Each transaction function is supplied with its first parameter - * being a {@link org.hyperledger.fabric.contract.Context}. The other parameters - * are supplied at the developer's discretion. - *

- * The sequence of calls is + * + *

All methods on this interface have default implementations; for many contracts it may not be needed to sub-class + * these. + * + *

Each method on the Contract that is marked with the {@link org.hyperledger.fabric.contract.annotation.Transaction} + * annotation is considered a Transaction Function. This is eligible for calling. Each transaction function is supplied + * with its first parameter being a {@link org.hyperledger.fabric.contract.Context}. The other parameters are supplied + * at the developer's discretion. + * + *

The sequence of calls is * *

  * createContext()  -> beforeTransaction() -> the transaction function -> afterTransaction()
  * 
- *

- * If any of these functions throws an exception it is considered an error case - * and the whole transaction is failed. The - * {@link org.hyperledger.fabric.contract.Context} is a very important object as - * it provides transactional context for access to current transaction id, - * ledger state, etc. - *

- * Note on Threading - *

- * All code should be 'Thread Friendly'. Each method must not rely on instance - * fields or class side variables for storage. Nor should they use any - * ThreadLocal Storage. Ledger data is stored via the ledger api available via - * the {@link Context}. - *

- * If information needs to be passed from - * {@link #beforeTransaction(Context)} to - * {@link #afterTransaction(Context, Object)} or between separate transaction - * functions when called directly then a subclass of the {@link Context} - * should be provided. + * + *

If any of these functions throws an exception it is considered an error case and the whole transaction is failed. + * The {@link org.hyperledger.fabric.contract.Context} is a very important object as it provides transactional context + * for access to current transaction id, ledger state, etc. + * + *

Note on Threading + * + *

All code should be 'Thread Friendly'. Each method must not rely on instance fields or class side variables for + * storage. Nor should they use any ThreadLocal Storage. Ledger data is stored via the ledger api available via the + * {@link Context}. + * + *

If information needs to be passed from {@link #beforeTransaction(Context)} to {@link #afterTransaction(Context, + * Object)} or between separate transaction functions when called directly then a subclass of the {@link Context} should + * be provided. */ public interface ContractInterface { /** * Create context from {@link ChaincodeStub}. * - * Default impl provided, but can be - * overwritten by contract + *

Default impl provided, but can be overwritten by contract * * @param stub Instance of the ChaincodeStub to use for this transaction - * @return instance of the context to use for the current transaction being - * executed + * @return instance of the context to use for the current transaction being executed */ default Context createContext(final ChaincodeStub stub) { return ContextFactory.getInstance().createContext(stub); @@ -66,9 +58,8 @@ default Context createContext(final ChaincodeStub stub) { /** * Invoked for any transaction that does not exist. * - * This will throw an exception. If you wish to alter the exception thrown or if - * you wish to consider requests for transactions that don't exist as not an - * error, subclass this method. + *

This will throw an exception. If you wish to alter the exception thrown or if you wish to consider requests + * for transactions that don't exist as not an error, subclass this method. * * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. */ @@ -79,25 +70,21 @@ default void unknownTransaction(final Context ctx) { /** * Invoked once before each transaction. * - * Any exceptions thrown will fail the transaction, and neither the required - * transaction or the {@link #afterTransaction(Context, Object)} will be called + *

Any exceptions thrown will fail the transaction, and neither the required transaction or the + * {@link #afterTransaction(Context, Object)} will be called * * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. */ - default void beforeTransaction(final Context ctx) { - } + default void beforeTransaction(final Context ctx) {} /** * Invoked once after each transaction. * - * Any exceptions thrown will fail the transaction. + *

Any exceptions thrown will fail the transaction. * - * @param ctx the context as created by - * {@link #createContext(ChaincodeStub)}. - * @param result The object returned from the transaction function if any. As - * this is a Java object and therefore pass-by-reference it is - * possible to modify this object. + * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. + * @param result The object returned from the transaction function if any. As this is a Java object and therefore + * pass-by-reference it is possible to modify this object. */ - default void afterTransaction(final Context ctx, final Object result) { - } + default void afterTransaction(final Context ctx, final Object result) {} } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java index 510f1498..0219f71d 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java @@ -6,6 +6,9 @@ package org.hyperledger.fabric.contract; +import java.io.IOException; +import java.util.Properties; +import java.util.logging.Logger; import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.contract.execution.ExecutionFactory; import org.hyperledger.fabric.contract.execution.ExecutionService; @@ -25,13 +28,9 @@ import org.hyperledger.fabric.shim.ResponseUtils; import org.hyperledger.fabric.traces.Traces; -import java.io.IOException; -import java.util.Properties; -import java.util.logging.Logger; - /** - * Router class routes Init/Invoke requests to contracts. Implements - * {@link org.hyperledger.fabric.shim.Chaincode} interface. + * Router class routes Init/Invoke requests to contracts. Implements {@link org.hyperledger.fabric.shim.Chaincode} + * interface. * * @see ContractInterface */ @@ -47,10 +46,9 @@ public final class ContractRouter extends ChaincodeBase { private final ExecutionService executor; /** - * Take the arguments from the cli, and initiate processing of cli options and - * environment variables. + * Take the arguments from the cli, and initiate processing of cli options and environment variables. * - * Create the Contract scanner, and the Execution service + *

Create the Contract scanner, and the Execution service * * @param args */ @@ -81,9 +79,7 @@ public ContractRouter(final String[] args) { executor = ExecutionFactory.getInstance().createExecutionService(serializers); } - /** - * Locate all the contracts that are available on the classpath. - */ + /** Locate all the contracts that are available on the classpath. */ protected void findAllContracts() { registry.findAndSetContracts(this.typeRegistry); } @@ -91,7 +87,7 @@ protected void findAllContracts() { /** * Start the chaincode container off and running. * - * This will send the initial flow back to the peer + *

This will send the initial flow back to the peer * * @throws Exception */ @@ -169,8 +165,7 @@ public static void main(final String[] args) throws Exception { // check if this should be running in client or server mode if (cfc.isServer()) { logger.info("Starting chaincode as server"); - ChaincodeServer chaincodeServer = new NettyChaincodeServer(cfc, - cfc.getChaincodeServerConfig()); + ChaincodeServer chaincodeServer = new NettyChaincodeServer(cfc, cfc.getChaincodeServerConfig()); chaincodeServer.start(); } else { logger.info("Starting chaincode as client"); @@ -201,5 +196,4 @@ public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer chaincodeServer.start(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java index 0fca449f..b51c218f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java @@ -8,25 +8,19 @@ import org.hyperledger.fabric.shim.ChaincodeException; /** - * Specific RuntimeException for events that occur in the calling and handling - * of the Contracts, NOT within the contract logic itself. - *

- * FUTURE At some future point we wish to add more diagnostic information - * into this, for example current tx id + * Specific RuntimeException for events that occur in the calling and handling of the Contracts, NOT within the contract + * logic itself. * + *

FUTURE At some future point we wish to add more diagnostic information into this, for example current tx id */ public class ContractRuntimeException extends ChaincodeException { - /** - * - * @param string - */ + /** @param string */ public ContractRuntimeException(final String string) { super(string); } /** - * * @param string * @param cause */ @@ -34,17 +28,11 @@ public ContractRuntimeException(final String string, final Throwable cause) { super(string, cause); } - /** - * - * @param cause - */ + /** @param cause */ public ContractRuntimeException(final Throwable cause) { super(cause); } - /** - * Generated serial version id. - */ + /** Generated serial version id. */ private static final long serialVersionUID = -884373036398750450L; - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java index c344b37b..fb3e2fc9 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contact.java @@ -12,27 +12,19 @@ import java.lang.annotation.Target; /** - * Class level annotation that identifies this class as being a contact. Can be - * populated with email, name and url fields. - * + * Class level annotation that identifies this class as being a contact. Can be populated with email, name and url + * fields. */ @Retention(RUNTIME) @Target(ElementType.TYPE) public @interface Contact { - /** - * @return String - */ + /** @return String */ String email() default ""; - /** - * @return String - */ + /** @return String */ String name() default ""; - /** - * @return String - */ + /** @return String */ String url() default ""; - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java index d28987b2..8114170e 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Contract.java @@ -12,19 +12,17 @@ import java.lang.annotation.Target; /** - * Class level annotation that identifies this class as being a contract. Can - * supply information and an alternative name for the contract rather than the - * classname + * Class level annotation that identifies this class as being a contract. Can supply information and an alternative name + * for the contract rather than the classname */ @Retention(RUNTIME) @Target(ElementType.TYPE) public @interface Contract { /** - * The Info object can be supplied to provide additional information about the - * contract. + * The Info object can be supplied to provide additional information about the contract. * - * Including title, description, version and license + *

Including title, description, version and license * * @return Info object */ @@ -33,8 +31,8 @@ /** * Contract name. * - * Normally the name of the class is used to refer to the contract (name without - * package). This can be altered if wished. + *

Normally the name of the class is used to refer to the contract (name without package). This can be altered if + * wished. * * @return Name of the contract to be used instead of the Classname */ @@ -43,14 +41,12 @@ /** * Transaction Serializer Classname. * - * Fully Qualified Classname of the TRANSACTION serializer that should be used - * with this contract. + *

Fully Qualified Classname of the TRANSACTION serializer that should be used with this contract. * - * This is the serializer that is used to parse incoming transaction request - * parameters and convert the return type + *

This is the serializer that is used to parse incoming transaction request parameters and convert the return + * type * * @return Default serializer classname */ String transactionSerializer() default "org.hyperledger.fabric.contract.execution.JSONTransactionSerializer"; - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java index 8799198d..a671fcf0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/DataType.java @@ -12,18 +12,15 @@ import java.lang.annotation.Target; /** - * Class level annotation indicating this class represents one of the complex - * types that can be returned or passed to the transaction functions. - *

- * These datatypes are used (within the current implementation) for determining - * the data flow protocol from the Contracts to the SDK and for permitting a - * fully formed Interface Definition to be created for the contract. - *

- * Complex types can appear within this definition, and these are identified - * using this annotation. - *

- * FUTURE To take these annotations are also utilize them for leverage - * storage + * Class level annotation indicating this class represents one of the complex types that can be returned or passed to + * the transaction functions. + * + *

These datatypes are used (within the current implementation) for determining the data flow protocol from the + * Contracts to the SDK and for permitting a fully formed Interface Definition to be created for the contract. + * + *

Complex types can appear within this definition, and these are identified using this annotation. + * + *

FUTURE To take these annotations are also utilize them for leverage storage */ @Retention(RUNTIME) @Target(ElementType.TYPE) diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java index 683ba668..f289e56a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Default.java @@ -14,11 +14,9 @@ /** * Default Contract. * - * Class level annotation that defines the contract that is the default - * contract, and as such invoke of the transaction functions does not need to be - * qualified by the contract name + *

Class level annotation that defines the contract that is the default contract, and as such invoke of the + * transaction functions does not need to be qualified by the contract name */ @Retention(RUNTIME) @Target(ElementType.TYPE) -public @interface Default { -} +public @interface Default {} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java index 8b1d05fd..17d02e16 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Info.java @@ -15,41 +15,29 @@ /** * Info Details * - * - * Class level annotation that identifies this class as being an info object. - * Can supply additional information about the contract, including title, - * description, version, license and contact information. - * + *

Class level annotation that identifies this class as being an info object. Can supply additional information about + * the contract, including title, description, version, license and contact information. */ @Retention(RUNTIME) @Target(ElementType.TYPE) public @interface Info { - /** - * @return String - */ + /** @return String */ String title() default ""; - /** - * @return String - */ + /** @return String */ String description() default ""; - /** - * @return String - */ + /** @return String */ String version() default ""; - /** - * @return String - */ + /** @return String */ String termsOfService() default ""; /** * License object that can be populated to include name and url. * * @return License object - * */ License license() default @License(); @@ -57,8 +45,6 @@ * Contact object that can be populated with email, name and url fields. * * @return Contact object - * */ Contact contact() default @Contact(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java index 88989f02..a585f634 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/License.java @@ -12,24 +12,16 @@ import java.lang.annotation.Target; /** - * Class level annotation that identifies this class as being a license object. - * Can be populated to include name and url. - * + * Class level annotation that identifies this class as being a license object. Can be populated to include name and + * url. */ @Retention(RUNTIME) @Target(ElementType.TYPE) public @interface License { - /** - * - * @return String - */ + /** @return String */ String name() default ""; - /** - * - * @return String - */ + /** @return String */ String url() default ""; - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java index 1b75fffb..5a94e8dc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Property.java @@ -14,10 +14,9 @@ /** * Field and parameter level annotation defining a property of the class. * - * (identified by {@link DataType}) Can also be used on the parameters of - * transaction functions - *

- * Example of using this annotation + *

(identified by {@link DataType}) Can also be used on the parameters of transaction functions + * + *

Example of using this annotation * *

  *
@@ -36,9 +35,8 @@
 public @interface Property {
 
     /**
-     * Allows each property to be defined a detail set of rules to determine the
-     * valid types of this data. The format follows the syntax of the OpenAPI Schema
-     * object.
+     * Allows each property to be defined a detail set of rules to determine the valid types of this data. The format
+     * follows the syntax of the OpenAPI Schema object.
      *
      * @return String array of the key-value pairs of the schema
      */
diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Serializer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Serializer.java
index 10ff45d6..37d91fc9 100644
--- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Serializer.java
+++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Serializer.java
@@ -12,32 +12,22 @@
 import java.lang.annotation.Target;
 
 /**
- * Class level annotation that defines the serializer that should be used to
- * convert objects to and from the wire format.
+ * Class level annotation that defines the serializer that should be used to convert objects to and from the wire
+ * format.
  *
- * 

This should annotate a class that implements the Serializer interface

+ *

This should annotate a class that implements the Serializer interface */ @Retention(RUNTIME) @Target({ElementType.TYPE, ElementType.TYPE_USE}) public @interface Serializer { - /** - * What is this serializer able to target? - * - */ + /** What is this serializer able to target? */ enum TARGET { - /** - * Target transaction functions. - */ + /** Target transaction functions. */ TRANSACTION, - /** - * Target all elements. - */ + /** Target all elements. */ ALL } - /** - * - * @return Target of the serializer - */ + /** @return Target of the serializer */ TARGET target() default Serializer.TARGET.ALL; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java index c9180ca4..3f41e3fb 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/annotation/Transaction.java @@ -12,44 +12,35 @@ import java.lang.annotation.Target; /** - * Method level annotation indicating the method to be a callable transaction - * function. - *

- * These functions are called in client SDKs by the combination of + * Method level annotation indicating the method to be a callable transaction function. + * + *

These functions are called in client SDKs by the combination of * *

  *  [contractname]:[transactioname]
  * 
* - * Unless specified otherwise, the contract name is the class name (without - * package) and the transaction name is the method name. + * Unless specified otherwise, the contract name is the class name (without package) and the transaction name is the + * method name. */ @Retention(RUNTIME) @Target(METHOD) public @interface Transaction { - /** - * The intended invocation style for a transaction function. - */ + /** The intended invocation style for a transaction function. */ enum TYPE { - /** - * Transaction is used to submit updates to the ledger. - */ + /** Transaction is used to submit updates to the ledger. */ SUBMIT, - /** - * Transaction is evaluated to query information from the ledger. - */ + /** Transaction is evaluated to query information from the ledger. */ EVALUATE } /** * Submit semantics. * - *

TRUE indicates that this function is intended to be called with the 'submit' - * semantics

+ *

TRUE indicates that this function is intended to be called with the 'submit' semantics * - *

FALSE indicates that this is intended to be called with the evaluate - * semantics

+ *

FALSE indicates that this is intended to be called with the evaluate semantics * * @return boolean, default is true * @deprecated Please use intent @@ -59,19 +50,20 @@ enum TYPE { /** * What are submit semantics for this transaction. + * *

- *
SUBMIT
indicates that this function is intended to be called with the - * 'submit' semantics
- *
EVALUATE
indicates that this is intended to be called - * with the 'evaluate' semantics
+ *
SUBMIT + *
indicates that this function is intended to be called with the 'submit' semantics + *
EVALUATE + *
indicates that this is intended to be called with the 'evaluate' semantics *
+ * * @return submit semantics */ TYPE intent() default Transaction.TYPE.SUBMIT; /** - * The name of the callable transaction if it should be different to the method - * name. + * The name of the callable transaction if it should be different to the method name. * * @return the transaction name */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java index 0d437c5e..fee47eb1 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java @@ -14,9 +14,7 @@ public class ExecutionFactory { private static ExecutionFactory rf; - /** - * @return ExecutionFactory - */ + /** @return ExecutionFactory */ public static ExecutionFactory getInstance() { if (rf == null) { rf = new ExecutionFactory(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java index ef0b9719..8c859680 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java @@ -13,13 +13,11 @@ /** * ExecutionService. * - * Service that executes {@link InvocationRequest} (wrapped Init/Invoke + extra - * data) using routing information + *

Service that executes {@link InvocationRequest} (wrapped Init/Invoke + extra data) using routing information */ public interface ExecutionService { /** - * * @param txFn * @param req * @param stub diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java index 6978e037..92c478c1 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/InvocationRequest.java @@ -11,33 +11,21 @@ /** * Invocation Request. * - * All information needed to find - * {@link org.hyperledger.fabric.contract.annotation.Contract} and invoke the - * request. + *

All information needed to find {@link org.hyperledger.fabric.contract.annotation.Contract} and invoke the request. */ public interface InvocationRequest { - /** - * - */ + /** */ String DEFAULT_NAMESPACE = "default"; - /** - * @return Namespace - */ + /** @return Namespace */ String getNamespace(); - /** - * @return Method - */ + /** @return Method */ String getMethod(); - /** - * @return Args as byte array - */ + /** @return Args as byte array */ List getArgs(); - /** - * @return Request - */ + /** @return Request */ String getRequestName(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java index c7633e53..c1c99591 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java @@ -15,7 +15,6 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; - import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.annotation.Serializer; @@ -27,19 +26,14 @@ import org.json.JSONException; import org.json.JSONObject; -/** - * Used as a the default serialisation for transmission from SDK to Contract. - */ +/** Used as a the default serialisation for transmission from SDK to Contract. */ @Serializer() public class JSONTransactionSerializer implements SerializerInterface { private static Logger logger = Logger.getLogger(JSONTransactionSerializer.class.getName()); private final TypeRegistry typeRegistry = TypeRegistry.getRegistry(); - /** - * Create a new serialiser. - */ - public JSONTransactionSerializer() { - } + /** Create a new serialiser. */ + public JSONTransactionSerializer() {} /** * Convert the value supplied to a byte array, according to the TypeSchema. @@ -56,23 +50,23 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { final String type = ts.getType(); if (type != null) { switch (type) { - case "array": - final JSONArray array = normalizeArray(new JSONArray(value), ts); - buffer = array.toString().getBytes(UTF_8); - break; - case "string": - final String format = ts.getFormat(); - if (format != null && format.contentEquals("uint16")) { - buffer = Character.valueOf((char) value).toString().getBytes(UTF_8); - } else { - buffer = ((String) value).getBytes(UTF_8); - } - break; - case "number": - case "integer": - case "boolean": - default: - buffer = (value).toString().getBytes(UTF_8); + case "array": + final JSONArray array = normalizeArray(new JSONArray(value), ts); + buffer = array.toString().getBytes(UTF_8); + break; + case "string": + final String format = ts.getFormat(); + if (format != null && format.contentEquals("uint16")) { + buffer = Character.valueOf((char) value).toString().getBytes(UTF_8); + } else { + buffer = ((String) value).getBytes(UTF_8); + } + break; + case "number": + case "integer": + case "boolean": + default: + buffer = (value).toString().getBytes(UTF_8); } } else { // at this point we can assert that the value is @@ -102,14 +96,13 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { /** * Normalize the Array. * - * We need to take the JSON array, and if there are complex datatypes within it - * ensure that they don't get spurious JSON properties appearing + *

We need to take the JSON array, and if there are complex datatypes within it ensure that they don't get + * spurious JSON properties appearing * - * This method needs to be general so has to copy with nested arrays and with - * primitive and Object types + *

This method needs to be general so has to copy with nested arrays and with primitive and Object types * * @param jsonArray incoming array - * @param ts Schema to normalise to + * @param ts Schema to normalise to * @return JSONArray */ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) { @@ -143,7 +136,6 @@ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) final JSONObject obj = new JSONObject(jsonArray.getJSONObject(i), propNames); normalizedArray.put(i, obj); } - } return normalizedArray; } @@ -152,8 +144,7 @@ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) * Take the byte buffer and return the object as required. * * @param buffer Byte buffer from the wire - * @param ts TypeSchema representing the type - * + * @param ts TypeSchema representing the type * @return Object created; relies on Java auto-boxing for primitives */ @Override @@ -172,11 +163,10 @@ public Object fromBuffer(final byte[] buffer, final TypeSchema ts) { } /** - * We need to be able to map between the primative class types and the object - * variants. In the case where this is needed Java auto-boxing doesn't actually - * help. + * We need to be able to map between the primative class types and the object variants. In the case where this is + * needed Java auto-boxing doesn't actually help. * - * For other types the parameter is passed directly back + *

For other types the parameter is passed directly back * * @param primitive class for the primitive * @return Class for the Object variant @@ -191,31 +181,32 @@ private Class mapPrimitive(final Class primitive) { } switch (primitiveType) { - case "int": - return isArray ? Integer[].class : Integer.class; - case "long": - return isArray ? Long[].class : Long.class; - case "float": - return isArray ? Float[].class : Float.class; - case "double": - return isArray ? Double[].class : Double.class; - case "short": - return isArray ? Short[].class : Short.class; - case "byte": - return isArray ? Byte[].class : Byte.class; - case "char": - return isArray ? Character[].class : Character.class; - case "boolean": - return isArray ? Boolean[].class : Boolean.class; - default: - return primitive; + case "int": + return isArray ? Integer[].class : Integer.class; + case "long": + return isArray ? Long[].class : Long.class; + case "float": + return isArray ? Float[].class : Float.class; + case "double": + return isArray ? Double[].class : Double.class; + case "short": + return isArray ? Short[].class : Short.class; + case "byte": + return isArray ? Byte[].class : Byte.class; + case "char": + return isArray ? Character[].class : Character.class; + case "boolean": + return isArray ? Boolean[].class : Boolean.class; + default: + return primitive; } } /* * Internal method to do the conversion */ - private Object convert(final String stringData, final TypeSchema ts) throws IllegalArgumentException, IllegalAccessException, InstantiationException { + private Object convert(final String stringData, final TypeSchema ts) + throws IllegalArgumentException, IllegalAccessException, InstantiationException { logger.debug(() -> "Schema to convert is " + ts); String type = ts.getType(); String format = null; @@ -236,20 +227,20 @@ private Object convert(final String stringData, final TypeSchema ts) throws Ille } else if (type.contentEquals("integer")) { final String intFormat = ts.getFormat(); switch (intFormat) { - case "int32": - value = Integer.parseInt(stringData); - break; - case "int8": - value = Byte.parseByte(stringData); - break; - case "int16": - value = Short.parseShort(stringData); - break; - case "int64": - value = Long.parseLong(stringData); - break; - default: - throw new RuntimeException("Unknown format for integer " + intFormat); + case "int32": + value = Integer.parseInt(stringData); + break; + case "int8": + value = Byte.parseByte(stringData); + break; + case "int16": + value = Short.parseShort(stringData); + break; + case "int64": + value = Long.parseLong(stringData); + break; + default: + throw new RuntimeException("Unknown format for integer " + intFormat); } } else if (type.contentEquals("number")) { @@ -268,13 +259,13 @@ private Object convert(final String stringData, final TypeSchema ts) throws Ille final TypeSchema itemSchema = ts.getItems(); // note here that the type has to be converted in the case of primitives - final Object[] data = (Object[]) Array.newInstance(mapPrimitive(itemSchema.getTypeClass(this.typeRegistry)), jsonArray.length()); + final Object[] data = (Object[]) + Array.newInstance(mapPrimitive(itemSchema.getTypeClass(this.typeRegistry)), jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { final Object convertedData = convert(jsonArray.get(i).toString(), itemSchema); data[i] = convertedData; } value = data; - } return value; } @@ -282,9 +273,9 @@ private Object convert(final String stringData, final TypeSchema ts) throws Ille /** * Create new instance of the specificied object from the supplied JSON String. * - * @param format Details of the format needed + * @param format Details of the format needed * @param jsonString JSON string - * @param ts TypeSchema + * @param ts TypeSchema * @return new object */ Object createComponentInstance(final String format, final String jsonString, final TypeSchema ts) { @@ -293,7 +284,10 @@ Object createComponentInstance(final String format, final String jsonString, fin Object obj; try { obj = dtd.getTypeClass().getDeclaredConstructor().newInstance(); - } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e1) { + } catch (IllegalAccessException + | InstantiationException + | InvocationTargetException + | NoSuchMethodException e1) { throw new ContractRuntimeException("Unable to to create new instance of type", e1); } @@ -302,7 +296,7 @@ Object createComponentInstance(final String format, final String jsonString, fin ts.validate(json); try { final Map fields = dtd.getProperties(); - for (final Iterator iterator = fields.values().iterator(); iterator.hasNext();) { + for (final Iterator iterator = fields.values().iterator(); iterator.hasNext(); ) { final PropertyDefinition prop = iterator.next(); final Field f = prop.getField(); @@ -310,12 +304,14 @@ Object createComponentInstance(final String format, final String jsonString, fin final Object newValue = convert(json.get(prop.getName()).toString(), prop.getSchema()); f.set(obj, newValue); - } return obj; - } catch (SecurityException | IllegalArgumentException | IllegalAccessException | InstantiationException | JSONException e) { + } catch (SecurityException + | IllegalArgumentException + | IllegalAccessException + | InstantiationException + | JSONException e) { throw new ContractRuntimeException("Unable to convert JSON to object", e); } - } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/SerializerInterface.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/SerializerInterface.java index ed5cc584..f52d87d0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/SerializerInterface.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/SerializerInterface.java @@ -9,15 +9,13 @@ import org.hyperledger.fabric.contract.metadata.TypeSchema; /** - * This interface allows contract developers to change the serialization - * mechanism. There are two scenarios where instances of DataTypes are - * serialized. + * This interface allows contract developers to change the serialization mechanism. There are two scenarios where + * instances of DataTypes are serialized. * - * When the objects are (logically) transferred from the Client application to - * the Contract resulting in a transaction function being invoked. Typically this - * is JSON, hence a default JSON parser is provided. + *

When the objects are (logically) transferred from the Client application to the Contract resulting in a + * transaction function being invoked. Typically this is JSON, hence a default JSON parser is provided. * - * The JSONTransactionSerializer can be extended if needed + *

The JSONTransactionSerializer can be extended if needed */ public interface SerializerInterface { @@ -34,10 +32,8 @@ public interface SerializerInterface { * Take the byte buffer and return the object as required. * * @param buffer Byte buffer from the wire - * @param ts TypeSchema representing the type - * + * @param ts TypeSchema representing the type * @return Object created; relies on Java auto-boxing for primitives */ Object fromBuffer(byte[] buffer, TypeSchema ts); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java index e9611107..b8803269 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java @@ -6,7 +6,11 @@ package org.hyperledger.fabric.contract.execution.impl; - import org.hyperledger.fabric.contract.Context; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; +import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.contract.annotation.Serializer; @@ -22,29 +26,21 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.hyperledger.fabric.shim.ResponseUtils; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - public class ContractExecutionService implements ExecutionService { private static Logger logger = Logger.getLogger(ContractExecutionService.class.getName()); private final SerializerRegistryImpl serializers; - /** - * @param serializers - */ + /** @param serializers */ public ContractExecutionService(final SerializerRegistryImpl serializers) { this.serializers = serializers; } - /** - * - */ + /** */ @Override - public Chaincode.Response executeRequest(final TxFunction txFn, final InvocationRequest req, final ChaincodeStub stub) { + public Chaincode.Response executeRequest( + final TxFunction txFn, final InvocationRequest req, final ChaincodeStub stub) { logger.fine(() -> "Routing Request" + txFn); final TxFunction.Routing rd = txFn.getRouting(); Chaincode.Response response; @@ -83,21 +79,22 @@ public Chaincode.Response executeRequest(final TxFunction txFn, final Invocation } private byte[] convertReturn(final Object obj, final TxFunction txFn) { - final SerializerInterface serializer = serializers.getSerializer( - txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION); + final SerializerInterface serializer = + serializers.getSerializer(txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION); final TypeSchema ts = txFn.getReturnSchema(); return serializer.toBuffer(obj, ts); } private List convertArgs(final List stubArgs, final TxFunction txFn) { - final SerializerInterface serializer = serializers.getSerializer( - txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION); + final SerializerInterface serializer = + serializers.getSerializer(txFn.getRouting().getSerializerName(), Serializer.TARGET.TRANSACTION); final List schemaParams = txFn.getParamsList(); final List args = new ArrayList<>(stubArgs.size() + 1); // allow for context as the first argument for (int i = 0; i < schemaParams.size(); i++) { - args.add(i, serializer.fromBuffer(stubArgs.get(i), schemaParams.get(i).getSchema())); + args.add( + i, + serializer.fromBuffer(stubArgs.get(i), schemaParams.get(i).getSchema())); } return args; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java index a2b9d9e9..a63d2ffc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java @@ -9,7 +9,6 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperledger.fabric.contract.execution.InvocationRequest; @@ -22,11 +21,10 @@ public class ContractInvocationRequest implements InvocationRequest { private static Log logger = LogFactory.getLog(ContractInvocationRequest.class); - /** - * @param context - */ + /** @param context */ public ContractInvocationRequest(final ChaincodeStub context) { - final String func = context.getStringArgs().size() > 0 ? context.getStringArgs().get(0) : null; + final String func = + context.getStringArgs().size() > 0 ? context.getStringArgs().get(0) : null; final String[] funcParts = func.split(":"); logger.debug(func); if (funcParts.length == 2) { @@ -41,44 +39,33 @@ public ContractInvocationRequest(final ChaincodeStub context) { logger.debug(namespace + " " + method + " " + args); } - /** - * - */ + /** */ @Override public String getNamespace() { return namespace; } - /** - * - */ + /** */ @Override public String getMethod() { return method; } - /** - * - */ + /** */ @Override public List getArgs() { return args; } - /** - * - */ + /** */ @Override public String getRequestName() { return namespace + ":" + method; } - /** - * - */ + /** */ @Override public String toString() { return namespace + ":" + method + " @" + Integer.toHexString(System.identityHashCode(this)); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/package-info.java index dd93d90a..b708841f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.execution.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/package-info.java index 2c9651ad..4fa00279 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.execution; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java index 6b1830db..c7b5d0c0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java @@ -17,7 +17,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; - import org.everit.json.schema.Schema; import org.everit.json.schema.ValidationException; import org.everit.json.schema.loader.SchemaClient; @@ -37,17 +36,14 @@ /** * Builder to assist in production of the metadata. - *

- * This class is used to build up the JSON structure to be returned as the - * metadata It is not a store of information, rather a set of functional data to - * process to and from metadata json to the internal data structure + * + *

This class is used to build up the JSON structure to be returned as the metadata It is not a store of information, + * rather a set of functional data to process to and from metadata json to the internal data structure */ public final class MetadataBuilder { private static Logger logger = Logger.getLogger(MetadataBuilder.class); - private MetadataBuilder() { - - } + private MetadataBuilder() {} @SuppressWarnings("serial") static class MetadataMap extends HashMap { @@ -83,8 +79,11 @@ public static void validate() { InputStream jsonSchemaInputStream = cl.getResourceAsStream("json-schema-draft-04-schema.json")) { final JSONObject rawContractSchema = new JSONObject(new JSONTokener(contractSchemaInputStream)); final JSONObject rawJsonSchema = new JSONObject(new JSONTokener(jsonSchemaInputStream)); - final SchemaLoader schemaLoader = SchemaLoader.builder().schemaClient(schemaClient).schemaJson(rawContractSchema) - .registerSchemaByURI(URI.create("http://json-schema.org/draft-04/schema"), rawJsonSchema).build(); + final SchemaLoader schemaLoader = SchemaLoader.builder() + .schemaClient(schemaClient) + .schemaJson(rawContractSchema) + .registerSchemaByURI(URI.create("http://json-schema.org/draft-04/schema"), rawJsonSchema) + .build(); final Schema schema = schemaLoader.load().build(); schema.validate(metadata()); @@ -92,17 +91,18 @@ public static void validate() { throw new RuntimeException(e); } catch (final ValidationException e) { logger.error(e.getMessage()); - e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(logger::info); + e.getCausingExceptions().stream() + .map(ValidationException::getMessage) + .forEach(logger::info); logger.error(debugString()); throw e; } - } /** * Setup the metadata from the found contracts. * - * @param registry RoutingRegistry + * @param registry RoutingRegistry * @param typeRegistry TypeRegistry */ public static void initialize(final RoutingRegistry registry, final TypeRegistry typeRegistry) { @@ -117,7 +117,6 @@ public static void initialize(final RoutingRegistry registry, final TypeRegistry // check logger.info("Validating schema created"); MetadataBuilder.validate(); - } /** @@ -195,7 +194,7 @@ public static String addContract(final ContractDefinition contractDefinition) { /** * Adds a new transaction function to the metadata for the given contract. * - * @param txFunction Object representing the transaction function + * @param txFunction Object representing the transaction function * @param contractName Name of the contract that this function belongs to */ public static void addTransaction(final TxFunction txFunction, final String contractName) { @@ -270,10 +269,7 @@ private static JSONObject metadata() { return joMetadata; } - /** - * - * @return All the components indexed by name - */ + /** @return All the components indexed by name */ public static Map getComponents() { return componentMap; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java index 213fb83d..79453428 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java @@ -9,7 +9,6 @@ import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; - import org.everit.json.schema.Schema; import org.everit.json.schema.ValidationException; import org.everit.json.schema.loader.SchemaLoader; @@ -19,24 +18,18 @@ import org.json.JSONObject; /** - * * TypeSchema. * - * Custom sub-type of Map that helps with the case where if there's no value - * then do not insert the property at all + *

Custom sub-type of Map that helps with the case where if there's no value then do not insert the property at all * - * Does not include the "schema" top level map + *

Does not include the "schema" top level map */ @SuppressWarnings("serial") public final class TypeSchema extends HashMap { private static Logger logger = Logger.getLogger(TypeSchema.class.getName()); - /** - * - */ - public TypeSchema() { - - } + /** */ + public TypeSchema() {} private Object putInternal(final String key, final Object value) { if (value != null && !value.toString().isEmpty()) { @@ -62,10 +55,7 @@ TypeSchema[] putIfNotNull(final String key, final TypeSchema[] value) { return (TypeSchema[]) this.putInternal(key, value); } - /** - * - * @return Return Type String - */ + /** @return Return Type String */ public String getType() { if (this.containsKey("schema")) { final Map intermediateMap = (Map) this.get("schema"); @@ -74,10 +64,7 @@ public String getType() { return (String) this.get("type"); } - /** - * - * @return TypeSchema items - */ + /** @return TypeSchema items */ public TypeSchema getItems() { if (this.containsKey("schema")) { final Map intermediateMap = (Map) this.get("schema"); @@ -86,23 +73,16 @@ public TypeSchema getItems() { return (TypeSchema) this.get("items"); } - /** - * - * @return Reference - */ + /** @return Reference */ public String getRef() { if (this.containsKey("schema")) { final Map intermediateMap = (Map) this.get("schema"); return (String) intermediateMap.get("$ref"); } return (String) this.get("$ref"); - } - /** - * - * @return Format - */ + /** @return Format */ public String getFormat() { if (this.containsKey("schema")) { final Map intermediateMap = (Map) this.get("schema"); @@ -112,7 +92,6 @@ public String getFormat() { } /** - * * @param typeRegistry * @return Class object */ @@ -135,33 +114,33 @@ public Class getTypeClass(final TypeRegistry typeRegistry) { // need to check the format final String format = getFormat(); switch (format) { - case "int8": - clz = byte.class; - break; - case "int16": - clz = short.class; - break; - case "int32": - clz = int.class; - break; - case "int64": - clz = long.class; - break; - default: - throw new RuntimeException("Unknown format for integer of " + format); + case "int8": + clz = byte.class; + break; + case "int16": + clz = short.class; + break; + case "int32": + clz = int.class; + break; + case "int64": + clz = long.class; + break; + default: + throw new RuntimeException("Unknown format for integer of " + format); } } else if (type.contentEquals("number")) { // need to check the format final String format = getFormat(); switch (format) { - case "double": - clz = double.class; - break; - case "float": - clz = float.class; - break; - default: - throw new RuntimeException("Unknown format for number of " + format); + case "double": + clz = double.class; + break; + case "float": + clz = float.class; + break; + default: + throw new RuntimeException("Unknown format for number of " + format); } } else if (type.contentEquals("boolean")) { clz = boolean.class; @@ -183,7 +162,6 @@ public Class getTypeClass(final TypeRegistry typeRegistry) { * * @param clz * @return TypeSchema - * */ public static TypeSchema typeConvert(final Class clz) { final TypeSchema returnschema = new TypeSchema(); @@ -213,61 +191,60 @@ public static TypeSchema typeConvert(final Class clz) { } switch (className) { - case "java.lang.String": - schema.put("type", "string"); - break; - case "char": - case "java.lang.Character": - schema.put("type", "string"); - schema.put("format", "uint16"); - break; - case "byte": - case "java.lang.Byte": - schema.put("type", "integer"); - schema.put("format", "int8"); - break; - case "short": - case "java.lang.Short": - schema.put("type", "integer"); - schema.put("format", "int16"); - break; - case "int": - case "java.lang.Integer": - schema.put("type", "integer"); - schema.put("format", "int32"); - break; - case "long": - case "java.lang.Long": - schema.put("type", "integer"); - schema.put("format", "int64"); - break; - case "double": - case "java.lang.Double": - schema.put("type", "number"); - schema.put("format", "double"); - break; - case "float": - case "java.lang.Float": - schema.put("type", "number"); - schema.put("format", "float"); - break; - case "boolean": - case "java.lang.Boolean": - schema.put("type", "boolean"); - break; - default: - schema.put("$ref", "#/components/schemas/" + className.substring(className.lastIndexOf('.') + 1)); + case "java.lang.String": + schema.put("type", "string"); + break; + case "char": + case "java.lang.Character": + schema.put("type", "string"); + schema.put("format", "uint16"); + break; + case "byte": + case "java.lang.Byte": + schema.put("type", "integer"); + schema.put("format", "int8"); + break; + case "short": + case "java.lang.Short": + schema.put("type", "integer"); + schema.put("format", "int16"); + break; + case "int": + case "java.lang.Integer": + schema.put("type", "integer"); + schema.put("format", "int32"); + break; + case "long": + case "java.lang.Long": + schema.put("type", "integer"); + schema.put("format", "int64"); + break; + case "double": + case "java.lang.Double": + schema.put("type", "number"); + schema.put("format", "double"); + break; + case "float": + case "java.lang.Float": + schema.put("type", "number"); + schema.put("format", "float"); + break; + case "boolean": + case "java.lang.Boolean": + schema.put("type", "boolean"); + break; + default: + schema.put("$ref", "#/components/schemas/" + className.substring(className.lastIndexOf('.') + 1)); } return returnschema; } - - /** - * Validates the object against this schema. - * - * @param obj - */ + /** + * Validates the object against this schema. + * + * @param obj + */ public void validate(final JSONObject obj) { // get the components bit of the main metadata @@ -289,11 +266,11 @@ public void validate(final JSONObject obj) { schema.validate(toValidate); } catch (final ValidationException e) { final StringBuilder sb = new StringBuilder("Validation Errors::"); - e.getCausingExceptions().stream().map(ValidationException::getMessage).forEach(sb::append); + e.getCausingExceptions().stream() + .map(ValidationException::getMessage) + .forEach(sb::append); logger.info(sb.toString()); throw new ContractRuntimeException(sb.toString(), e); } - } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/package-info.java index 743c7b04..d02326ec 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.metadata; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java index 5185aedb..24dbf8be 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/package-info.java @@ -7,15 +7,10 @@ /** * Provides interfaces and classes to support the contract programming model. * - *

- * The {@link org.hyperledger.fabric.contract} package implements the Fabric - * programming model as described in the Developing + *

The {@link org.hyperledger.fabric.contract} package implements the Fabric programming model as described in the Developing * Applications chapter of the Fabric documentation. * - *

- * The main interface to implement is - * {@link org.hyperledger.fabric.contract.ContractInterface} - * + *

The main interface to implement is {@link org.hyperledger.fabric.contract.ContractInterface} */ package org.hyperledger.fabric.contract; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java index ba8072cb..4bca0f44 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ContractDefinition.java @@ -8,77 +8,56 @@ import java.lang.reflect.Method; import java.util.Collection; - import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.annotation.Contract; /** * Definition of the Contract * - * A data structure that represents the contract that will be executed in the - * chaincode. Primarily has + *

A data structure that represents the contract that will be executed in the chaincode. Primarily has * - * Name - either defined by the Contract annotation or the Class name (can be - * referred to as Namespace) Default - is the default contract (defined by the - * Default annotation) TxFunctions in this contract do not need the name prefix + *

Name - either defined by the Contract annotation or the Class name (can be referred to as Namespace) Default - is + * the default contract (defined by the Default annotation) TxFunctions in this contract do not need the name prefix * when invoked TxFunctions - the transaction functions defined in this contract * - * Will embedded the ContractInterface instance, as well as the annotation - * itself, and the routing for any tx function that is unknown - * + *

Will embedded the ContractInterface instance, as well as the annotation itself, and the routing for any tx + * function that is unknown */ public interface ContractDefinition { - /** - * @return the fully qualified name of the Contract - */ + /** @return the fully qualified name of the Contract */ String getName(); - /** - * @return Complete collection of all the transaction functions in this contract - */ + /** @return Complete collection of all the transaction functions in this contract */ Collection getTxFunctions(); - /** - * @return Object reference to the instantiated object that is 'the contract' - */ + /** @return Object reference to the instantiated object that is 'the contract' */ Class getContractImpl(); /** - * @param m The java.lang.reflect object that is the method that is a tx - * function + * @param m The java.lang.reflect object that is the method that is a tx function * @return TxFunction object representing this method */ TxFunction addTxFunction(Method m); - /** - * - * @return if this is contract is the default one or not - */ + /** @return if this is contract is the default one or not */ boolean isDefault(); /** - * * @param method name to be returned * @return TxFunction that represents this requested method */ TxFunction getTxFunction(String method); /** - * * @param method name to be checked * @return true if this txFunction exists or not */ boolean hasTxFunction(String method); - /** - * @return The TxFunction to be used for this contract in case of unknown - * request - */ + /** @return The TxFunction to be used for this contract in case of unknown request */ TxFunction getUnknownRoute(); - /** - * @return Underlying raw annotation - */ + /** @return Underlying raw annotation */ Contract getAnnotation(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java index 3267a718..84d2e3fb 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/DataTypeDefinition.java @@ -6,33 +6,22 @@ package org.hyperledger.fabric.contract.routing; import java.util.Map; - import org.hyperledger.fabric.contract.metadata.TypeSchema; public interface DataTypeDefinition { - /** - * @return String - */ + /** @return String */ String getName(); - /** - * @return Map of String to PropertyDefinitions - */ + /** @return Map of String to PropertyDefinitions */ Map getProperties(); - /** - * @return String - */ + /** @return String */ String getSimpleName(); - /** - * @return Class object of the type - */ + /** @return Class object of the type */ Class getTypeClass(); - /** - * @return TypeSchema - */ + /** @return TypeSchema */ TypeSchema getSchema(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java index bc81c234..2411e6aa 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/ParameterDefinition.java @@ -6,29 +6,19 @@ package org.hyperledger.fabric.contract.routing; import java.lang.reflect.Parameter; - import org.hyperledger.fabric.contract.metadata.TypeSchema; public interface ParameterDefinition { - /** - * @return Class type of the parameter - */ + /** @return Class type of the parameter */ Class getTypeClass(); - /** - * @return TypeSchema of the parameter - */ + /** @return TypeSchema of the parameter */ TypeSchema getSchema(); - /** - * @return Parameter - */ + /** @return Parameter */ Parameter getParameter(); - /** - * @return name of the parameter - */ + /** @return name of the parameter */ String getName(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java index dd4e7e37..4c53cdc7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/PropertyDefinition.java @@ -6,29 +6,19 @@ package org.hyperledger.fabric.contract.routing; import java.lang.reflect.Field; - import org.hyperledger.fabric.contract.metadata.TypeSchema; public interface PropertyDefinition { - /** - * @return Class of the Property - */ + /** @return Class of the Property */ Class getTypeClass(); - /** - * @return TypeSchema - */ + /** @return TypeSchema */ TypeSchema getSchema(); - /** - * @return Field - */ + /** @return Field */ Field getField(); - /** - * @return Name of the property - */ + /** @return Name of the property */ String getName(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java index 3c4e9825..264ff9b2 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/RoutingRegistry.java @@ -6,7 +6,6 @@ package org.hyperledger.fabric.contract.routing; import java.util.Collection; - import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.execution.InvocationRequest; @@ -65,5 +64,4 @@ public interface RoutingRegistry { * @param typeRegistry */ void findAndSetContracts(TypeRegistry typeRegistry); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java index 80472df5..37e307b7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TransactionType.java @@ -6,24 +6,14 @@ package org.hyperledger.fabric.contract.routing; public enum TransactionType { - /** - * - */ - INVOKE, //deprecated - /** - * - */ - QUERY, //deprecated - /** - * - */ - DEFAULT, //deprecated - /** - * - */ + /** */ + INVOKE, // deprecated + /** */ + QUERY, // deprecated + /** */ + DEFAULT, // deprecated + /** */ SUBMIT, - /** - * - */ + /** */ EVALUATE } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java index 860e2278..392419fa 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TxFunction.java @@ -8,7 +8,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; - import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.metadata.TypeSchema; @@ -17,86 +16,68 @@ public interface TxFunction { interface Routing { /** * Method to route calls to the transaction function. + * * @return a method. */ Method getMethod(); /** * The associated contract class. + * * @return a contract class. */ Class getContractClass(); /** * The associated contract instance. + * * @return a contract. * @throws IllegalAccessException * @throws InstantiationException * @throws InvocationTargetException * @throws NoSuchMethodException */ - ContractInterface getContractInstance() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException; + ContractInterface getContractInstance() + throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException; /** * Name of the serializer used for the transaction function. + * * @return a serializer name. */ String getSerializerName(); } - /** - * @return is this tx to be called when request fn is unknown - */ + /** @return is this tx to be called when request fn is unknown */ boolean isUnknownTx(); - /** - * @param unknown true if the transaction is to be called when the request fn is unknown; otherwise false. - */ + /** @param unknown true if the transaction is to be called when the request fn is unknown; otherwise false. */ void setUnknownTx(boolean unknown); - /** - * @return Name - */ + /** @return Name */ String getName(); - /** - * @return Routing object - */ + /** @return Routing object */ Routing getRouting(); - /** - * @return Class of the return type - */ + /** @return Class of the return type */ Class getReturnType(); - /** - * @return Parameter array - */ + /** @return Parameter array */ java.lang.reflect.Parameter[] getParameters(); - /** - * @return Submit or Evaluate - */ + /** @return Submit or Evaluate */ TransactionType getType(); - /** - * @param returnSchema - */ + /** @param returnSchema */ void setReturnSchema(TypeSchema returnSchema); - /** - * @return TypeSchema of the return type - */ + /** @return TypeSchema of the return type */ TypeSchema getReturnSchema(); - /** - * @param list - */ + /** @param list */ void setParameterDefinitions(List list); - /** - * @return List of parameters - */ + /** @return List of parameters */ List getParamsList(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java index 73271956..4b61e2d4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/TypeRegistry.java @@ -6,27 +6,20 @@ package org.hyperledger.fabric.contract.routing; import java.util.Collection; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; public interface TypeRegistry { - /** - * @return TypeRegistry - */ + /** @return TypeRegistry */ static TypeRegistry getRegistry() { return TypeRegistryImpl.getInstance(); } - /** - * @param dtd - */ + /** @param dtd */ void addDataType(DataTypeDefinition dtd); - /** - * @param cl - */ + /** @param cl */ void addDataType(Class cl); /** @@ -41,9 +34,6 @@ static TypeRegistry getRegistry() { */ DataTypeDefinition getDataType(TypeSchema schema); - /** - * @return All datatypes - */ + /** @return All datatypes */ Collection getAllDataTypes(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java index 09a293fc..056b3abc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; - import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; @@ -22,9 +21,7 @@ /** * Implementation of the ContractDefinition. * - * Contains information about the contract, including transaction functions and - * unknown transaction routing - * + *

Contains information about the contract, including transaction functions and unknown transaction routing */ public final class ContractDefinitionImpl implements ContractDefinition { private static Logger logger = Logger.getLogger(ContractDefinitionImpl.class); @@ -36,10 +33,7 @@ public final class ContractDefinitionImpl implements ContractDefinition { private final Contract contractAnnotation; private TxFunction unknownTx; - /** - * - * @param cl - */ + /** @param cl */ public ContractDefinitionImpl(final Class cl) { final Contract annotation = cl.getAnnotation(Contract.class); @@ -62,7 +56,8 @@ public ContractDefinitionImpl(final Class cl) { unknownTx = new TxFunctionImpl(m, this); unknownTx.setUnknownTx(true); } catch (NoSuchMethodException | SecurityException e) { - final ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTransaction method", e); + final ContractRuntimeException cre = + new ContractRuntimeException("Failure to find unknownTransaction method", e); logger.severe(() -> logger.formatError(cre)); throw cre; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java index 78c2b9a1..5165bfbf 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java @@ -9,7 +9,6 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; - import org.hyperledger.fabric.contract.annotation.Property; import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.DataTypeDefinition; @@ -22,10 +21,7 @@ public final class DataTypeDefinitionImpl implements DataTypeDefinition { private final String simpleName; private final Class clazz; - /** - * - * @param componentClass - */ + /** @param componentClass */ public DataTypeDefinitionImpl(final Class componentClass) { this.clazz = componentClass; this.name = componentClass.getName(); @@ -44,20 +40,22 @@ public DataTypeDefinitionImpl(final Class componentClass) { final String userKey = userSupplied[i]; Object userValue; switch (userKey.toLowerCase()) { - case "title": - case "pattern": - userValue = userSupplied[i + 1]; - break; - case "uniqueitems": - userValue = Boolean.parseBoolean(userSupplied[i + 1]); - break; - case "required": - case "enum": - userValue = Stream.of(userSupplied[i + 1].split(",")).map(String::trim).toArray(String[]::new); - break; - default: - userValue = Integer.parseInt(userSupplied[i + 1]); - break; + case "title": + case "pattern": + userValue = userSupplied[i + 1]; + break; + case "uniqueitems": + userValue = Boolean.parseBoolean(userSupplied[i + 1]); + break; + case "required": + case "enum": + userValue = Stream.of(userSupplied[i + 1].split(",")) + .map(String::trim) + .toArray(String[]::new); + break; + default: + userValue = Integer.parseInt(userSupplied[i + 1]); + break; } ts.put(userKey, userValue); } @@ -66,7 +64,6 @@ public DataTypeDefinitionImpl(final Class componentClass) { this.properties.put(f.getName(), propDef); } } - } @Override @@ -115,5 +112,4 @@ public String getSimpleName() { public String toString() { return this.simpleName + " " + properties; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java index a99765ca..7fa8f6e6 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ParameterDefinitionImpl.java @@ -7,7 +7,6 @@ package org.hyperledger.fabric.contract.routing.impl; import java.lang.reflect.Parameter; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.ParameterDefinition; @@ -19,13 +18,13 @@ public final class ParameterDefinitionImpl implements ParameterDefinition { private final String name; /** - * * @param name * @param typeClass * @param schema * @param p */ - public ParameterDefinitionImpl(final String name, final Class typeClass, final TypeSchema schema, final Parameter p) { + public ParameterDefinitionImpl( + final String name, final Class typeClass, final TypeSchema schema, final Parameter p) { this.typeClass = typeClass; this.schema = schema; this.parameter = p; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java index 5ea83705..f7772d04 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/PropertyDefinitionImpl.java @@ -7,7 +7,6 @@ package org.hyperledger.fabric.contract.routing.impl; import java.lang.reflect.Field; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.PropertyDefinition; @@ -19,7 +18,6 @@ public final class PropertyDefinitionImpl implements PropertyDefinition { private final String name; /** - * * @param name * @param typeClass * @param schema @@ -51,5 +49,4 @@ public Field getField() { public String getName() { return this.name; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java index 084b3280..5996137c 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java @@ -5,6 +5,9 @@ */ package org.hyperledger.fabric.contract.routing.impl; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; @@ -13,7 +16,6 @@ import java.util.List; import java.util.Map; import java.util.Set; - import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; @@ -26,18 +28,12 @@ import org.hyperledger.fabric.contract.routing.TxFunction; import org.hyperledger.fabric.contract.routing.TypeRegistry; -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ScanResult; - /** - * Registry to hold permit access to the routing definitions. This is the - * primary internal data structure to permit access to information about the - * contracts, and their transaction functions. - * - * Contracts are added, and processed. At runtime, this can then be accessed to - * locate a specific 'Route' that can be handed off to the ExecutionService + * Registry to hold permit access to the routing definitions. This is the primary internal data structure to permit + * access to information about the contracts, and their transaction functions. * + *

Contracts are added, and processed. At runtime, this can then be accessed to locate a specific 'Route' that can be + * handed off to the ExecutionService */ public final class RoutingRegistryImpl implements RoutingRegistry { private static Logger logger = Logger.getLogger(RoutingRegistryImpl.class); @@ -131,7 +127,6 @@ public ContractDefinition getContract(final String namespace) { @Override public Collection getAllDefinitions() { return contracts.values(); - } /* @@ -145,9 +140,7 @@ public Collection getAllDefinitions() { public void findAndSetContracts(final TypeRegistry typeRegistry) { // Find all classes that are valid contract or data type instances. - final ClassGraph classGraph = new ClassGraph() - .enableClassInfo() - .enableAnnotationInfo(); + final ClassGraph classGraph = new ClassGraph().enableClassInfo().enableAnnotationInfo(); final List> contractClasses = new ArrayList<>(); final List> dataTypeClasses = new ArrayList<>(); try (ScanResult scanResult = classGraph.scan()) { @@ -198,7 +191,6 @@ public void findAndSetContracts(final TypeRegistry typeRegistry) { // now need to look for the data types have been set with the dataTypeClasses.forEach(typeRegistry::addDataType); - } private void addContracts(final List> contractClasses) { @@ -217,7 +209,6 @@ private void addContracts(final List> contractClasses) logger.debug("Found annotated method " + m.getName()); contract.addTxFunction(m); - } } @@ -225,5 +216,4 @@ private void addContracts(final List> contractClasses) } } } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java index 74b9a0b8..3e7c1f74 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java @@ -5,35 +5,29 @@ */ package org.hyperledger.fabric.contract.routing.impl; +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.ScanResult; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.annotation.Serializer; import org.hyperledger.fabric.contract.execution.SerializerInterface; -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ScanResult; - /** * Registry to hold permit access to the serializer implementations. * - * It holds the serializers that have been defined. JSONTransactionSerializer - * is the default. + *

It holds the serializers that have been defined. JSONTransactionSerializer is the default. */ public class SerializerRegistryImpl { private static Logger logger = Logger.getLogger(SerializerRegistryImpl.class); private final Class annotationClass = Serializer.class; - /** - * - */ - public SerializerRegistryImpl() { - } + /** */ + public SerializerRegistryImpl() {} // Could index these by name and or type. private final Map contents = new HashMap<>(); @@ -41,7 +35,7 @@ public SerializerRegistryImpl() { /** * Get a Serializer for the matching fully qualified classname, and the Target. * - * @param name fully qualified classname + * @param name fully qualified classname * @param target the intended target of the serializer * @return Serializer instance */ @@ -50,7 +44,8 @@ public SerializerInterface getSerializer(final String name, final Serializer.TAR return contents.get(key); } - private SerializerInterface add(final String name, final Serializer.TARGET target, final Class clazz) { + private SerializerInterface add( + final String name, final Serializer.TARGET target, final Class clazz) { logger.debug(() -> "Adding new Class " + clazz.getCanonicalName() + " for " + target); try { final String key = name + ":" + target; @@ -78,7 +73,8 @@ public void findAndSetContents() throws InstantiationException, IllegalAccessExc final Set seenClass = new HashSet<>(); try (ScanResult scanResult = classGraph.scan()) { - for (final ClassInfo classInfo : scanResult.getClassesWithAnnotation(this.annotationClass.getCanonicalName())) { + for (final ClassInfo classInfo : + scanResult.getClassesWithAnnotation(this.annotationClass.getCanonicalName())) { logger.debug("Found class with contract annotation: " + classInfo.getName()); try { final Class cls = (Class) classInfo.loadClass(); @@ -94,9 +90,6 @@ public void findAndSetContents() throws InstantiationException, IllegalAccessExc logger.debug("Failed to load class: " + e); } } - } - } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java index b12726d2..3f61350a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java @@ -10,7 +10,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; @@ -42,7 +41,6 @@ public final class RoutingImpl implements Routing { private final String serializerName; /** - * * @param method * @param contract */ @@ -63,7 +61,9 @@ public Class getContractClass() { } @Override - public ContractInterface getContractInstance() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { + public ContractInterface getContractInstance() + throws IllegalAccessException, InstantiationException, InvocationTargetException, + NoSuchMethodException { return clazz.getDeclaredConstructor().newInstance(); } @@ -76,13 +76,12 @@ public String toString() { public String getSerializerName() { return serializerName; } - } /** * New TxFunction Definition Impl. * - * @param m Reflect method object + * @param m Reflect method object * @param contract ContractDefinition this is part of */ public TxFunctionImpl(final Method m, final ContractDefinition contract) { @@ -114,15 +113,15 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { this.returnSchema = TypeSchema.typeConvert(m.getReturnType()); // parameter processing - final List params = new ArrayList( - Arrays.asList(method.getParameters())); + final List params = + new ArrayList(Arrays.asList(method.getParameters())); // validate the first one is a context object if (params.size() == 0) { throw new ContractRuntimeException("First argument should be of type Context"); } else if (!Context.class.isAssignableFrom(params.get(0).getType())) { - throw new ContractRuntimeException( - "First argument should be of type Context " + method.getName() + " " + params.get(0).getType()); + throw new ContractRuntimeException("First argument should be of type Context " + method.getName() + " " + + params.get(0).getType()); } else { params.remove(0); @@ -137,7 +136,8 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { final TypeSchema paramMap = new TypeSchema(); final TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); - final Property annotation = parameter.getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); + final Property annotation = + parameter.getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); if (annotation != null) { final String[] userSupplied = annotation.schema(); for (int i = 0; i < userSupplied.length; i += 2) { @@ -147,8 +147,8 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { paramMap.put("name", parameter.getName()); paramMap.put("schema", schema); - final ParameterDefinition pd = new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), paramMap, - parameter); + final ParameterDefinition pd = + new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), paramMap, parameter); paramsList.add(pd); } } @@ -193,10 +193,7 @@ public List getParamsList() { return paramsList; } - /** - * - * @param paramsList - */ + /** @param paramsList */ public void setParamsList(final ArrayList paramsList) { this.paramsList = paramsList; } @@ -209,7 +206,6 @@ public TypeSchema getReturnSchema() { @Override public void setParameterDefinitions(final List list) { this.paramsList = list; - } @Override @@ -221,5 +217,4 @@ public boolean isUnknownTx() { public void setUnknownTx(final boolean unknown) { this.isUnknownTx = unknown; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java index dc50d3dc..07377c77 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java @@ -8,15 +8,11 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; - import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.DataTypeDefinition; import org.hyperledger.fabric.contract.routing.TypeRegistry; -/** - * Registry to hold the complex data types as defined in the contract. - * - */ +/** Registry to hold the complex data types as defined in the contract. */ public final class TypeRegistryImpl implements TypeRegistry { private static TypeRegistryImpl singletonInstance; @@ -75,5 +71,4 @@ public DataTypeDefinition getDataType(final TypeSchema schema) { final String format = ref.substring(ref.lastIndexOf("/") + 1); return getDataType(format); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/package-info.java index 108f8132..e3d4b1ea 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.routing.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/package-info.java index 32533b45..4ab5847b 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.routing; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java index f2427e22..74fd07ab 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java @@ -12,22 +12,19 @@ import org.hyperledger.fabric.contract.annotation.Transaction; import org.hyperledger.fabric.contract.metadata.MetadataBuilder; -/** - * - */ -@Contract(name = "org.hyperledger.fabric", - info = @Info(title = "Fabric System Contract", description = "Provides information about the contracts within this container")) +/** */ +@Contract( + name = "org.hyperledger.fabric", + info = + @Info( + title = "Fabric System Contract", + description = "Provides information about the contracts within this container")) public final class SystemContract implements ContractInterface { - /** - * - */ - public SystemContract() { - - } + /** */ + public SystemContract() {} /** - * * @param ctx * @return Metadata */ @@ -36,5 +33,4 @@ public String getMetadata(final Context ctx) { final String jsonmetadata = MetadataBuilder.getMetadata(); return jsonmetadata; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/package-info.java index 5dcfe058..cde12bb0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.contract.systemcontract; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java index 195eb5f8..1f109da8 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java @@ -8,14 +8,12 @@ /** Place holder. */ public interface Collection { - /** - * Constant that can be used to refer to the 'Worldstate' collection explicitly. - */ + /** Constant that can be used to refer to the 'Worldstate' collection explicitly. */ String WORLD = "worldstate"; /** - * Placeholder. Purely in place to prevent Checkstyle inferring this class is pointless. - * will be removed in the next story + * Placeholder. Purely in place to prevent Checkstyle inferring this class is pointless. will be removed in the next + * story */ void placeholder(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java index ce347971..3f9c11cc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java @@ -11,40 +11,36 @@ /** * Ledger representing the overall shared Transaction Data of the Network. * - * It is composed of a number of collections, one being the public or world - * state, and other private data collections, including the implicit - * organizational collections. - * - * Ledger objects can be passed between methods if required. All operations on - * the Ledger directly or via any child object such as a Collection will be - * controlled by the supplied transactional context. + *

It is composed of a number of collections, one being the public or world state, and other private data + * collections, including the implicit organizational collections. * + *

Ledger objects can be passed between methods if required. All operations on the Ledger directly or via any child + * object such as a Collection will be controlled by the supplied transactional context. */ public interface Ledger { /** * Get the Ledger instance that represents the current ledger state. * - * Any interactions with the ledger will be done under the control of the - * transactional context supplied. The ledger object may be passed to other - * methods if required. + *

Any interactions with the ledger will be done under the control of the transactional context supplied. The + * ledger object may be passed to other methods if required. * - * A new instance is returned on each call. + *

A new instance is returned on each call. * - * @param ctx Context The Transactional context to use for interactions with - * this ledger + * @param ctx Context The Transactional context to use for interactions with this ledger * @return Ledger instance */ static Ledger getLedger(final Context ctx) { return new LedgerImpl(ctx); - }; + } + ; /** * Return the a collection based on the supplied name. * - * Private Data collections can be accessed by name. + *

Private Data collections can be accessed by name. * - * A new instance of a Collection object is returned on each call. + *

A new instance of a Collection object is returned on each call. * * @param name * @return Collection instance @@ -54,7 +50,7 @@ static Ledger getLedger(final Context ctx) { /** * Return the World State collection. * - * A new instance of a Collection object is returned on each call. + *

A new instance of a Collection object is returned on each call. * * @return Collection instance */ @@ -63,14 +59,12 @@ static Ledger getLedger(final Context ctx) { /** * Return a implicit organization collection. * - * Given the mspid of the ogranization return the private data collection that - * is implicitly created + *

Given the mspid of the ogranization return the private data collection that is implicitly created * - * A new instance of a Collection object is returned on each call. + *

A new instance of a Collection object is returned on each call. * * @param mspid String Organization's mspid * @return Collection instance */ Collection getOrganizationCollection(String mspid); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java index faea7f49..c313ef77 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java @@ -7,16 +7,12 @@ import org.hyperledger.fabric.ledger.Collection; -/** - * Placeholder. - */ +/** Placeholder. */ public class CollectionImpl implements Collection { private final String name; /** - * - * * @param name * @param ledgerImpl */ @@ -29,5 +25,4 @@ public void placeholder() { // TODO Auto-generated method stub } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java index 1087cd24..9f8ed761 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java @@ -39,5 +39,4 @@ public Collection getDefaultCollection() { public Collection getOrganizationCollection(final String mspid) { return this.getCollection("_implicit_org_" + mspid); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/package-info.java index 96b288ea..025bb854 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/package-info.java @@ -1,6 +1,6 @@ -/* - * Copyright 2023 IBM All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.ledger.impl; +/* + * Copyright 2023 IBM All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.fabric.ledger.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/package-info.java index ca6cfec7..129a4271 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/package-info.java @@ -4,9 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - *

- * Provides the API for contracts to access the shared ledger. - * - */ +/** Provides the API for contracts to access the shared ledger. */ package org.hyperledger.fabric.ledger; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java index 56bcdab6..74cd6247 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java @@ -8,16 +8,14 @@ import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.logging.Logger; - import org.hyperledger.fabric.metrics.impl.DefaultProvider; import org.hyperledger.fabric.metrics.impl.NullProvider; /** * Metrics Interface. * - * Metrics setups up the provider in use from the configuration supplied If not - * enabled, nothing happens, but if enabled but no specific logger default is - * used that uses the org.hyperledger.Performance logger + *

Metrics setups up the provider in use from the configuration supplied If not enabled, nothing happens, but if + * enabled but no specific logger default is used that uses the org.hyperledger.Performance logger */ public final class Metrics { @@ -28,13 +26,9 @@ public final class Metrics { private static MetricsProvider provider; - - private Metrics() { - - } + private Metrics() {} /** - * * @param props * @return The metrics provide */ @@ -46,37 +40,36 @@ public static MetricsProvider initialize(final Properties props) { final String providerClass = (String) props.get(CHAINCODE_METRICS_PROVIDER); @SuppressWarnings("unchecked") // it must be this type otherwise an error - final - Class clazz = (Class) Class.forName(providerClass); + final Class clazz = (Class) Class.forName(providerClass); provider = clazz.getConstructor().newInstance(); } else { logger.info("Using default metrics provider (logs to org.hyperledger.Performance)"); provider = new DefaultProvider(); } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { + } catch (ClassNotFoundException + | InstantiationException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException + | NoSuchMethodException + | SecurityException e) { throw new RuntimeException("Unable to start metrics", e); } } else { // return a 'null' provider logger.info("Metrics disabled"); provider = new NullProvider(); - } provider.initialize(props); return provider; } - /** - * - * @return MetricsProvider - */ + /** @return MetricsProvider */ public static MetricsProvider getProvider() { if (provider == null) { throw new IllegalStateException("No provider set, this should have been set"); } return provider; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java index 482fbbdf..9609ea87 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java @@ -9,20 +9,16 @@ import java.util.Properties; /** - * Interface to be implemented to send metrics on the chaincode to the - * 'backend-of-choice'. + * Interface to be implemented to send metrics on the chaincode to the 'backend-of-choice'. * - * An instance of this will be created, and provided with the resources from - * which chaincode specific metrics can be collected. (via the no-argument - * constructor). + *

An instance of this will be created, and provided with the resources from which chaincode specific metrics can be + * collected. (via the no-argument constructor). * - * The choice of when, where and what to collect etc are within the remit of the - * provider. + *

The choice of when, where and what to collect etc are within the remit of the provider. * - * This is the effective call sequence. + *

This is the effective call sequence. * - * MyMetricsProvider mmp = new MyMetricsProvider() - * mmp.initialize(props_from_environment); // short while later.... + *

MyMetricsProvider mmp = new MyMetricsProvider() mmp.initialize(props_from_environment); // short while later.... * mmp.setTaskMetricsCollector(taskService); */ public interface MetricsProvider { @@ -32,17 +28,15 @@ public interface MetricsProvider { * * @param props */ - default void initialize(final Properties props) { - }; + default void initialize(final Properties props) {} + ; /** - * Pass a reference to this task service for information gathering. This is - * related specifically to the handling of tasks within the chaincode. i.e. how - * individual transactions are dispatched for execution. + * Pass a reference to this task service for information gathering. This is related specifically to the handling of + * tasks within the chaincode. i.e. how individual transactions are dispatched for execution. * * @param taskService */ - default void setTaskMetricsCollector(final TaskMetricsCollector taskService) { - }; - + default void setTaskMetricsCollector(final TaskMetricsCollector taskService) {} + ; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java index bb2c6065..ef59d6a4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/TaskMetricsCollector.java @@ -8,11 +8,9 @@ /** * Collect metrics relating to the task execution. * - * The task execution (of which each fabric transaction is one) is backed by a - * thread pool that implements this interface. As that is an implementation - * class this interface abstracts the information available from it (as far as + *

The task execution (of which each fabric transaction is one) is backed by a thread pool that implements this + * interface. As that is an implementation class this interface abstracts the information available from it (as far as * metrics go). - * */ public interface TaskMetricsCollector { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java index a2dc8a78..841e4164 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java @@ -9,24 +9,17 @@ import java.util.Timer; import java.util.TimerTask; import java.util.logging.Logger; - import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.metrics.MetricsProvider; import org.hyperledger.fabric.metrics.TaskMetricsCollector; -/** - * Simple default provider that logs to the org.hyperledger.Performance logger - * the basic metrics. - * - */ +/** Simple default provider that logs to the org.hyperledger.Performance logger the basic metrics. */ public final class DefaultProvider implements MetricsProvider { private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); private TaskMetricsCollector taskService; - /** - * - */ + /** */ public DefaultProvider() { perflogger.info("Default Metrics Provider started"); } @@ -41,13 +34,15 @@ public void setTaskMetricsCollector(final TaskMetricsCollector taskService) { @Override public void initialize(final Properties props) { final Timer metricTimer = new Timer(true); - metricTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - DefaultProvider.this.logMetrics(); - } - }, 0, TIME_INTERVAL); - + metricTimer.scheduleAtFixedRate( + new TimerTask() { + @Override + public void run() { + DefaultProvider.this.logMetrics(); + } + }, + 0, + TIME_INTERVAL); } protected void logMetrics() { @@ -58,14 +53,18 @@ protected void logMetrics() { } final StringBuilder sb = new StringBuilder(); sb.append('{'); - sb.append(String.format(" \"active_count\":%d ", DefaultProvider.this.taskService.getActiveCount())).append(','); - sb.append(String.format(" \"pool_size\":%d ", DefaultProvider.this.taskService.getPoolSize())).append(','); - sb.append(String.format(" \"core_pool_size\":%d ", DefaultProvider.this.taskService.getCorePoolSize())).append(','); - sb.append(String.format(" \"current_task_count\":%d ", DefaultProvider.this.taskService.getCurrentTaskCount())).append(','); - sb.append(String.format(" \"current_queue_depth\":%d ", DefaultProvider.this.taskService.getCurrentQueueCount())); + sb.append(String.format(" \"active_count\":%d ", DefaultProvider.this.taskService.getActiveCount())) + .append(','); + sb.append(String.format(" \"pool_size\":%d ", DefaultProvider.this.taskService.getPoolSize())) + .append(','); + sb.append(String.format(" \"core_pool_size\":%d ", DefaultProvider.this.taskService.getCorePoolSize())) + .append(','); + sb.append(String.format( + " \"current_task_count\":%d ", DefaultProvider.this.taskService.getCurrentTaskCount())) + .append(','); + sb.append(String.format( + " \"current_queue_depth\":%d ", DefaultProvider.this.taskService.getCurrentQueueCount())); return sb.append('}').toString(); }); - } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java index f977ac67..19639009 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java @@ -7,17 +7,9 @@ import org.hyperledger.fabric.metrics.MetricsProvider; -/** - * Very simple provider that does absolutely nothing. Used when metrics are - * disabled. - * - */ +/** Very simple provider that does absolutely nothing. Used when metrics are disabled. */ public class NullProvider implements MetricsProvider { - /** - * - */ - public NullProvider() { - } - + /** */ + public NullProvider() {} } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/package-info.java index 30152965..59afe468 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.metrics.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java index ec9d196a..f9cf1f7b 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/package-info.java @@ -7,24 +7,17 @@ /** * Provides interfaces and classes to support collection of metrics. * - *

- * The main metrics that are available are the statistics around the number of - * tasks that are running, and how the thread pool is handling these. + *

The main metrics that are available are the statistics around the number of tasks that are running, and how the + * thread pool is handling these. * - *

- * Note a 'task' is a message from the Peer to the Chaincode - this message is - * either a new transaction, or a response from a stub API, eg getState(). Query - * apis may return more than one response. + *

Note a 'task' is a message from the Peer to the Chaincode - this message is either a new transaction, or a + * response from a stub API, eg getState(). Query apis may return more than one response. * - *

- * To enable metrics, add a CHAINCODE_METRICS_ENABLED=true setting - * to the config.props chaincode configuration file. - * See the Overview for details of how to - * configure chaincode. + *

To enable metrics, add a CHAINCODE_METRICS_ENABLED=true setting to the config.props + * chaincode configuration file. See the Overview for details of how to configure + * chaincode. * - *

Open Telemetry

- * - * To use Open Telemetry, set the following properties: + *

Open Telemetry To use Open Telemetry, set the following properties: * *

  * CHAINCODE_METRICS_ENABLED=true
@@ -34,7 +27,8 @@
  * Additionally, you can set properties after the specification:
  * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sdk-environment-variables.md
  *
- * Example:
+ * 

Example: + * *

  * OTEL_EXPORTER_OTLP_ENDPOINT=otelcollector:4317
  * OTEL_EXPORTER_OTLP_INSECURE=true
diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java
index cb5d58f6..dfeb5e02 100644
--- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java
+++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/package-info.java
@@ -4,7 +4,5 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-/**
- * Provides logging classes.
- */
+/** Provides logging classes. */
 package org.hyperledger.fabric;
diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java
index 046595df..b8882487 100644
--- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java
+++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java
@@ -11,13 +11,11 @@
 import java.util.HashMap;
 import java.util.Map;
 
-/**
- * Defines methods that all chaincodes must implement.
- */
+/** Defines methods that all chaincodes must implement. */
 public interface Chaincode {
     /**
-     * Called during an instantiate transaction after the container has been
-     * established, allowing the chaincode to initialize its internal data.
+     * Called during an instantiate transaction after the container has been established, allowing the chaincode to
+     * initialize its internal data.
      *
      * @param stub the chaincode stub
      * @return the chaincode response
@@ -25,8 +23,7 @@ public interface Chaincode {
     Response init(ChaincodeStub stub);
 
     /**
-     * Called for every Invoke transaction. The chaincode may change its state
-     * variables.
+     * Called for every Invoke transaction. The chaincode may change its state variables.
      *
      * @param stub the chaincode stub
      * @return the chaincode response
@@ -34,9 +31,8 @@ public interface Chaincode {
     Response invoke(ChaincodeStub stub);
 
     /**
-     * Wrapper around protobuf Response, contains status, message and payload.
-     * Object returned by call to {@link #init(ChaincodeStub)}
-     * and{@link #invoke(ChaincodeStub)}
+     * Wrapper around protobuf Response, contains status, message and payload. Object returned by call to
+     * {@link #init(ChaincodeStub)} and{@link #invoke(ChaincodeStub)}
      */
     class Response {
         private final int statusCode;
@@ -45,6 +41,7 @@ class Response {
 
         /**
          * Constructor.
+         *
          * @param status a status object.
          * @param message a response message.
          * @param payload a response payload.
@@ -57,6 +54,7 @@ public Response(final Status status, final String message, final byte[] payload)
 
         /**
          * Constructor.
+         *
          * @param statusCode a status code.
          * @param message a response message.
          * @param payload a response payload.
@@ -69,6 +67,7 @@ public Response(final int statusCode, final String message, final byte[] payload
 
         /**
          * Get the response status.
+         *
          * @return status.
          */
         public Status getStatus() {
@@ -81,6 +80,7 @@ public Status getStatus() {
 
         /**
          * Get the response status code.
+         *
          * @return status code.
          */
         public int getStatusCode() {
@@ -89,6 +89,7 @@ public int getStatusCode() {
 
         /**
          * Get the response message.
+         *
          * @return a message.
          */
         public String getMessage() {
@@ -97,6 +98,7 @@ public String getMessage() {
 
         /**
          * Get the response payload.
+         *
          * @return payload bytes.
          */
         public byte[] getPayload() {
@@ -105,27 +107,20 @@ public byte[] getPayload() {
 
         /**
          * Get the response payload as a UTF-8 string.
+         *
          * @return a string.
          */
         public String getStringPayload() {
             return (payload == null) ? null : new String(payload, UTF_8);
         }
 
-        /**
-         * {@link Response} status enum.
-         */
+        /** {@link Response} status enum. */
         public enum Status {
-            /**
-             * Successful response status.
-             */
+            /** Successful response status. */
             SUCCESS(200),
-            /**
-             * Minimum threshold for as error status code.
-             */
+            /** Minimum threshold for as error status code. */
             ERROR_THRESHOLD(400),
-            /**
-             * Server-side error status.
-             */
+            /** Server-side error status. */
             INTERNAL_SERVER_ERROR(500);
 
             private static final Map CODETOSTATUS = new HashMap<>();
@@ -137,6 +132,7 @@ public enum Status {
 
             /**
              * Get the status code associated with this status object.
+             *
              * @return a status code.
              */
             public int getCode() {
@@ -145,6 +141,7 @@ public int getCode() {
 
             /**
              * Get a status object for a given status code.
+             *
              * @param code a status code.
              * @return a status object.
              */
@@ -158,6 +155,7 @@ public static Status forCode(final int code) {
 
             /**
              * Whether a status exists for a given status code.
+             *
              * @param code a status code.
              * @return True if a status for the code exists; otherwise false.
              */
@@ -170,8 +168,6 @@ public static boolean hasStatusForCode(final int code) {
                     CODETOSTATUS.put(status.code, status);
                 }
             }
-
         }
-
     }
 }
diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java
index da8da55e..0ce76bc4 100644
--- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java
+++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java
@@ -9,6 +9,14 @@
 import static java.lang.String.format;
 import static java.util.logging.Level.ALL;
 
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.util.JsonFormat;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
+import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
+import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
+import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
+import io.grpc.stub.StreamObserver;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -26,10 +34,6 @@
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 import java.util.logging.SimpleFormatter;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.util.JsonFormat;
-
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Options;
@@ -43,35 +47,21 @@
 import org.hyperledger.fabric.shim.impl.InvocationTaskManager;
 import org.hyperledger.fabric.traces.Traces;
 
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
-import io.grpc.netty.shaded.io.grpc.netty.NegotiationType;
-import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
-import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
-import io.grpc.stub.StreamObserver;
-
 /**
  * Abstract implementation of {@link Chaincode}.
  *
- * 

- * All chaincode implementations must extend the abstract class - * ChaincodeBase. It is possible to implement chaincode by - * extending ChaincodeBase directly however new projects should - * implement {@link org.hyperledger.fabric.contract.ContractInterface} and use - * the contract programming model instead. + *

All chaincode implementations must extend the abstract class ChaincodeBase. It is possible to + * implement chaincode by extending ChaincodeBase directly however new projects should implement + * {@link org.hyperledger.fabric.contract.ContractInterface} and use the contract programming model instead. * * @see org.hyperledger.fabric.contract */ public abstract class ChaincodeBase implements Chaincode { - /** - * - */ + /** */ public static final String CORE_CHAINCODE_LOGGING_SHIM = "CORE_CHAINCODE_LOGGING_SHIM"; - /** - * - */ + /** */ public static final String CORE_CHAINCODE_LOGGING_LEVEL = "CORE_CHAINCODE_LOGGING_LEVEL"; @Override @@ -82,19 +72,13 @@ public abstract class ChaincodeBase implements Chaincode { private static final Logger LOGGER = Logger.getLogger(ChaincodeBase.class.getName()); - /** - * - */ + /** */ public static final String DEFAULT_HOST = "127.0.0.1"; - /** - * - */ + /** */ public static final int DEFAULT_PORT = 7051; - /** - * Default to 100MB for maximum inbound grpc message size. - */ + /** Default to 100MB for maximum inbound grpc message size. */ public static final String DEFAULT_MAX_INBOUND_MESSAGE_SIZE = "104857600"; private String host = DEFAULT_HOST; @@ -132,10 +116,10 @@ private int getMaxInboundMessageSize() { if (this.props == null) { throw new IllegalStateException("Chaincode config not available"); } - final int maxMsgSize = Integer - .parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE)); - final String msgSizeInfo = String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE, - maxMsgSize); + final int maxMsgSize = + Integer.parseInt(this.props.getProperty(MAX_INBOUND_MESSAGE_SIZE, DEFAULT_MAX_INBOUND_MESSAGE_SIZE)); + final String msgSizeInfo = + String.format("Maximum Inbound Message Size [%s] = %d", MAX_INBOUND_MESSAGE_SIZE, maxMsgSize); LOGGER.info(msgSizeInfo); return maxMsgSize; } @@ -145,7 +129,6 @@ private int getMaxInboundMessageSize() { * * @param args command line arguments */ - public void start(final String[] args) { try { initializeLogging(); @@ -173,7 +156,8 @@ protected final void connectToPeer() throws IOException { // This is then passed to the ChaincodeSupportClient to be connected to the // gRPC streams - final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(this.id).build(); + final ChaincodeID chaincodeId = + ChaincodeID.newBuilder().setName(this.id).build(); final ManagedChannelBuilder channelBuilder = newChannelBuilder(); final ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder); @@ -202,9 +186,9 @@ protected final void connectToPeer() throws IOException { // for any error - shut everything down // as this is long lived (well forever) then any completion means something // has stopped in the peer or the network comms, so also shutdown - final StreamObserver requestObserver = chaincodeSupportClient.getStub().register( - - new StreamObserver() { + final StreamObserver requestObserver = chaincodeSupportClient + .getStub() + .register(new StreamObserver() { @Override public void onNext(final ChaincodeMessage chaincodeMessage) { // message off to the ITM... @@ -225,24 +209,20 @@ public void onCompleted() { LOGGER.severe("Chaincode stream is complete. Shutting down the chaincode stream."); chaincodeSupportClient.shutdown(itm); } - } - - ); + }); chaincodeSupportClient.start(itm, requestObserver); - } /** * connect external chaincode to peer for chat. * * @param requestObserver reqeust from peer - * @return itm - The InnvocationTask Manager handles the message level - * communication with the peer. + * @return itm - The InnvocationTask Manager handles the message level communication with the peer. * @throws IOException validation fields exception */ - protected StreamObserver connectToPeer( - final StreamObserver requestObserver) throws IOException { + protected StreamObserver connectToPeer(final StreamObserver requestObserver) + throws IOException { validateOptions(); if (requestObserver == null) { throw new IOException("StreamObserver 'requestObserver' for chat with peer can't be null"); @@ -256,7 +236,8 @@ protected StreamObserver connectToPeer( // This is then passed to the ChaincodeSupportClient to be connected to the // gRPC streams - final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(this.id).build(); + final ChaincodeID chaincodeId = + ChaincodeID.newBuilder().setName(this.id).build(); final ManagedChannelBuilder channelBuilder = newChannelBuilder(); final ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder); @@ -288,8 +269,8 @@ public void onCompleted() { protected final void initializeLogging() { // the VM wide formatting string. - System.setProperty("java.util.logging.SimpleFormatter.format", - "%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %5$s%6$s%n"); + System.setProperty( + "java.util.logging.SimpleFormatter.format", "%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %5$s%6$s%n"); final Logger rootLogger = Logger.getLogger(""); for (final java.util.logging.Handler handler : rootLogger.getHandlers()) { @@ -300,7 +281,6 @@ protected final void initializeLogging() { public synchronized String format(final LogRecord record) { return Thread.currentThread() + " " + super.format(record); } - }); } @@ -322,33 +302,31 @@ public synchronized String format(final LogRecord record) { final Level shimLogLevel = mapLevel(System.getenv(CORE_CHAINCODE_LOGGING_SHIM)); Logger.getLogger(ChaincodeBase.class.getPackage().getName()).setLevel(shimLogLevel); Logger.getLogger(ContractRouter.class.getPackage().getName()).setLevel(chaincodeLogLevel); - } private Level mapLevel(final String level) { if (level != null) { switch (level.toUpperCase().trim()) { - case "CRITICAL": - case "ERROR": - return Level.SEVERE; - case "WARNING": - case "WARN": - return Level.WARNING; - case "INFO": - return Level.INFO; - case "NOTICE": - return Level.CONFIG; - case "DEBUG": - return Level.FINEST; - default: - break; + case "CRITICAL": + case "ERROR": + return Level.SEVERE; + case "WARNING": + case "WARN": + return Level.WARNING; + case "INFO": + return Level.INFO; + case "NOTICE": + return Level.CONFIG; + case "DEBUG": + return Level.FINEST; + default: + break; } } return Level.INFO; } - private SocketAddress parseHostPort(final String hostAddrStr) throws URISyntaxException { // WORKAROUND: add any scheme to make the resulting URI valid. @@ -357,8 +335,7 @@ private SocketAddress parseHostPort(final String hostAddrStr) throws URISyntaxEx int port = uri.getPort(); if (uri.getHost() == null || uri.getPort() == -1) { - throw new URISyntaxException(uri.toString(), - "URI must have host and port parts"); + throw new URISyntaxException(uri.toString(), "URI must have host and port parts"); } // validation succeeded @@ -374,9 +351,7 @@ public boolean isServer() { return !chaincodeServerAddress.isEmpty(); } - /** - * Validate init parameters from env chaincode base. - */ + /** Validate init parameters from env chaincode base. */ public void validateOptions() { if (this.id == null || this.id.isEmpty()) { throw new IllegalArgumentException(format( @@ -435,12 +410,9 @@ protected final void processCommandLineOptions(final String[] args) { LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>"); LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id); LOGGER.info("CORE_PEER_ADDRESS: " + this.host + ":" + this.port); - } - /** - * set fields from env. - */ + /** set fields from env. */ public final void processEnvironmentOptions() { if (System.getenv().containsKey(CORE_CHAINCODE_ID_NAME)) { @@ -492,9 +464,8 @@ public final void processEnvironmentOptions() { } /** - * Obtains configuration specifically for running the chaincode and settable on - * a per chaincode basis rather than taking properties from the Peers' - * configuration. + * Obtains configuration specifically for running the chaincode and settable on a per chaincode basis rather than + * taking properties from the Peers' configuration. * * @return Configuration */ @@ -579,8 +550,10 @@ final SslContext createSSLContext() throws IOException { final byte[] ckb = Files.readAllBytes(Paths.get(this.tlsClientKeyPath)); final byte[] ccb = Files.readAllBytes(Paths.get(this.tlsClientCertPath)); - return GrpcSslContexts.forClient().trustManager(new File(this.tlsClientRootCertPath)) - .keyManager(new ByteArrayInputStream(Base64.getDecoder().decode(ccb)), + return GrpcSslContexts.forClient() + .trustManager(new File(this.tlsClientRootCertPath)) + .keyManager( + new ByteArrayInputStream(Base64.getDecoder().decode(ccb)), new ByteArrayInputStream(Base64.getDecoder().decode(ckb))) .build(); } @@ -663,12 +636,9 @@ String getId() { return id; } - /** - * Chaincode State. - */ + /** Chaincode State. */ public enum CCState { - /** - * */ + /** */ CREATED, /** */ ESTABLISHED, @@ -678,18 +648,12 @@ public enum CCState { private CCState state = CCState.CREATED; - /** - * - * @return State - */ + /** @return State */ public final CCState getState() { return this.state; } - /** - * - * @param newState - */ + /** @param newState */ public final void setState(final CCState newState) { this.state = newState; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java index fe73b570..7a4b5312 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java @@ -8,18 +8,13 @@ import static java.nio.charset.StandardCharsets.UTF_8; /** - * Contracts should use {@code ChaincodeException} to indicate when an error - * occurs in Smart Contract logic. + * Contracts should use {@code ChaincodeException} to indicate when an error occurs in Smart Contract logic. * - *

- * When a {@code ChaincodeException} is thrown an error response will be - * returned from the chaincode container containing the exception message and - * payload, if specified. + *

When a {@code ChaincodeException} is thrown an error response will be returned from the chaincode container + * containing the exception message and payload, if specified. * - *

- * {@code ChaincodeException} may be extended to provide application specific - * error information. Subclasses should ensure that {@link #getPayload} returns - * a serialized representation of the error in a suitable format for client + *

{@code ChaincodeException} may be extended to provide application specific error information. Subclasses should + * ensure that {@link #getPayload} returns a serialized representation of the error in a suitable format for client * applications to process. */ public class ChaincodeException extends RuntimeException { @@ -28,16 +23,13 @@ public class ChaincodeException extends RuntimeException { private byte[] payload; - /** - * Constructs a new {@code ChaincodeException} with no detail message. - */ + /** Constructs a new {@code ChaincodeException} with no detail message. */ public ChaincodeException() { super(); } /** - * Constructs a new {@code ChaincodeException} with the specified detail - * message. + * Constructs a new {@code ChaincodeException} with the specified detail message. * * @param message the detail message. */ @@ -55,19 +47,17 @@ public ChaincodeException(final Throwable cause) { } /** - * Constructs a new {@code ChaincodeException} with the specified detail message - * and cause. + * Constructs a new {@code ChaincodeException} with the specified detail message and cause. * * @param message the detail message. - * @param cause the cause. + * @param cause the cause. */ public ChaincodeException(final String message, final Throwable cause) { super(message, cause); } /** - * Constructs a new {@code ChaincodeException} with the specified detail message - * and response payload. + * Constructs a new {@code ChaincodeException} with the specified detail message and response payload. * * @param message the detail message. * @param payload the response payload. @@ -79,12 +69,11 @@ public ChaincodeException(final String message, final byte[] payload) { } /** - * Constructs a new {@code ChaincodeException} with the specified detail - * message, response payload and cause. + * Constructs a new {@code ChaincodeException} with the specified detail message, response payload and cause. * * @param message the detail message. * @param payload the response payload. - * @param cause the cause. + * @param cause the cause. */ public ChaincodeException(final String message, final byte[] payload, final Throwable cause) { super(message, cause); @@ -93,8 +82,7 @@ public ChaincodeException(final String message, final byte[] payload, final Thro } /** - * Constructs a new {@code ChaincodeException} with the specified detail message - * and response payload. + * Constructs a new {@code ChaincodeException} with the specified detail message and response payload. * * @param message the detail message. * @param payload the response payload. @@ -106,12 +94,11 @@ public ChaincodeException(final String message, final String payload) { } /** - * Constructs a new {@code ChaincodeException} with the specified detail - * message, response payload and cause. + * Constructs a new {@code ChaincodeException} with the specified detail message, response payload and cause. * * @param message the detail message. * @param payload the response payload. - * @param cause the cause. + * @param cause the cause. */ public ChaincodeException(final String message, final String payload, final Throwable cause) { super(message, cause); @@ -122,12 +109,9 @@ public ChaincodeException(final String message, final String payload, final Thro /** * Returns the response payload or {@code null} if there is no response. * - *

- * The payload should represent the chaincode error in a way that client - * applications written in different programming languages can interpret. For - * example it could include a domain specific error code, in addition to any - * state information which would allow client applications to respond - * appropriately. + *

The payload should represent the chaincode error in a way that client applications written in different + * programming languages can interpret. For example it could include a domain specific error code, in addition to + * any state information which would allow client applications to respond appropriately. * * @return the response payload or {@code null} if there is no response. */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServer.java index 8c8ff2b3..81c7ce29 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServer.java @@ -8,9 +8,7 @@ import java.io.IOException; -/** - * External chaincode server. - */ +/** External chaincode server. */ public interface ChaincodeServer { /** @@ -21,9 +19,6 @@ public interface ChaincodeServer { */ void start() throws IOException, InterruptedException; - /** - * shutdown now grpc server. - */ + /** shutdown now grpc server. */ void stop(); - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java index 27c84257..af81bfb7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java @@ -22,28 +22,33 @@ public final class ChaincodeServerProperties { private String trustCertCollectionFile; private boolean tlsEnabled = false; - /** - * Constructor using default configuration. - */ - public ChaincodeServerProperties() { - } + /** Constructor using default configuration. */ + public ChaincodeServerProperties() {} /** * Constructor. + * * @param portChaincodeServer ignored. * @param maxInboundMetadataSize the maximum metadata size allowed to be received by the server. * @param maxInboundMessageSize the maximum message size allowed to be received by the server. * @param maxConnectionAgeSeconds the maximum connection age in seconds. * @param keepAliveTimeoutSeconds timeout for a keep-alive ping request in seconds. - * @param permitKeepAliveTimeMinutes the most aggressive keep-alive time clients are permitted to configure in minutes. + * @param permitKeepAliveTimeMinutes the most aggressive keep-alive time clients are permitted to configure in + * minutes. * @param keepAliveTimeMinutes delay before server sends a keep-alive in minutes. - * @param permitKeepAliveWithoutCalls whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection. + * @param permitKeepAliveWithoutCalls whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are + * no outstanding RPCs on the connection. */ // checkstyle:ignore-next-line:ParameterNumber public ChaincodeServerProperties( - final int portChaincodeServer, final int maxInboundMetadataSize, final int maxInboundMessageSize, - final int maxConnectionAgeSeconds, final int keepAliveTimeoutSeconds, final int permitKeepAliveTimeMinutes, - final int keepAliveTimeMinutes, final boolean permitKeepAliveWithoutCalls) { + final int portChaincodeServer, + final int maxInboundMetadataSize, + final int maxInboundMessageSize, + final int maxConnectionAgeSeconds, + final int keepAliveTimeoutSeconds, + final int permitKeepAliveTimeMinutes, + final int keepAliveTimeMinutes, + final boolean permitKeepAliveWithoutCalls) { this.serverAddress = null; this.maxInboundMetadataSize = maxInboundMetadataSize; @@ -57,6 +62,7 @@ public ChaincodeServerProperties( /** * The maximum size of metadata allowed to be received. + * * @return The maximum metadata size allowed. */ public int getMaxInboundMetadataSize() { @@ -65,6 +71,7 @@ public int getMaxInboundMetadataSize() { /** * Sets the maximum metadata size allowed to be received by the server. + * * @param maxInboundMetadataSize The new maximum size allowed for incoming metadata. */ public void setMaxInboundMetadataSize(final int maxInboundMetadataSize) { @@ -73,6 +80,7 @@ public void setMaxInboundMetadataSize(final int maxInboundMetadataSize) { /** * The maximum message size allowed to be received by the server. + * * @return the maximum message size allowed. */ public int getMaxInboundMessageSize() { @@ -81,6 +89,7 @@ public int getMaxInboundMessageSize() { /** * Sets the maximum message size allowed to be received by the server. + * * @param maxInboundMessageSize The new maximum size allowed for incoming messages. */ public void setMaxInboundMessageSize(final int maxInboundMessageSize) { @@ -89,6 +98,7 @@ public void setMaxInboundMessageSize(final int maxInboundMessageSize) { /** * The maximum connection age. + * * @return The maximum connection age in seconds. */ public int getMaxConnectionAgeSeconds() { @@ -97,6 +107,7 @@ public int getMaxConnectionAgeSeconds() { /** * Specify a maximum connection age. + * * @param maxConnectionAgeSeconds The maximum connection age in seconds. */ public void setMaxConnectionAgeSeconds(final int maxConnectionAgeSeconds) { @@ -105,6 +116,7 @@ public void setMaxConnectionAgeSeconds(final int maxConnectionAgeSeconds) { /** * The timeout for a keep-alive ping requests. + * * @return timeout in seconds. */ public int getKeepAliveTimeoutSeconds() { @@ -113,6 +125,7 @@ public int getKeepAliveTimeoutSeconds() { /** * Set the timeout for keep-alive ping requests. + * * @param keepAliveTimeoutSeconds timeout in seconds. */ public void setKeepAliveTimeoutSeconds(final int keepAliveTimeoutSeconds) { @@ -121,6 +134,7 @@ public void setKeepAliveTimeoutSeconds(final int keepAliveTimeoutSeconds) { /** * The most aggressive keep-alive time clients are permitted to configure. + * * @return time in minutes. */ public int getPermitKeepAliveTimeMinutes() { @@ -129,6 +143,7 @@ public int getPermitKeepAliveTimeMinutes() { /** * Specify the most aggressive keep-alive time clients are permitted to configure. + * * @param permitKeepAliveTimeMinutes time in minutes. */ public void setPermitKeepAliveTimeMinutes(final int permitKeepAliveTimeMinutes) { @@ -137,6 +152,7 @@ public void setPermitKeepAliveTimeMinutes(final int permitKeepAliveTimeMinutes) /** * The delay before the server sends a keep-alive. + * * @return delay in minutes. */ public int getKeepAliveTimeMinutes() { @@ -145,6 +161,7 @@ public int getKeepAliveTimeMinutes() { /** * Set the delay before the server sends a keep-alive. + * * @param keepAliveTimeMinutes delay in minutes. */ public void setKeepAliveTimeMinutes(final int keepAliveTimeMinutes) { @@ -152,7 +169,9 @@ public void setKeepAliveTimeMinutes(final int keepAliveTimeMinutes) { } /** - * Whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection. + * Whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the + * connection. + * * @return true if clients are allowed to send keep-alive requests without calls; otherwise false. */ public boolean getPermitKeepAliveWithoutCalls() { @@ -161,6 +180,7 @@ public boolean getPermitKeepAliveWithoutCalls() { /** * Get the server socket address. + * * @return a socket address. */ public SocketAddress getServerAddress() { @@ -169,6 +189,7 @@ public SocketAddress getServerAddress() { /** * Set the server socket address. + * * @param address a socket address. */ public void setServerAddress(final SocketAddress address) { @@ -176,7 +197,9 @@ public void setServerAddress(final SocketAddress address) { } /** - * Whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection. + * Whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the + * connection. + * * @return true if clients are allowed to send keep-alive requests without calls; otherwise false. */ public boolean isPermitKeepAliveWithoutCalls() { @@ -184,7 +207,9 @@ public boolean isPermitKeepAliveWithoutCalls() { } /** - * Specify whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection. + * Specify whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the + * connection. + * * @param permitKeepAliveWithoutCalls Whether to allow clients to send keep-alive requests without calls. */ public void setPermitKeepAliveWithoutCalls(final boolean permitKeepAliveWithoutCalls) { @@ -193,6 +218,7 @@ public void setPermitKeepAliveWithoutCalls(final boolean permitKeepAliveWithoutC /** * Password used to access the server key. + * * @return a password. */ public String getKeyPassword() { @@ -201,6 +227,7 @@ public String getKeyPassword() { /** * Set the password used to access the server key. + * * @param keyPassword a password. */ public void setKeyPassword(final String keyPassword) { @@ -209,6 +236,7 @@ public void setKeyPassword(final String keyPassword) { /** * Server keychain file name. + * * @return a file name. */ public String getKeyCertChainFile() { @@ -217,6 +245,7 @@ public String getKeyCertChainFile() { /** * Set the server keychain file name. + * * @param keyCertChainFile a file name. */ public void setKeyCertChainFile(final String keyCertChainFile) { @@ -225,6 +254,7 @@ public void setKeyCertChainFile(final String keyCertChainFile) { /** * Server key file name. + * * @return a file name. */ public String getKeyFile() { @@ -233,6 +263,7 @@ public String getKeyFile() { /** * Set the server key file name. + * * @param keyFile a file name. */ public void setKeyFile(final String keyFile) { @@ -241,6 +272,7 @@ public void setKeyFile(final String keyFile) { /** * Server trust certificate collection file name. + * * @return a file name. */ public String getTrustCertCollectionFile() { @@ -249,6 +281,7 @@ public String getTrustCertCollectionFile() { /** * Set the server trust certificate collection file name. + * * @param trustCertCollectionFile a file name. */ public void setTrustCertCollectionFile(final String trustCertCollectionFile) { @@ -257,6 +290,7 @@ public void setTrustCertCollectionFile(final String trustCertCollectionFile) { /** * Whether TLS is enabled for the server. + * * @return true if TLS is enabled; otherwise false. */ public boolean isTlsEnabled() { @@ -265,6 +299,7 @@ public boolean isTlsEnabled() { /** * Set whether TLS is enabled for the server. + * * @param tlsEnabled true to enable TLS; otherwise false. */ public void setTlsEnabled(final boolean tlsEnabled) { @@ -273,6 +308,7 @@ public void setTlsEnabled(final boolean tlsEnabled) { /** * Check that all the server property values are valid. + * * @throws IllegalArgumentException if any properties are not valid. */ public void validate() { @@ -280,30 +316,37 @@ public void validate() { throw new IllegalArgumentException("chaincodeServerProperties.getServerAddress() must be set"); } if (this.getKeepAliveTimeMinutes() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getKeepAliveTimeMinutes() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getKeepAliveTimeMinutes() must be more then 0"); } if (this.getKeepAliveTimeoutSeconds() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getKeepAliveTimeoutSeconds() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getKeepAliveTimeoutSeconds() must be more then 0"); } if (this.getPermitKeepAliveTimeMinutes() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getPermitKeepAliveTimeMinutes() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getPermitKeepAliveTimeMinutes() must be more then 0"); } if (this.getMaxConnectionAgeSeconds() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getMaxConnectionAgeSeconds() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getMaxConnectionAgeSeconds() must be more then 0"); } if (this.getMaxInboundMetadataSize() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getMaxInboundMetadataSize() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getMaxInboundMetadataSize() must be more then 0"); } if (this.getMaxInboundMessageSize() <= 0) { - throw new IllegalArgumentException("chaincodeServerProperties.getMaxInboundMessageSize() must be more then 0"); + throw new IllegalArgumentException( + "chaincodeServerProperties.getMaxInboundMessageSize() must be more then 0"); } - if (this.isTlsEnabled() && (this.getKeyCertChainFile() == null || this.getKeyCertChainFile().isEmpty() - || this.getKeyFile() == null || this.getKeyFile().isEmpty())) { + if (this.isTlsEnabled() + && (this.getKeyCertChainFile() == null + || this.getKeyCertChainFile().isEmpty() + || this.getKeyFile() == null + || this.getKeyFile().isEmpty())) { throw new IllegalArgumentException("if chaincodeServerProperties.isTlsEnabled() must be more specified" - + " chaincodeServerProperties.getKeyCertChainFile() and chaincodeServerProperties.getKeyFile()" - + " with optional chaincodeServerProperties.getKeyPassword()"); + + " chaincodeServerProperties.getKeyCertChainFile() and chaincodeServerProperties.getKeyFile()" + + " with optional chaincodeServerProperties.getKeyPassword()"); } } - - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index 7c77f5da..8c223fc4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java @@ -13,7 +13,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; - import org.hyperledger.fabric.protos.peer.ChaincodeEvent; import org.hyperledger.fabric.protos.peer.SignedProposal; import org.hyperledger.fabric.shim.Chaincode.Response; @@ -24,23 +23,21 @@ import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; /** - * An object which manages the transaction context, provides access to state variables, and supports calls to other chaincode implementations. + * An object which manages the transaction context, provides access to state variables, and supports calls to other + * chaincode implementations. */ public interface ChaincodeStub { /** - * Returns the arguments corresponding to the call to - * {@link Chaincode#init(ChaincodeStub)} or - * {@link Chaincode#invoke(ChaincodeStub)}, each argument represented as byte - * array. + * Returns the arguments corresponding to the call to {@link Chaincode#init(ChaincodeStub)} or + * {@link Chaincode#invoke(ChaincodeStub)}, each argument represented as byte array. * * @return a list of arguments (bytes arrays) */ List getArgs(); /** - * Returns the arguments corresponding to the call to - * {@link Chaincode#init(ChaincodeStub)} or + * Returns the arguments corresponding to the call to {@link Chaincode#init(ChaincodeStub)} or * {@link Chaincode#invoke(ChaincodeStub)}, cast to UTF-8 string. * * @return a list of arguments cast to UTF-8 strings @@ -48,22 +45,19 @@ public interface ChaincodeStub { List getStringArgs(); /** - * A convenience method that returns the first argument of the chaincode - * invocation for use as a function name. - *

- * The bytes of the first argument are decoded as a UTF-8 string. + * A convenience method that returns the first argument of the chaincode invocation for use as a function name. + * + *

The bytes of the first argument are decoded as a UTF-8 string. * * @return the function name */ String getFunction(); /** - * A convenience method that returns all except the first argument of the - * chaincode invocation for use as the parameters to the function returned by - * #{@link ChaincodeStub#getFunction()}. - *

- * The bytes of the arguments are decoded as a UTF-8 strings and returned as a - * list of string parameters. + * A convenience method that returns all except the first argument of the chaincode invocation for use as the + * parameters to the function returned by #{@link ChaincodeStub#getFunction()}. + * + *

The bytes of the arguments are decoded as a UTF-8 strings and returned as a list of string parameters. * * @return a list of parameters */ @@ -71,9 +65,8 @@ public interface ChaincodeStub { /** * Returns the transaction id for the current chaincode invocation request. - *

- * The transaction id uniquely identifies the transaction within the scope of - * the channel. + * + *

The transaction id uniquely identifies the transaction within the scope of the channel. * * @return the transaction id */ @@ -81,49 +74,45 @@ public interface ChaincodeStub { /** * Returns the channel id for the current proposal. - *

- * This would be the 'channel_id' of the transaction proposal except where the - * chaincode is calling another on a different channel. + * + *

This would be the 'channel_id' of the transaction proposal except where the chaincode is calling another on a + * different channel. * * @return the channel id */ String getChannelId(); /** - * Locally calls the specified chaincode invoke() using the same - * transaction context. - *

- * chaincode calling chaincode doesn't create a new transaction message. - *

- * If the called chaincode is on the same channel, it simply adds the called - * chaincode read set and write set to the calling transaction. - *

- * If the called chaincode is on a different channel, only the Response is - * returned to the calling chaincode; any putState calls from the - * called chaincode will not have any effect on the ledger; that is, the called - * chaincode on a different channel will not have its read set and write set - * applied to the transaction. Only the calling chaincode's read set and write - * set will be applied to the transaction. Effectively the called chaincode on a - * different channel is a `Query`, which does not participate in state - * validation checks in subsequent commit phase. - *

- * If `channel` is empty, the caller's channel is assumed. - *

- * Invoke another chaincode using the same transaction context. + * Locally calls the specified chaincode invoke() using the same transaction context. + * + *

chaincode calling chaincode doesn't create a new transaction message. + * + *

If the called chaincode is on the same channel, it simply adds the called chaincode read set and write set to + * the calling transaction. + * + *

If the called chaincode is on a different channel, only the Response is returned to the calling chaincode; any + * putState calls from the called chaincode will not have any effect on the ledger; that is, the called + * chaincode on a different channel will not have its read set and write set applied to the transaction. Only the + * calling chaincode's read set and write set will be applied to the transaction. Effectively the called chaincode + * on a different channel is a `Query`, which does not participate in state validation checks in subsequent commit + * phase. + * + *

If `channel` is empty, the caller's channel is assumed. + * + *

Invoke another chaincode using the same transaction context. * * @param chaincodeName Name of chaincode to be invoked. - * @param args Arguments to pass on to the called chaincode. - * @param channel If not specified, the caller's channel is assumed. + * @param args Arguments to pass on to the called chaincode. + * @param channel If not specified, the caller's channel is assumed. * @return {@link Response} object returned by called chaincode */ Response invokeChaincode(String chaincodeName, List args, String channel); /** * Returns the value of the specified key from the ledger. - *

- * Note that getState doesn't read data from the writeset, which has not been - * committed to the ledger. In other words, GetState doesn't consider data - * modified by PutState that has not been committed. + * + *

Note that getState doesn't read data from the writeset, which has not been committed to the ledger. In other + * words, GetState doesn't consider data modified by PutState that has not been committed. * * @param key name of the value * @return value the value read from the ledger @@ -131,9 +120,8 @@ public interface ChaincodeStub { byte[] getState(String key); /** - * retrieves the key-level endorsement policy for key. Note that - * this will introduce a read dependency on key in the - * transaction's readset. + * retrieves the key-level endorsement policy for key. Note that this will introduce a read dependency + * on key in the transaction's readset. * * @param key key to get key level endorsement * @return endorsement policy @@ -141,15 +129,14 @@ public interface ChaincodeStub { byte[] getStateValidationParameter(String key); /** - * Puts the specified key and value into the - * transaction's writeset as a data-write proposal. - *

- * putState doesn't effect the ledger until the transaction is validated and - * successfully committed. Simple keys must not be an empty string and must not - * start with 0x00 character, in order to avoid range query collisions with + * Puts the specified key and value into the transaction's writeset as a data-write + * proposal. + * + *

putState doesn't effect the ledger until the transaction is validated and successfully committed. Simple keys + * must not be an empty string and must not start with 0x00 character, in order to avoid range query collisions with * composite keys * - * @param key name of the value + * @param key name of the value * @param value the value to write to the ledger */ void putState(String key, byte[] value); @@ -157,79 +144,66 @@ public interface ChaincodeStub { /** * Sets the key-level endorsement policy for key. * - * @param key key to set key level endorsement + * @param key key to set key level endorsement * @param value endorsement policy */ void setStateValidationParameter(String key, byte[] value); /** - * Records the specified key to be deleted in the writeset of the - * transaction proposal. - *

- * The key and its value will be deleted from the ledger when the - * transaction is validated and successfully committed. + * Records the specified key to be deleted in the writeset of the transaction proposal. + * + *

The key and its value will be deleted from the ledger when the transaction is validated and + * successfully committed. * * @param key name of the value to be deleted */ void delState(String key); /** - * Returns all existing keys, and their values, that are lexicographically - * between startkey (inclusive) and the endKey - * (exclusive). - *

- * The keys are returned by the iterator in lexical order. Note that startKey - * and endKey can be empty string, which implies unbounded range query on start - * or end. - *

- * Call close() on the returned {@link QueryResultsIterator#close()} object when - * done. + * Returns all existing keys, and their values, that are lexicographically between startkey (inclusive) + * and the endKey (exclusive). + * + *

The keys are returned by the iterator in lexical order. Note that startKey and endKey can be empty string, + * which implies unbounded range query on start or end. + * + *

Call close() on the returned {@link QueryResultsIterator#close()} object when done. * * @param startKey key as the start of the key range (inclusive) - * @param endKey key as the end of the key range (exclusive) + * @param endKey key as the end of the key range (exclusive) * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getStateByRange(String startKey, String endKey); /** - * Returns a range iterator over a set of keys in the ledger. The iterator can - * be used to fetch keys between the startKey (inclusive) and - * endKey (exclusive). When an empty string is passed as a value to - * the bookmark argument, the returned iterator can be used to - * fetch the first pageSize keys between the startKey - * and endKey. When the bookmark is a non-empty - * string, the iterator can be used to fetch first pageSize keys - * between the bookmark and endKey. Note that only the - * bookmark present in a prior page of query results - * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) - * can be used as a value to the bookmark argument. Otherwise, an empty string - * must be passed as bookmark. The keys are returned by the iterator in lexical - * order. Note that startKey and endKey can be empty - * string, which implies unbounded range query on start or end. This call is - * only supported in a read only transaction. + * Returns a range iterator over a set of keys in the ledger. The iterator can be used to fetch keys between the + * startKey (inclusive) and endKey (exclusive). When an empty string is passed as a value + * to the bookmark argument, the returned iterator can be used to fetch the first pageSize + * keys between the startKey and endKey. When the bookmark is a non-empty + * string, the iterator can be used to fetch first pageSize keys between the bookmark and + * endKey. Note that only the bookmark present in a prior page of query results + * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) can be used as a value to the bookmark + * argument. Otherwise, an empty string must be passed as bookmark. The keys are returned by the iterator in lexical + * order. Note that startKey and endKey can be empty string, which implies unbounded range + * query on start or end. This call is only supported in a read only transaction. * * @param startKey the start key - * @param endKey the end key + * @param endKey the end key * @param pageSize the page size * @param bookmark the bookmark * @return QueryIterator */ - QueryResultsIteratorWithMetadata getStateByRangeWithPagination(String startKey, String endKey, int pageSize, String bookmark); + QueryResultsIteratorWithMetadata getStateByRangeWithPagination( + String startKey, String endKey, int pageSize, String bookmark); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey}. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. - *

- * This method takes responsibility to correctly parse the {@link CompositeKey} - * from a String and behaves exactly as - * {@link ChaincodeStub#getStateByPartialCompositeKey(CompositeKey)}. - *

- *

- * Call close() on the returned {@link QueryResultsIterator#close()} object when - * done. + * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey}. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. + * + *

This method takes responsibility to correctly parse the {@link CompositeKey} from a String and behaves exactly + * as {@link ChaincodeStub#getStateByPartialCompositeKey(CompositeKey)}. + * + *

Call close() on the returned {@link QueryResultsIterator#close()} object when done. * * @param compositeKey partial composite key * @return an {@link Iterable} of {@link KeyValue} @@ -237,21 +211,15 @@ public interface ChaincodeStub { QueryResultsIterator getStateByPartialCompositeKey(String compositeKey); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey}. - *

- * It combines the attributes and the objectType to form a partial composite - * key. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. - *

- * This method takes responsibility to correctly combine Object type and - * attributes creating a {@link CompositeKey} and behaves exactly as - * {@link ChaincodeStub#getStateByPartialCompositeKey(CompositeKey)}. - *

- * Call close() on the returned {@link QueryResultsIterator#close()} object when - * done. + * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey}. + * + *

It combines the attributes and the objectType to form a partial composite key. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. + * + *

This method takes responsibility to correctly combine Object type and attributes creating a + * {@link CompositeKey} and behaves exactly as {@link ChaincodeStub#getStateByPartialCompositeKey(CompositeKey)}. + * Call close() on the returned {@link QueryResultsIterator#close()} object when done. * * @param objectType ObjectType of the compositeKey * @param attributes Attributes of the composite key @@ -260,11 +228,9 @@ public interface ChaincodeStub { QueryResultsIterator getStateByPartialCompositeKey(String objectType, String... attributes); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey}. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. + * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey}. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. * * @param compositeKey partial composite key * @return an {@link Iterable} of {@link KeyValue} @@ -272,36 +238,32 @@ public interface ChaincodeStub { QueryResultsIterator getStateByPartialCompositeKey(CompositeKey compositeKey); /** - * Queries the state in the ledger based on a given partial composite key. This - * function returns an iterator which can be used to iterate over the composite - * keys whose prefix matches the given partial composite key. - *

- * When an empty string is passed as a value to the bookmark - * argument, the returned iterator can be used to fetch the first - * pageSize composite keys whose prefix matches the given partial - * composite key. - *

- * When the bookmark is a non-empty string, the iterator can be - * used to fetch first pageSize keys between the - * bookmark (inclusive) and and the last matching composite key. - *

- * Note that only the bookmark present in a prior page of query results - * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) - * can be used as a value to the bookmark argument. Otherwise, an empty string - * must be passed as bookmark. - *

- * This call is only supported in a read only transaction. + * Queries the state in the ledger based on a given partial composite key. This function returns an iterator which + * can be used to iterate over the composite keys whose prefix matches the given partial composite key. + * + *

When an empty string is passed as a value to the bookmark argument, the returned iterator can be + * used to fetch the first pageSize composite keys whose prefix matches the given partial composite + * key. + * + *

When the bookmark is a non-empty string, the iterator can be used to fetch first pageSize + * keys between the bookmark (inclusive) and and the last matching composite key. + * + *

Note that only the bookmark present in a prior page of query results + * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) can be used as a value to the bookmark + * argument. Otherwise, an empty string must be passed as bookmark. + * + *

This call is only supported in a read only transaction. * * @param compositeKey the composite key - * @param pageSize the page size - * @param bookmark the bookmark + * @param pageSize the page size + * @param bookmark the bookmark * @return QueryIterator */ - QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(CompositeKey compositeKey, int pageSize, String bookmark); + QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination( + CompositeKey compositeKey, int pageSize, String bookmark); /** - * Given a set of attributes, this method combines these attributes to return a - * composite key. + * Given a set of attributes, this method combines these attributes to return a composite key. * * @param objectType A string used as the prefix of the resulting key * @param attributes List of attribute values to concatenate into the key @@ -319,53 +281,46 @@ public interface ChaincodeStub { /** * Performs a "rich" query against a state database. - *

- * It is only supported for state databases that support rich query, e.g. - * CouchDB. The query string is in the native syntax of the underlying state - * database. An {@link QueryResultsIterator} is returned which can be used to + * + *

It is only supported for state databases that support rich query, e.g. CouchDB. The query string is in the + * native syntax of the underlying state database. An {@link QueryResultsIterator} is returned which can be used to * iterate (next) over the query result set. * - * @param query query string in a syntax supported by the underlying state - * database + * @param query query string in a syntax supported by the underlying state database * @return {@link QueryResultsIterator} object contains query results - * @throws UnsupportedOperationException if the underlying state database does - * not support rich queries. + * @throws UnsupportedOperationException if the underlying state database does not support rich queries. */ QueryResultsIterator getQueryResult(String query); /** - * Performs a "rich" query against a state database. It is only supported for - * state databases that support rich query, e.g., CouchDB. The query string is - * in the native syntax of the underlying state database. An iterator is - * returned which can be used to iterate over keys in the query result set. When - * an empty string is passed as a value to the bookmark argument, - * the returned iterator can be used to fetch the first pageSize of - * query results.. - *

- * When the bookmark is a non-empty string, the iterator can be - * used to fetch first pageSize keys between the - * bookmark (inclusive) and the last key in the query result. - *

- * Note that only the bookmark present in a prior page of query results - * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) - * can be used as a value to the bookmark argument. Otherwise, an empty string - * must be passed as bookmark. - *

- * This call is only supported in a read only transaction. - * - * @param query the query + * Performs a "rich" query against a state database. It is only supported for state databases that support rich + * query, e.g., CouchDB. The query string is in the native syntax of the underlying state database. An iterator is + * returned which can be used to iterate over keys in the query result set. When an empty string is passed as a + * value to the bookmark argument, the returned iterator can be used to fetch the first pageSize + * of query results.. + * + *

When the bookmark is a non-empty string, the iterator can be used to fetch first pageSize + * keys between the bookmark (inclusive) and the last key in the query result. + * + *

Note that only the bookmark present in a prior page of query results + * ({@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}) can be used as a value to the bookmark + * argument. Otherwise, an empty string must be passed as bookmark. + * + *

This call is only supported in a read only transaction. + * + * @param query the query * @param pageSize the page size * @param bookmark the bookmark * @return QueryIterator */ - QueryResultsIteratorWithMetadata getQueryResultWithPagination(String query, int pageSize, String bookmark); + QueryResultsIteratorWithMetadata getQueryResultWithPagination( + String query, int pageSize, String bookmark); /** * Returns a history of key values across time. - *

- * For each historic key update, the historic value and associated transaction - * id and timestamp are returned. The timestamp is the timestamp provided by the - * client in the proposal header. This method requires peer configuration + * + *

For each historic key update, the historic value and associated transaction id and timestamp are returned. The + * timestamp is the timestamp provided by the client in the proposal header. This method requires peer configuration * core.ledger.history.enableHistoryDatabase to be true. * * @param key The state variable key @@ -374,227 +329,197 @@ public interface ChaincodeStub { QueryResultsIterator getHistoryForKey(String key); /** - * Returns the value of the specified key from the specified - * collection. - *

- * Note that {@link #getPrivateData(String, String)} doesn't read data from the - * private writeset, which has not been committed to the - * collection. In other words, - * {@link #getPrivateData(String, String)} doesn't consider data modified by - * {@link #putPrivateData(String, String, byte[])} * that has not been - * committed. + * Returns the value of the specified key from the specified collection. + * + *

Note that {@link #getPrivateData(String, String)} doesn't read data from the private writeset, which has not + * been committed to the collection. In other words, {@link #getPrivateData(String, String)} doesn't + * consider data modified by {@link #putPrivateData(String, String, byte[])} * that has not been committed. * * @param collection name of the collection - * @param key name of the value + * @param key name of the value * @return value the value read from the collection */ byte[] getPrivateData(String collection, String key); /** * @param collection name of the collection - * @param key name of the value + * @param key name of the value * @return the private data hash */ byte[] getPrivateDataHash(String collection, String key); /** - * Retrieves the key-level endorsement policy for the private data specified by - * key. Note that this introduces a read dependency on - * key in the transaction's readset. + * Retrieves the key-level endorsement policy for the private data specified by key. Note that this + * introduces a read dependency on key in the transaction's readset. * * @param collection name of the collection - * @param key key to get endorsement policy + * @param key key to get endorsement policy * @return Key Level endorsement as byte array */ byte[] getPrivateDataValidationParameter(String collection, String key); /** - * Puts the specified key and value into the - * transaction's private writeset. - *

- * Note that only hash of the private writeset goes into the transaction - * proposal response (which is sent to the client who issued the transaction) - * and the actual private writeset gets temporarily stored in a transient store. - * putPrivateData doesn't effect the collection until the - * transaction is validated and successfully committed. Simple keys must not be - * an empty string and must not start with null character (0x00), in order to - * avoid range query collisions with composite keys, which internally get - * prefixed with 0x00 as composite key namespace. + * Puts the specified key and value into the transaction's private writeset. + * + *

Note that only hash of the private writeset goes into the transaction proposal response (which is sent to the + * client who issued the transaction) and the actual private writeset gets temporarily stored in a transient store. + * putPrivateData doesn't effect the collection until the transaction is validated and successfully + * committed. Simple keys must not be an empty string and must not start with null character (0x00), in order to + * avoid range query collisions with composite keys, which internally get prefixed with 0x00 as composite key + * namespace. * * @param collection name of the collection - * @param key name of the value - * @param value the value to write to the ledger + * @param key name of the value + * @param value the value to write to the ledger */ void putPrivateData(String collection, String key, byte[] value); /** - * Sets the key-level endorsement policy for the private data specified by - * key. + * Sets the key-level endorsement policy for the private data specified by key. * * @param collection name of the collection - * @param key key to set endorsement policy - * @param value endorsement policy + * @param key key to set endorsement policy + * @param value endorsement policy */ void setPrivateDataValidationParameter(String collection, String key, byte[] value); /** - * Records the specified key to be deleted in the private writeset - * of the transaction. - *

- * Note that only hash of the private writeset goes into the transaction - * proposal response (which is sent to the client who issued the transaction) - * and the actual private writeset gets temporarily stored in a transient store. - * The key and its value will be deleted from the collection when - * the transaction is validated and successfully committed. + * Records the specified key to be deleted in the private writeset of the transaction. + * + *

Note that only hash of the private writeset goes into the transaction proposal response (which is sent to the + * client who issued the transaction) and the actual private writeset gets temporarily stored in a transient store. + * The key and its value will be deleted from the collection when the transaction is validated and + * successfully committed. * * @param collection name of the collection - * @param key name of the value to be deleted + * @param key name of the value to be deleted */ void delPrivateData(String collection, String key); /** - * Reqauests purging of the specified key to be from - * the private data stores. - *

- * Note that only hash of the private writeset goes into the transaction - * proposal response (which is sent to the client who issued the transaction) - * and the actual private writeset gets temporarily stored in a transient store. - * The key and its value will be purged from the collection. This is an - * asynchronous activity. - *

- * Purge is a complete removal of the history of the key. There is existing purge - * possible mased on block height. This API allows the contract to be pro-active in - * requesting data be purged. This can contribute towards meeting privacy requirements. + * Reqauests purging of the specified key to be from the private data stores. + * + *

Note that only hash of the private writeset goes into the transaction proposal response (which is sent to the + * client who issued the transaction) and the actual private writeset gets temporarily stored in a transient store. + * The key and its value will be purged from the collection. This is an asynchronous activity. + * + *

Purge is a complete removal of the history of the key. There is existing purge possible mased on block height. + * This API allows the contract to be pro-active in requesting data be purged. This can contribute towards meeting + * privacy requirements. * * @param collection name of the collection - * @param key name of the value to be deleted + * @param key name of the value to be deleted */ void purgePrivateData(String collection, String key); /** - * Returns all existing keys, and their values, that are lexicographically - * between startkey (inclusive) and the endKey - * (exclusive) in a given private collection. - *

- * Note that startKey and endKey can be empty string, which implies unbounded - * range query on start or end. The query is re-executed during validation phase - * to ensure result set has not changed since transaction endorsement (phantom - * reads detected). + * Returns all existing keys, and their values, that are lexicographically between startkey (inclusive) + * and the endKey (exclusive) in a given private collection. + * + *

Note that startKey and endKey can be empty string, which implies unbounded range query on start or end. The + * query is re-executed during validation phase to ensure result set has not changed since transaction endorsement + * (phantom reads detected). * * @param collection name of the collection - * @param startKey private data variable key as the start of the key range - * (inclusive) - * @param endKey private data variable key as the end of the key range - * (exclusive) + * @param startKey private data variable key as the start of the key range (inclusive) + * @param endKey private data variable key as the end of the key range (exclusive) * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getPrivateDataByRange(String collection, String startKey, String endKey); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey} in a given private collection. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. - *

- * The query is re-executed during validation phase to ensure result set has not - * changed since transaction endorsement (phantom reads detected). - *

- * This method takes responsibility to correctly parse the {@link CompositeKey} - * from a String and behaves exactly as - * {@link ChaincodeStub#getPrivateDataByPartialCompositeKey(String, CompositeKey)}. - *

- * - * @param collection name of the collection + * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey} in a + * given private collection. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. + * + *

The query is re-executed during validation phase to ensure result set has not changed since transaction + * endorsement (phantom reads detected). + * + *

This method takes responsibility to correctly parse the {@link CompositeKey} from a String and behaves exactly + * as {@link ChaincodeStub#getPrivateDataByPartialCompositeKey(String, CompositeKey)}. + * + * @param collection name of the collection * @param compositeKey partial composite key * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String compositeKey); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey} in a given private collection. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. - *

- * The query is re-executed during validation phase to ensure result set has not - * changed since transaction endorsement (phantom reads detected). + * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey} in a + * given private collection. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. + * + *

The query is re-executed during validation phase to ensure result set has not changed since transaction + * endorsement (phantom reads detected). * - * @param collection name of the collection + * @param collection name of the collection * @param compositeKey partial composite key * @return an {@link Iterable} of {@link KeyValue} */ QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, CompositeKey compositeKey); /** - * Returns all existing keys, and their values, that are prefixed by the - * specified partial {@link CompositeKey} in a given private collection. - *

- * If a full composite key is specified, it will not match itself, resulting in - * no keys being returned. - *

- * The query is re-executed during validation phase to ensure result set has not - * changed since transaction endorsement (phantom reads detected). - *

- * This method takes responsibility to correctly combine Object type and - * attributes creating a {@link CompositeKey} and behaves exactly as - * {@link ChaincodeStub#getPrivateDataByPartialCompositeKey(String, CompositeKey)}. - *

+ * Returns all existing keys, and their values, that are prefixed by the specified partial {@link CompositeKey} in a + * given private collection. + * + *

If a full composite key is specified, it will not match itself, resulting in no keys being returned. + * + *

The query is re-executed during validation phase to ensure result set has not changed since transaction + * endorsement (phantom reads detected). + * + *

This method takes responsibility to correctly combine Object type and attributes creating a + * {@link CompositeKey} and behaves exactly as {@link ChaincodeStub#getPrivateDataByPartialCompositeKey(String, + * CompositeKey)}. * * @param collection name of the collection * @param objectType ObjectType of the compositeKey * @param attributes Attributes of the composite key * @return an {@link Iterable} of {@link KeyValue} */ - QueryResultsIterator getPrivateDataByPartialCompositeKey(String collection, String objectType, String... attributes); + QueryResultsIterator getPrivateDataByPartialCompositeKey( + String collection, String objectType, String... attributes); /** * Perform a rich query against a given private collection. - *

- * It is only supported for state databases that support rich query, - * e.g.CouchDB. The query string is in the native syntax of the underlying state - * database. An iterator is returned which can be used to iterate (next) over - * the query result set. The query is NOT re-executed during validation phase, - * phantom reads are not detected. That is, other committed transactions may - * have added, updated, or removed keys that impact the result set, and this - * would not be detected at validation/commit time. Applications susceptible to - * this should therefore not use GetQueryResult as part of transactions that - * update ledger, and should limit use to read-only chaincode operations. + * + *

It is only supported for state databases that support rich query, e.g.CouchDB. The query string is in the + * native syntax of the underlying state database. An iterator is returned which can be used to iterate (next) over + * the query result set. The query is NOT re-executed during validation phase, phantom reads are not detected. That + * is, other committed transactions may have added, updated, or removed keys that impact the result set, and this + * would not be detected at validation/commit time. Applications susceptible to this should therefore not use + * GetQueryResult as part of transactions that update ledger, and should limit use to read-only chaincode + * operations. * * @param collection name of the collection - * @param query query string in a syntax supported by the underlying state - * database + * @param query query string in a syntax supported by the underlying state database * @return {@link QueryResultsIterator} object contains query results - * @throws UnsupportedOperationException if the underlying state database does - * not support rich queries. + * @throws UnsupportedOperationException if the underlying state database does not support rich queries. */ QueryResultsIterator getPrivateDataQueryResult(String collection, String query); /** - * Allows the chaincode to propose an event on the transaction proposal response. - * When the transaction is included in a block and the block is successfully committed to the ledger, - * the block event (including transaction level chaincode events) - * will be delivered to the current client application event listeners that have been registered with the peer's event producer. - * Consult each SDK's documentation for details. - * Only a single chaincode event can be included in a transaction. - * If setEvent() is called multiple times only the last event will be included in the transaction. - * The event must originate from the outer-most invoked chaincode in chaincode-to-chaincode scenarios. + * Allows the chaincode to propose an event on the transaction proposal response. When the transaction is included + * in a block and the block is successfully committed to the ledger, the block event (including transaction level + * chaincode events) will be delivered to the current client application event listeners that have been registered + * with the peer's event producer. Consult each SDK's documentation for details. Only a single chaincode event can + * be included in a transaction. If setEvent() is called multiple times only the last event will be included in the + * transaction. The event must originate from the outer-most invoked chaincode in chaincode-to-chaincode scenarios. * The marshaled ChaincodeEvent will be available in the transaction's ChaincodeAction.events field. * - * @param name Name of event. Cannot be null or empty string. + * @param name Name of event. Cannot be null or empty string. * @param payload Optional event payload. */ void setEvent(String name, byte[] payload); /** * Invoke another chaincode using the same transaction context. - *

- * Same as {@link #invokeChaincode(String, List, String)} using channelId to - * null + * + *

Same as {@link #invokeChaincode(String, List, String)} using channelId to null * * @param chaincodeName Name of chaincode to be invoked. - * @param args Arguments to pass on to the called chaincode. + * @param args Arguments to pass on to the called chaincode. * @return {@link Response} object returned by called chaincode */ default Response invokeChaincode(final String chaincodeName, final List args) { @@ -603,28 +528,29 @@ default Response invokeChaincode(final String chaincodeName, final List /** * Invoke another chaincode using the same transaction context. - *

- * This is a convenience version of - * {@link #invokeChaincode(String, List, String)}. The string args will be + * + *

This is a convenience version of {@link #invokeChaincode(String, List, String)}. The string args will be * encoded into as UTF-8 bytes. * * @param chaincodeName Name of chaincode to be invoked. - * @param args Arguments to pass on to the called chaincode. - * @param channel If not specified, the caller's channel is assumed. + * @param args Arguments to pass on to the called chaincode. + * @param channel If not specified, the caller's channel is assumed. * @return {@link Response} object returned by called chaincode */ - default Response invokeChaincodeWithStringArgs(final String chaincodeName, final List args, final String channel) { - return invokeChaincode(chaincodeName, args.stream().map(x -> x.getBytes(UTF_8)).collect(toList()), channel); + default Response invokeChaincodeWithStringArgs( + final String chaincodeName, final List args, final String channel) { + return invokeChaincode( + chaincodeName, args.stream().map(x -> x.getBytes(UTF_8)).collect(toList()), channel); } /** * Invoke another chaincode using the same transaction context. - *

- * This is a convenience version of {@link #invokeChaincode(String, List)}. The - * string args will be encoded into as UTF-8 bytes. + * + *

This is a convenience version of {@link #invokeChaincode(String, List)}. The string args will be encoded into + * as UTF-8 bytes. * * @param chaincodeName Name of chaincode to be invoked. - * @param args Arguments to pass on to the called chaincode. + * @param args Arguments to pass on to the called chaincode. * @return {@link Response} object returned by called chaincode */ default Response invokeChaincodeWithStringArgs(final String chaincodeName, final List args) { @@ -633,12 +559,12 @@ default Response invokeChaincodeWithStringArgs(final String chaincodeName, final /** * Invoke another chaincode using the same transaction context. - *

- * This is a convenience version of {@link #invokeChaincode(String, List)}. The - * string args will be encoded into as UTF-8 bytes. + * + *

This is a convenience version of {@link #invokeChaincode(String, List)}. The string args will be encoded into + * as UTF-8 bytes. * * @param chaincodeName Name of chaincode to be invoked. - * @param args Arguments to pass on to the called chaincode. + * @param args Arguments to pass on to the called chaincode. * @return {@link Response} object returned by called chaincode */ default Response invokeChaincodeWithStringArgs(final String chaincodeName, final String... args) { @@ -646,10 +572,9 @@ default Response invokeChaincodeWithStringArgs(final String chaincodeName, final } /** - * Returns the byte array value specified by the key and decoded as a UTF-8 - * encoded string, from the ledger. - *

- * This is a convenience version of {@link #getState(String)} + * Returns the byte array value specified by the key and decoded as a UTF-8 encoded string, from the ledger. + * + *

This is a convenience version of {@link #getState(String)} * * @param key name of the value * @return value the value read from the ledger @@ -659,24 +584,22 @@ default String getStringState(final String key) { } /** - * Writes the specified value and key into the sidedb collection value converted - * to byte array. + * Writes the specified value and key into the sidedb collection value converted to byte array. * * @param collection collection name - * @param key name of the value - * @param value the value to write to the ledger + * @param key name of the value + * @param value the value to write to the ledger */ - default void putPrivateData(final String collection, final String key, final String value) { putPrivateData(collection, key, value.getBytes(UTF_8)); } /** - * Returns the byte array value specified by the key and decoded as a UTF-8 - * encoded string, from the sidedb collection. + * Returns the byte array value specified by the key and decoded as a UTF-8 encoded string, from the sidedb + * collection. * * @param collection collection name - * @param key name of the value + * @param key name of the value * @return value the value read from the ledger */ default String getPrivateDataUTF8(final String collection, final String key) { @@ -686,7 +609,7 @@ default String getPrivateDataUTF8(final String collection, final String key) { /** * Writes the specified value and key into the ledger. * - * @param key name of the value + * @param key name of the value * @param value the value to write to the ledger */ default void putStringState(final String key, final String value) { @@ -694,8 +617,8 @@ default void putStringState(final String key, final String value) { } /** - * Returns the CHAINCODE type event that will be posted to interested clients - * when the chaincode's result is committed to the ledger. + * Returns the CHAINCODE type event that will be posted to interested clients when the chaincode's result is + * committed to the ledger. * * @return the chaincode event or null */ @@ -704,8 +627,7 @@ default void putStringState(final String key, final String value) { /** * Returns the signed transaction proposal currently being executed. * - * @return null if the current transaction is an internal call to a system - * chaincode. + * @return null if the current transaction is an internal call to a system chaincode. */ SignedProposal getSignedProposal(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java index 88bf0361..f53d0ad1 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java @@ -6,13 +6,12 @@ package org.hyperledger.fabric.shim; import io.grpc.stub.StreamObserver; +import java.io.IOException; +import java.util.logging.Logger; import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.peer.ChaincodeGrpc; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; -import java.io.IOException; -import java.util.logging.Logger; - public class ChatChaincodeWithPeer extends ChaincodeGrpc.ChaincodeImplBase { private static Logger logger = Logger.getLogger(ChatChaincodeWithPeer.class.getName()); @@ -28,8 +27,8 @@ public class ChatChaincodeWithPeer extends ChaincodeGrpc.ChaincodeImplBase { } /** - * Chaincode as a server - peer establishes a connection to the chaincode as a client - * Currently only supports a stream connection. + * Chaincode as a server - peer establishes a connection to the chaincode as a client Currently only supports a + * stream connection. * * @param responseObserver * @return @@ -43,7 +42,8 @@ public StreamObserver connect(final StreamObserver "catch exception while chaincodeBase.connectToPeer(responseObserver)." + Logging.formatError(e)); + logger.severe(() -> + "catch exception while chaincodeBase.connectToPeer(responseObserver)." + Logging.formatError(e)); return null; } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/GrpcServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/GrpcServer.java index aa10efc3..9460dd22 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/GrpcServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/GrpcServer.java @@ -8,9 +8,7 @@ import java.io.IOException; -/** - * Common interface for grpc server. - */ +/** Common interface for grpc server. */ public interface GrpcServer { /** @@ -20,9 +18,7 @@ public interface GrpcServer { */ void start() throws IOException; - /** - * shutdown now grpc server. - */ + /** shutdown now grpc server. */ void stop(); /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java index a7073d78..df594ed2 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java @@ -10,9 +10,7 @@ public class NettyChaincodeServer implements ChaincodeServer { - /** - * Server. - */ + /** Server. */ private final GrpcServer grpcServer; /** @@ -22,7 +20,9 @@ public class NettyChaincodeServer implements ChaincodeServer { * @param chaincodeServerProperties - setting for grpc server * @throws IOException */ - public NettyChaincodeServer(final ChaincodeBase chaincodeBase, final ChaincodeServerProperties chaincodeServerProperties) throws IOException { + public NettyChaincodeServer( + final ChaincodeBase chaincodeBase, final ChaincodeServerProperties chaincodeServerProperties) + throws IOException { // create listener and grpc server grpcServer = new NettyGrpcServer(chaincodeBase, chaincodeServerProperties); } @@ -30,7 +30,7 @@ public NettyChaincodeServer(final ChaincodeBase chaincodeBase, final ChaincodeSe /** * run external chaincode server. * - * @throws IOException problem while start grpc server + * @throws IOException problem while start grpc server * @throws InterruptedException thrown when block and awaiting shutdown gprc server */ public void start() throws IOException, InterruptedException { @@ -38,9 +38,7 @@ public void start() throws IOException, InterruptedException { grpcServer.blockUntilShutdown(); } - /** - * shutdown now grpc server. - */ + /** shutdown now grpc server. */ public void stop() { grpcServer.stop(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java index 4d6e9c33..bb142337 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java @@ -6,23 +6,19 @@ package org.hyperledger.fabric.shim; - import io.grpc.Server; import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolConfig; import io.grpc.netty.shaded.io.netty.handler.ssl.ApplicationProtocolNames; import io.grpc.netty.shaded.io.netty.handler.ssl.ClientAuth; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; -import java.util.logging.Logger; - import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; -/** - * implementation grpc server with NettyGrpcServer. - */ +/** implementation grpc server with NettyGrpcServer. */ public final class NettyGrpcServer implements GrpcServer { private static final Logger LOGGER = Logger.getLogger(NettyGrpcServer.class.getName()); @@ -32,11 +28,12 @@ public final class NettyGrpcServer implements GrpcServer { /** * init netty grpc server. * - * @param chaincodeBase - chaincode implementation (invoke, init) + * @param chaincodeBase - chaincode implementation (invoke, init) * @param chaincodeServerProperties - setting for grpc server * @throws IOException */ - public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerProperties chaincodeServerProperties) throws IOException { + public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerProperties chaincodeServerProperties) + throws IOException { if (chaincodeBase == null) { throw new IllegalArgumentException("chaincode must be specified"); } @@ -45,7 +42,8 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP } chaincodeServerProperties.validate(); - final NettyServerBuilder serverBuilder = NettyServerBuilder.forAddress(chaincodeServerProperties.getServerAddress()) + final NettyServerBuilder serverBuilder = NettyServerBuilder.forAddress( + chaincodeServerProperties.getServerAddress()) .addService(new ChatChaincodeWithPeer(chaincodeBase)) .keepAliveTime(chaincodeServerProperties.getKeepAliveTimeMinutes(), TimeUnit.MINUTES) .keepAliveTimeout(chaincodeServerProperties.getKeepAliveTimeoutSeconds(), TimeUnit.SECONDS) @@ -56,14 +54,18 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP .maxInboundMessageSize(chaincodeServerProperties.getMaxInboundMessageSize()); if (chaincodeServerProperties.isTlsEnabled()) { - final File keyCertChainFile = Paths.get(chaincodeServerProperties.getKeyCertChainFile()).toFile(); - final File keyFile = Paths.get(chaincodeServerProperties.getKeyFile()).toFile(); + final File keyCertChainFile = + Paths.get(chaincodeServerProperties.getKeyCertChainFile()).toFile(); + final File keyFile = + Paths.get(chaincodeServerProperties.getKeyFile()).toFile(); SslContextBuilder sslContextBuilder; - if (chaincodeServerProperties.getKeyPassword() == null || chaincodeServerProperties.getKeyPassword().isEmpty()) { + if (chaincodeServerProperties.getKeyPassword() == null + || chaincodeServerProperties.getKeyPassword().isEmpty()) { sslContextBuilder = SslContextBuilder.forServer(keyCertChainFile, keyFile); } else { - sslContextBuilder = SslContextBuilder.forServer(keyCertChainFile, keyFile, chaincodeServerProperties.getKeyPassword()); + sslContextBuilder = SslContextBuilder.forServer( + keyCertChainFile, keyFile, chaincodeServerProperties.getKeyPassword()); } ApplicationProtocolConfig apn = new ApplicationProtocolConfig( @@ -74,7 +76,8 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP sslContextBuilder.applicationProtocolConfig(apn); if (chaincodeServerProperties.getTrustCertCollectionFile() != null) { - final File trustCertCollectionFile = Paths.get(chaincodeServerProperties.getTrustCertCollectionFile()).toFile(); + final File trustCertCollectionFile = Paths.get(chaincodeServerProperties.getTrustCertCollectionFile()) + .toFile(); sslContextBuilder.clientAuth(ClientAuth.REQUIRE); sslContextBuilder.trustManager(trustCertCollectionFile); } @@ -83,7 +86,8 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP } LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>:\n"); - LOGGER.info("ServerAddress:" + chaincodeServerProperties.getServerAddress().toString()); + LOGGER.info( + "ServerAddress:" + chaincodeServerProperties.getServerAddress().toString()); LOGGER.info("MaxInboundMetadataSize:" + chaincodeServerProperties.getMaxInboundMetadataSize()); LOGGER.info("MaxInboundMessageSize:" + chaincodeServerProperties.getMaxInboundMessageSize()); LOGGER.info("MaxConnectionAgeSeconds:" + chaincodeServerProperties.getMaxConnectionAgeSeconds()); @@ -107,14 +111,12 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP */ public void start() throws IOException { LOGGER.info("start grpc server"); - Runtime.getRuntime() - .addShutdownHook( - new Thread(() -> { - // Use stderr here since the logger may have been reset by its JVM shutdown hook. - System.err.println("*** shutting down gRPC server since JVM is shutting down"); - NettyGrpcServer.this.stop(); - System.err.println("*** server shut down"); - })); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + NettyGrpcServer.this.stop(); + System.err.println("*** server shut down"); + })); server.start(); } @@ -128,9 +130,7 @@ public void blockUntilShutdown() throws InterruptedException { server.awaitTermination(); } - /** - * shutdown now grpc server. - */ + /** shutdown now grpc server. */ public void stop() { LOGGER.info("shutdown now grpc server."); server.shutdownNow(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java index c46e1a78..bd6ee06e 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java @@ -14,8 +14,7 @@ public final class ResponseUtils { private static Logger logger = Logger.getLogger(ResponseUtils.class.getName()); - private ResponseUtils() { - } + private ResponseUtils() {} /** * @param message @@ -26,9 +25,7 @@ public static Chaincode.Response newSuccessResponse(final String message, final return new Chaincode.Response(SUCCESS, message, payload); } - /** - * @return Chaincode.Response - */ + /** @return Chaincode.Response */ public static Chaincode.Response newSuccessResponse() { return newSuccessResponse(null, null); } @@ -58,9 +55,7 @@ public static Chaincode.Response newErrorResponse(final String message, final by return new Chaincode.Response(INTERNAL_SERVER_ERROR, message, payload); } - /** - * @return Chaincode.Response - */ + /** @return Chaincode.Response */ public static Chaincode.Response newErrorResponse() { return newErrorResponse(null, null); } @@ -100,7 +95,5 @@ public static Chaincode.Response newErrorResponse(final Throwable throwable) { message = "Unexpected error"; return ResponseUtils.newErrorResponse(message, payload); } - - } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java index a7b25020..c390ef90 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java @@ -10,10 +10,9 @@ import java.util.Map; /** - * StateBasedEndorsement provides a set of convenience methods to create and - * modify a state-based endorsement policy. Endorsement policies created by this - * convenience layer will always be a logical AND of "ORG.peer" principals for - * one or more ORGs specified by the caller. + * StateBasedEndorsement provides a set of convenience methods to create and modify a state-based endorsement policy. + * Endorsement policies created by this convenience layer will always be a logical AND of "ORG.peer" principals for one + * or more ORGs specified by the caller. */ public interface StateBasedEndorsement { /** @@ -24,20 +23,18 @@ public interface StateBasedEndorsement { byte[] policy(); /** - * Adds the specified orgs to the list of orgs that are required to endorse. All - * orgs MSP role types will be set to the role that is specified in the first - * parameter. Among other aspects the desired role depends on the channel's - * configuration: if it supports node OUs, it is likely going to be the PEER - * role, while the MEMBER role is the suited one if it does not. + * Adds the specified orgs to the list of orgs that are required to endorse. All orgs MSP role types will be set to + * the role that is specified in the first parameter. Among other aspects the desired role depends on the channel's + * configuration: if it supports node OUs, it is likely going to be the PEER role, while the MEMBER role is the + * suited one if it does not. * - * @param roleType the MSP role type + * @param roleType the MSP role type * @param organizations the list of organizations */ void addOrgs(RoleType roleType, String... organizations); /** - * deletes the specified channel orgs from the existing key-level endorsement - * policy for this KVS key. + * deletes the specified channel orgs from the existing key-level endorsement policy for this KVS key. * * @param organizations the list of organizations */ @@ -50,17 +47,11 @@ public interface StateBasedEndorsement { */ List listOrgs(); - /** - * RoleType of an endorsement policy's identity. - */ + /** RoleType of an endorsement policy's identity. */ enum RoleType { - /** - * RoleTypeMember identifies an org's member identity. - */ + /** RoleTypeMember identifies an org's member identity. */ RoleTypeMember("MEMBER"), - /** - * RoleTypePeer identifies an org's peer identity. - */ + /** RoleTypePeer identifies an org's peer identity. */ RoleTypePeer("PEER"); private final String val; @@ -69,10 +60,7 @@ enum RoleType { this.val = val; } - /** - * - * @return String value - */ + /** @return String value */ public String getVal() { return val; } @@ -86,7 +74,6 @@ public String getVal() { } /** - * * @param val * @return RoleType */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java index da1db8ca..f93fc6ce 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java @@ -7,16 +7,11 @@ import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; -/** - * Factory for {@link StateBasedEndorsement} objects. - */ +/** Factory for {@link StateBasedEndorsement} objects. */ public class StateBasedEndorsementFactory { private static StateBasedEndorsementFactory instance; - /** - * - * @return Endorsement Factory - */ + /** @return Endorsement Factory */ public static synchronized StateBasedEndorsementFactory getInstance() { if (instance == null) { instance = new StateBasedEndorsementFactory(); @@ -25,8 +20,8 @@ public static synchronized StateBasedEndorsementFactory getInstance() { } /** - * Constructs a state-based endorsement policy from a given serialized EP byte - * array. If the byte array is empty, a new EP is created. + * Constructs a state-based endorsement policy from a given serialized EP byte array. If the byte array is empty, a + * new EP is created. * * @param ep serialized endorsement policy * @return New StateBasedEndorsement instance diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java index 6dbdbd26..68a67369 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java @@ -5,12 +5,12 @@ */ package org.hyperledger.fabric.shim.ext.sbe.impl; +import com.google.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperledger.fabric.protos.common.MSPPrincipal; @@ -21,11 +21,7 @@ import org.hyperledger.fabric.protos.common.SignaturePolicyEnvelope; import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement; -import com.google.protobuf.InvalidProtocolBufferException; - -/** - * Implements {@link StateBasedEndorsement}. - */ +/** Implements {@link StateBasedEndorsement}. */ public final class StateBasedEndorsementImpl implements StateBasedEndorsement { private static Log logger = LogFactory.getLog(StateBasedEndorsementImpl.class); @@ -44,7 +40,6 @@ public final class StateBasedEndorsementImpl implements StateBasedEndorsement { } catch (final InvalidProtocolBufferException e) { throw new IllegalArgumentException("error unmarshalling endorsement policy bytes", e); } - } @Override @@ -81,7 +76,9 @@ public List listOrgs() { } private void setMSPIDsFromSP(final SignaturePolicyEnvelope spe) { - spe.getIdentitiesList().stream().filter(identity -> Classification.ROLE.equals(identity.getPrincipalClassification())).forEach(this::addOrg); + spe.getIdentitiesList().stream() + .filter(identity -> Classification.ROLE.equals(identity.getPrincipalClassification())) + .forEach(this::addOrg); } private void addOrg(final MSPPrincipal identity) { @@ -102,15 +99,23 @@ private SignaturePolicyEnvelope policyFromMSPIDs() { final List sigpolicy = new ArrayList<>(); for (int i = 0; i < mspids.size(); i++) { final String mspid = mspids.get(i); - principals.add(MSPPrincipal.newBuilder().setPrincipalClassification(Classification.ROLE) - .setPrincipal(MSPRole.newBuilder().setMspIdentifier(mspid).setRole(orgs.get(mspid)).build().toByteString()).build()); + principals.add(MSPPrincipal.newBuilder() + .setPrincipalClassification(Classification.ROLE) + .setPrincipal(MSPRole.newBuilder() + .setMspIdentifier(mspid) + .setRole(orgs.get(mspid)) + .build() + .toByteString()) + .build()); sigpolicy.add(StateBasedEndorsementUtils.signedBy(i)); } // create the policy: it requires exactly 1 signature from all of the principals - return SignaturePolicyEnvelope.newBuilder().setVersion(0).setRule(StateBasedEndorsementUtils.nOutOf(mspids.size(), sigpolicy)) - .addAllIdentities(principals).build(); + return SignaturePolicyEnvelope.newBuilder() + .setVersion(0) + .setRule(StateBasedEndorsementUtils.nOutOf(mspids.size(), sigpolicy)) + .addAllIdentities(principals) + .build(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementUtils.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementUtils.java index 4234a70c..845056bc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementUtils.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementUtils.java @@ -7,7 +7,6 @@ import java.util.Arrays; import java.util.List; - import org.hyperledger.fabric.protos.common.MSPPrincipal; import org.hyperledger.fabric.protos.common.MSPPrincipal.Classification; import org.hyperledger.fabric.protos.common.MSPRole; @@ -16,15 +15,10 @@ import org.hyperledger.fabric.protos.common.SignaturePolicy.NOutOf; import org.hyperledger.fabric.protos.common.SignaturePolicyEnvelope; -/** - * Utility to create {@link SignaturePolicy} and - * {@link SignaturePolicyEnvelope}. - */ +/** Utility to create {@link SignaturePolicy} and {@link SignaturePolicyEnvelope}. */ public final class StateBasedEndorsementUtils { - private StateBasedEndorsementUtils() { - - } + private StateBasedEndorsementUtils() {} /** * Creates a SignaturePolicy requiring a given signer's signature. @@ -39,20 +33,21 @@ static SignaturePolicy signedBy(final int index) { /** * Create a policy. * - * Creates a policy which requires N out of the slice of policies to evaluate to - * true + *

Creates a policy which requires N out of the slice of policies to evaluate to true * * @param n * @param policies * @return SignaturePolicy */ static SignaturePolicy nOutOf(final int n, final List policies) { - return SignaturePolicy.newBuilder().setNOutOf(NOutOf.newBuilder().setN(n).addAllRules(policies).build()).build(); + return SignaturePolicy.newBuilder() + .setNOutOf(NOutOf.newBuilder().setN(n).addAllRules(policies).build()) + .build(); } /** - * Creates a {@link SignaturePolicyEnvelope} requiring 1 signature from any - * fabric entity, having the passed role, of the specified MSP. + * Creates a {@link SignaturePolicyEnvelope} requiring 1 signature from any fabric entity, having the passed role, + * of the specified MSP. * * @param mspId * @param role @@ -60,13 +55,21 @@ static SignaturePolicy nOutOf(final int n, final List policies) */ static SignaturePolicyEnvelope signedByFabricEntity(final String mspId, final MSPRoleType role) { // specify the principal: it's a member of the msp we just found - final MSPPrincipal principal = MSPPrincipal.newBuilder().setPrincipalClassification(Classification.ROLE) - .setPrincipal(MSPRole.newBuilder().setMspIdentifier(mspId).setRole(role).build().toByteString()).build(); + final MSPPrincipal principal = MSPPrincipal.newBuilder() + .setPrincipalClassification(Classification.ROLE) + .setPrincipal(MSPRole.newBuilder() + .setMspIdentifier(mspId) + .setRole(role) + .build() + .toByteString()) + .build(); // create the policy: it requires exactly 1 signature from the first (and only) // principal - return SignaturePolicyEnvelope.newBuilder().setVersion(0).setRule(nOutOf(1, Arrays.asList(signedBy(0)))).addIdentities(principal).build(); - + return SignaturePolicyEnvelope.newBuilder() + .setVersion(0) + .setRule(nOutOf(1, Arrays.asList(signedBy(0)))) + .addIdentities(principal) + .build(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/package-info.java index f4f3bb51..329c3a35 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/package-info.java @@ -1,6 +1,6 @@ -/* - * Copyright 2023 IBM All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.shim.ext.sbe.impl; +/* + * Copyright 2023 IBM All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.fabric.shim.ext.sbe.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/package-info.java index 50735e07..15c86c68 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * Provides an interface for creating and modifying state-based endorsement policies. - */ +/** Provides an interface for creating and modifying state-based endorsement policies. */ package org.hyperledger.fabric.shim.ext.sbe; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java index 8cafebdb..b2c3c916 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java @@ -9,27 +9,22 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.ERROR; import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.RESPONSE; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.StatusCode; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.logging.Logger; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.StatusCode; import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type; import org.hyperledger.fabric.shim.Chaincode; import org.hyperledger.fabric.shim.ChaincodeStub; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import org.hyperledger.fabric.traces.Traces; -/** - * A 'Callable' implementation the has the job of invoking the chaincode, and - * matching the response and requests. - */ +/** A 'Callable' implementation the has the job of invoking the chaincode, and matching the response and requests. */ public class ChaincodeInvocationTask implements Callable { private static Logger logger = Logger.getLogger(ChaincodeInvocationTask.class.getName()); @@ -51,17 +46,16 @@ public class ChaincodeInvocationTask implements Callable { private final Chaincode chaincode; /** - * - * @param message The incoming message that has triggered this task into - * execution - * @param type Is this init or invoke? (v2 Fabric deprecates init) - * @param outgoingMessage The Consumer functional interface to send any requests - * for ledger state - * @param chaincode A instance of the end users chaincode - * + * @param message The incoming message that has triggered this task into execution + * @param type Is this init or invoke? (v2 Fabric deprecates init) + * @param outgoingMessage The Consumer functional interface to send any requests for ledger state + * @param chaincode A instance of the end users chaincode */ - public ChaincodeInvocationTask(final ChaincodeMessage message, final Type type, - final Consumer outgoingMessage, final Chaincode chaincode) { + public ChaincodeInvocationTask( + final ChaincodeMessage message, + final Type type, + final Consumer outgoingMessage, + final Chaincode chaincode) { this.key = message.getChannelId() + message.getTxid(); this.type = type; @@ -71,9 +65,7 @@ public ChaincodeInvocationTask(final ChaincodeMessage message, final Type type, this.message = message; } - /** - * Main method to power the invocation of the chaincode. - */ + /** Main method to power the invocation of the chaincode. */ @Override public ChaincodeMessage call() { ChaincodeMessage finalResponseMessage; @@ -95,7 +87,6 @@ public ChaincodeMessage call() { // result is what will be sent to the peer as a response to this invocation final Chaincode.Response result; - perfLogger.fine(() -> "> task:invoke TX::" + this.txId); // Call chaincode's invoke @@ -110,24 +101,27 @@ public ChaincodeMessage call() { if (result.getStatus().getCode() >= Chaincode.Response.Status.INTERNAL_SERVER_ERROR.getCode()) { // Send ERROR with entire result.Message as payload - logger.severe(() -> String.format("[%-8.8s] Invoke failed with error code %d. Sending %s", + logger.severe(() -> String.format( + "[%-8.8s] Invoke failed with error code %d. Sending %s", message.getTxid(), result.getStatus().getCode(), ERROR)); - finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage(message.getChannelId(), - message.getTxid(), result, stub.getEvent()); + finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage( + message.getChannelId(), message.getTxid(), result, stub.getEvent()); if (span != null) { span.setStatus(StatusCode.ERROR, result.getMessage()); } } else { // Send COMPLETED with entire result as payload - logger.fine(() -> String.format("[%-8.8s] Invoke succeeded. Sending %s", message.getTxid(), COMPLETED)); - finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage(message.getChannelId(), - message.getTxid(), result, stub.getEvent()); + logger.fine( + () -> String.format("[%-8.8s] Invoke succeeded. Sending %s", message.getTxid(), COMPLETED)); + finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage( + message.getChannelId(), message.getTxid(), result, stub.getEvent()); } } catch (InvalidProtocolBufferException | RuntimeException e) { - logger.severe(() -> String.format("[%-8.8s] Invoke failed. Sending %s: %s", message.getTxid(), ERROR, e)); - finalResponseMessage = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), - message.getTxid(), e); + logger.severe( + () -> String.format("[%-8.8s] Invoke failed. Sending %s: %s", message.getTxid(), ERROR, e)); + finalResponseMessage = + ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), message.getTxid(), e); if (span != null) { span.setStatus(StatusCode.ERROR, e.getMessage()); } @@ -165,11 +159,11 @@ public boolean equals(final ChaincodeInvocationTask task) { } /** - * Posts the message that the peer has responded with to this task's request - * Uses an 'ArrayBlockingQueue'. This lets the producer post messages without waiting - * for the consumer. And the consumer can block until a message is posted. + * Posts the message that the peer has responded with to this task's request Uses an 'ArrayBlockingQueue'. This lets + * the producer post messages without waiting for the consumer. And the consumer can block until a message is + * posted. * - * In this case the data is only passed to the executing tasks. + *

In this case the data is only passed to the executing tasks. * * @param msg Chaincode message to pass pack * @throws InterruptedException should something really really go wrong @@ -182,17 +176,16 @@ public void postMessage(final ChaincodeMessage msg) throws InterruptedException /** * Send the chaincode message back to the peer. * - * Implementation of the Functional interface 'InvokeChaincodeSupport' + *

Implementation of the Functional interface 'InvokeChaincodeSupport' * - * It will send the message, via the outgoingMessageConsumer, and then block on - * the 'Exchanger' to wait for the response to come. + *

It will send the message, via the outgoingMessageConsumer, and then block on the 'Exchanger' to wait for the + * response to come. * - * This Exchange is an atomic operation between the thread that is running this - * task, and the thread that is handling the communication from the peer. + *

This Exchange is an atomic operation between the thread that is running this task, and the thread that is + * handling the communication from the peer. * * @param message The chaincode message from the peer * @return ByteString to be parsed by the caller - * */ protected ByteString invoke(final ChaincodeMessage message) { @@ -220,12 +213,12 @@ protected ByteString invoke(final ChaincodeMessage message) { logger.severe(() -> String.format("[%-8.8s] Unsuccessful response received.", txId)); throw new RuntimeException(String.format("[%-8.8s]Unsuccessful response received.", txId)); default: - logger.severe(() -> String.format("[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, - response.getType(), RESPONSE, ERROR)); - throw new RuntimeException(String.format("[%-8.8s] Unexpected %s response received. Expected %s or %s.", + logger.severe(() -> String.format( + "[%-8.8s] Unexpected %s response received. Expected %s or %s.", + txId, response.getType(), RESPONSE, ERROR)); + throw new RuntimeException(String.format( + "[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, response.getType(), RESPONSE, ERROR)); } - } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java index 831e2277..651bc81a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java @@ -16,11 +16,11 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.PUT_STATE_METADATA; import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER; +import com.google.protobuf.ByteString; import java.io.PrintWriter; import java.io.StringWriter; - -import org.hyperledger.fabric.protos.peer.ChaincodeID; import org.hyperledger.fabric.protos.peer.ChaincodeEvent; +import org.hyperledger.fabric.protos.peer.ChaincodeID; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type; import org.hyperledger.fabric.protos.peer.DelState; @@ -28,82 +28,170 @@ import org.hyperledger.fabric.protos.peer.GetStateMetadata; import org.hyperledger.fabric.protos.peer.PutState; import org.hyperledger.fabric.protos.peer.PutStateMetadata; -import org.hyperledger.fabric.protos.peer.StateMetadata; import org.hyperledger.fabric.protos.peer.Response; import org.hyperledger.fabric.protos.peer.Response.Builder; +import org.hyperledger.fabric.protos.peer.StateMetadata; import org.hyperledger.fabric.shim.Chaincode; -import com.google.protobuf.ByteString; - public final class ChaincodeMessageFactory { - private ChaincodeMessageFactory() { - } - - protected static ChaincodeMessage newGetPrivateDataHashEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(GET_PRIVATE_DATA_HASH, channelId, txId, GetState.newBuilder().setCollection(collection).setKey(key).build().toByteString()); - } - - protected static ChaincodeMessage newGetStateEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(GET_STATE, channelId, txId, GetState.newBuilder().setCollection(collection).setKey(key).build().toByteString()); - } - - protected static ChaincodeMessage newGetStateMetadataEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(GET_STATE_METADATA, channelId, txId, GetStateMetadata.newBuilder().setCollection(collection).setKey(key).build().toByteString()); - } - - protected static ChaincodeMessage newPutStateEventMessage(final String channelId, final String txId, final String collection, final String key, + private ChaincodeMessageFactory() {} + + protected static ChaincodeMessage newGetPrivateDataHashEventMessage( + final String channelId, final String txId, final String collection, final String key) { + return newEventMessage( + GET_PRIVATE_DATA_HASH, + channelId, + txId, + GetState.newBuilder() + .setCollection(collection) + .setKey(key) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newGetStateEventMessage( + final String channelId, final String txId, final String collection, final String key) { + return newEventMessage( + GET_STATE, + channelId, + txId, + GetState.newBuilder() + .setCollection(collection) + .setKey(key) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newGetStateMetadataEventMessage( + final String channelId, final String txId, final String collection, final String key) { + return newEventMessage( + GET_STATE_METADATA, + channelId, + txId, + GetStateMetadata.newBuilder() + .setCollection(collection) + .setKey(key) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newPutStateEventMessage( + final String channelId, + final String txId, + final String collection, + final String key, final ByteString value) { - return newEventMessage(PUT_STATE, channelId, txId, PutState.newBuilder().setCollection(collection).setKey(key).setValue(value).build().toByteString()); - } - - protected static ChaincodeMessage newPutStateMetadataEventMessage(final String channelId, final String txId, final String collection, final String key, - final String metakey, final ByteString value) { - return newEventMessage(PUT_STATE_METADATA, channelId, txId, PutStateMetadata.newBuilder().setCollection(collection).setKey(key) - .setMetadata(StateMetadata.newBuilder().setMetakey(metakey).setValue(value).build()).build().toByteString()); - } - - protected static ChaincodeMessage newDeleteStateEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(DEL_STATE, channelId, txId, DelState.newBuilder().setCollection(collection).setKey(key).build().toByteString()); - } - - protected static ChaincodeMessage newPurgeStateEventMessage(final String channelId, final String txId, final String collection, final String key) { - return newEventMessage(Type.PURGE_PRIVATE_DATA, channelId, txId, DelState.newBuilder().setCollection(collection).setKey(key).build().toByteString()); - } - - protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final Throwable throwable) { + return newEventMessage( + PUT_STATE, + channelId, + txId, + PutState.newBuilder() + .setCollection(collection) + .setKey(key) + .setValue(value) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newPutStateMetadataEventMessage( + final String channelId, + final String txId, + final String collection, + final String key, + final String metakey, + final ByteString value) { + return newEventMessage( + PUT_STATE_METADATA, + channelId, + txId, + PutStateMetadata.newBuilder() + .setCollection(collection) + .setKey(key) + .setMetadata(StateMetadata.newBuilder() + .setMetakey(metakey) + .setValue(value) + .build()) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newDeleteStateEventMessage( + final String channelId, final String txId, final String collection, final String key) { + return newEventMessage( + DEL_STATE, + channelId, + txId, + DelState.newBuilder() + .setCollection(collection) + .setKey(key) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newPurgeStateEventMessage( + final String channelId, final String txId, final String collection, final String key) { + return newEventMessage( + Type.PURGE_PRIVATE_DATA, + channelId, + txId, + DelState.newBuilder() + .setCollection(collection) + .setKey(key) + .build() + .toByteString()); + } + + protected static ChaincodeMessage newErrorEventMessage( + final String channelId, final String txId, final Throwable throwable) { return newErrorEventMessage(channelId, txId, printStackTrace(throwable)); } - protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message) { + protected static ChaincodeMessage newErrorEventMessage( + final String channelId, final String txId, final String message) { return newErrorEventMessage(channelId, txId, message, null); } - protected static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message, final ChaincodeEvent event) { + protected static ChaincodeMessage newErrorEventMessage( + final String channelId, final String txId, final String message, final ChaincodeEvent event) { return newEventMessage(ERROR, channelId, txId, ByteString.copyFromUtf8(message), event); } - protected static ChaincodeMessage newCompletedEventMessage(final String channelId, final String txId, final Chaincode.Response response, - final ChaincodeEvent event) { - final ChaincodeMessage message = newEventMessage(COMPLETED, channelId, txId, toProtoResponse(response).toByteString(), event); + protected static ChaincodeMessage newCompletedEventMessage( + final String channelId, final String txId, final Chaincode.Response response, final ChaincodeEvent event) { + final ChaincodeMessage message = newEventMessage( + COMPLETED, channelId, txId, toProtoResponse(response).toByteString(), event); return message; } - protected static ChaincodeMessage newInvokeChaincodeMessage(final String channelId, final String txId, final ByteString payload) { + protected static ChaincodeMessage newInvokeChaincodeMessage( + final String channelId, final String txId, final ByteString payload) { return newEventMessage(INVOKE_CHAINCODE, channelId, txId, payload, null); } protected static ChaincodeMessage newRegisterChaincodeMessage(final ChaincodeID chaincodeId) { - return ChaincodeMessage.newBuilder().setType(REGISTER).setPayload(chaincodeId.toByteString()).build(); + return ChaincodeMessage.newBuilder() + .setType(REGISTER) + .setPayload(chaincodeId.toByteString()) + .build(); } - protected static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload) { + protected static ChaincodeMessage newEventMessage( + final Type type, final String channelId, final String txId, final ByteString payload) { return newEventMessage(type, channelId, txId, payload, null); } - protected static ChaincodeMessage newEventMessage(final Type type, final String channelId, final String txId, final ByteString payload, + protected static ChaincodeMessage newEventMessage( + final Type type, + final String channelId, + final String txId, + final ByteString payload, final ChaincodeEvent event) { - final ChaincodeMessage.Builder builder = ChaincodeMessage.newBuilder().setType(type).setChannelId(channelId).setTxid(txId).setPayload(payload); + final ChaincodeMessage.Builder builder = ChaincodeMessage.newBuilder() + .setType(type) + .setChannelId(channelId) + .setTxid(txId) + .setPayload(payload); if (event != null) { builder.setChaincodeEvent(event); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java index 7216ad30..d3a6190d 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java @@ -5,21 +5,19 @@ */ package org.hyperledger.fabric.shim.impl; +import io.grpc.ClientInterceptor; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.logging.Logger; - -import io.grpc.ClientInterceptor; import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc; import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc.ChaincodeSupportStub; - -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.stub.StreamObserver; import org.hyperledger.fabric.traces.Traces; public class ChaincodeSupportClient { @@ -29,9 +27,7 @@ public class ChaincodeSupportClient { private final ManagedChannel channel; private final ChaincodeSupportStub stub; - /** - * @param channelBuilder - */ + /** @param channelBuilder */ public ChaincodeSupportClient(final ManagedChannelBuilder channelBuilder) { ClientInterceptor interceptor = Traces.getProvider().createInterceptor(); if (interceptor != null) { @@ -41,10 +37,7 @@ public ChaincodeSupportClient(final ManagedChannelBuilder channelBuilder) { this.stub = ChaincodeSupportGrpc.newStub(channel); } - /** - * - * @param itm - */ + /** @param itm */ public void shutdown(final InvocationTaskManager itm) { // first shutdown the thread pool @@ -59,16 +52,15 @@ public void shutdown(final InvocationTaskManager itm) { channel.shutdownNow(); Thread.currentThread().interrupt(); } - } /** - * * @param itm * @param requestObserver * @throws IOException verify parameters error */ - public void start(final InvocationTaskManager itm, final StreamObserver requestObserver) throws IOException { + public void start(final InvocationTaskManager itm, final StreamObserver requestObserver) + throws IOException { if (requestObserver == null) { throw new IOException("StreamObserver 'requestObserver' for chat with peer can't be null"); } @@ -110,6 +102,7 @@ public void accept(final ChaincodeMessage t) { /** * ChaincodeSupportStub. + * * @return stub */ public ChaincodeSupportStub getStub() { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java index 08783272..809b36a5 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java @@ -13,6 +13,9 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_QUERY_RESULT; import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.GET_STATE_BY_RANGE; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Timestamp; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; @@ -25,28 +28,27 @@ import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; - import org.hyperledger.fabric.protos.common.ChannelHeader; import org.hyperledger.fabric.protos.common.Header; import org.hyperledger.fabric.protos.common.HeaderType; import org.hyperledger.fabric.protos.common.SignatureHeader; import org.hyperledger.fabric.protos.ledger.queryresult.KV; +import org.hyperledger.fabric.protos.peer.ChaincodeEvent; import org.hyperledger.fabric.protos.peer.ChaincodeID; import org.hyperledger.fabric.protos.peer.ChaincodeInput; -import org.hyperledger.fabric.protos.peer.ChaincodeSpec; -import org.hyperledger.fabric.protos.peer.ChaincodeEvent; -import org.hyperledger.fabric.protos.peer.QueryMetadata; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; +import org.hyperledger.fabric.protos.peer.ChaincodeProposalPayload; +import org.hyperledger.fabric.protos.peer.ChaincodeSpec; import org.hyperledger.fabric.protos.peer.GetQueryResult; import org.hyperledger.fabric.protos.peer.GetState; import org.hyperledger.fabric.protos.peer.GetStateByRange; -import org.hyperledger.fabric.protos.peer.QueryResultBytes; -import org.hyperledger.fabric.protos.peer.StateMetadataResult; -import org.hyperledger.fabric.protos.peer.ChaincodeProposalPayload; +import org.hyperledger.fabric.protos.peer.MetaDataKeys; import org.hyperledger.fabric.protos.peer.Proposal; -import org.hyperledger.fabric.protos.peer.SignedProposal; +import org.hyperledger.fabric.protos.peer.QueryMetadata; +import org.hyperledger.fabric.protos.peer.QueryResultBytes; import org.hyperledger.fabric.protos.peer.Response; -import org.hyperledger.fabric.protos.peer.MetaDataKeys; +import org.hyperledger.fabric.protos.peer.SignedProposal; +import org.hyperledger.fabric.protos.peer.StateMetadataResult; import org.hyperledger.fabric.shim.Chaincode; import org.hyperledger.fabric.shim.ChaincodeStub; import org.hyperledger.fabric.shim.ledger.CompositeKey; @@ -55,10 +57,6 @@ import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Timestamp; - class InvocationStubImpl implements ChaincodeStub { private static final String UNSPECIFIED_START_KEY = new String(Character.toChars(0x000001)); @@ -79,7 +77,6 @@ class InvocationStubImpl implements ChaincodeStub { private ChaincodeEvent event; /** - * * @param message * @param handler * @throws InvalidProtocolBufferException @@ -93,7 +90,8 @@ class InvocationStubImpl implements ChaincodeStub { this.args = Collections.unmodifiableList(input.getArgsList()); this.signedProposal = message.getProposal(); - if (this.signedProposal == null || this.signedProposal.getProposalBytes().isEmpty()) { + if (this.signedProposal == null + || this.signedProposal.getProposalBytes().isEmpty()) { this.creator = null; this.txTimestamp = null; this.transientMap = Collections.emptyMap(); @@ -105,8 +103,8 @@ class InvocationStubImpl implements ChaincodeStub { final ChannelHeader channelHeader = ChannelHeader.parseFrom(header.getChannelHeader()); validateProposalType(channelHeader); final SignatureHeader signatureHeader = SignatureHeader.parseFrom(header.getSignatureHeader()); - final ChaincodeProposalPayload chaincodeProposalPayload = ChaincodeProposalPayload - .parseFrom(proposal.getPayload()); + final ChaincodeProposalPayload chaincodeProposalPayload = + ChaincodeProposalPayload.parseFrom(proposal.getPayload()); final Timestamp timestamp = channelHeader.getTimestamp(); this.txTimestamp = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); @@ -124,8 +122,8 @@ private byte[] computeBinding(final ChannelHeader channelHeader, final Signature final MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(signatureHeader.getNonce().asReadOnlyByteBuffer()); messageDigest.update(this.creator.asReadOnlyByteBuffer()); - final ByteBuffer epochBytes = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN) - .putLong(channelHeader.getEpoch()); + final ByteBuffer epochBytes = + ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(channelHeader.getEpoch()); epochBytes.flip(); messageDigest.update(epochBytes); return messageDigest.digest(); @@ -133,12 +131,12 @@ private byte[] computeBinding(final ChannelHeader channelHeader, final Signature private void validateProposalType(final ChannelHeader channelHeader) { switch (HeaderType.forNumber(channelHeader.getType())) { - case ENDORSER_TRANSACTION: - case CONFIG: - return; - default: - throw new RuntimeException( - String.format("Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType()))); + case ENDORSER_TRANSACTION: + case CONFIG: + return; + default: + throw new RuntimeException(String.format( + "Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType()))); } } @@ -168,7 +166,9 @@ public void setEvent(final String name, final byte[] payload) { throw new IllegalArgumentException("event name can not be nil string"); } if (payload != null) { - this.event = ChaincodeEvent.newBuilder().setEventName(name).setPayload(ByteString.copyFrom(payload)) + this.event = ChaincodeEvent.newBuilder() + .setEventName(name) + .setPayload(ByteString.copyFrom(payload)) .build(); } else { this.event = ChaincodeEvent.newBuilder().setEventName(name).build(); @@ -192,23 +192,26 @@ public String getTxId() { @Override public byte[] getState(final String key) { - return this.handler.invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", key)) + return this.handler + .invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", key)) .toByteArray(); } @Override public byte[] getStateValidationParameter(final String key) { - final ByteString payload = handler - .invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, "", key)); + final ByteString payload = + handler.invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, "", key)); try { final StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload); final Map stateMetadataMap = new HashMap<>(); - stateMetadataResult.getEntriesList() + stateMetadataResult + .getEntriesList() .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue())); if (stateMetadataMap.containsKey(MetaDataKeys.VALIDATION_PARAMETER.toString())) { - return stateMetadataMap.get(MetaDataKeys.VALIDATION_PARAMETER.toString()) + return stateMetadataMap + .get(MetaDataKeys.VALIDATION_PARAMETER.toString()) .toByteArray(); } } catch (final InvalidProtocolBufferException e) { @@ -217,7 +220,6 @@ public byte[] getStateValidationParameter(final String key) { } return null; - } @Override @@ -230,8 +232,8 @@ public void putState(final String key, final byte[] value) { @Override public void setStateValidationParameter(final String key, final byte[] value) { validateKey(key); - final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage(channelId, txId, "", key, - MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); + final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage( + channelId, txId, "", key, MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); this.handler.invoke(msg); } @@ -257,19 +259,22 @@ public QueryResultsIterator getStateByRange(final String startKey, fin return executeGetStateByRange("", start, end); } - private QueryResultsIterator executeGetStateByRange(final String collection, final String startKey, - final String endKey) { + private QueryResultsIterator executeGetStateByRange( + final String collection, final String startKey, final String endKey) { - final ByteString requestPayload = GetStateByRange.newBuilder().setCollection(collection).setStartKey(startKey) - .setEndKey(endKey).build().toByteString(); + final ByteString requestPayload = GetStateByRange.newBuilder() + .setCollection(collection) + .setStartKey(startKey) + .setEndKey(endKey) + .build() + .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, - txId, requestPayload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, - queryResultBytesToKv.andThen(KeyValueImpl::new)); - + return new QueryResultsIteratorImpl( + this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); } private final Function queryResultBytesToKv = new Function() { @@ -281,12 +286,11 @@ public KV apply(final QueryResultBytes queryResultBytes) { throw new RuntimeException(e); } } - }; @Override - public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(final String startKey, - final String endKey, final int pageSize, final String bookmark) { + public QueryResultsIteratorWithMetadata getStateByRangeWithPagination( + final String startKey, final String endKey, final int pageSize, final String bookmark) { String start = startKey; String end = endKey; @@ -300,26 +304,32 @@ public QueryResultsIteratorWithMetadata getStateByRangeWithPagination( CompositeKey.validateSimpleKeys(start, end); - final QueryMetadata queryMetadata = QueryMetadata.newBuilder().setBookmark(bookmark) - .setPageSize(pageSize).build(); + final QueryMetadata queryMetadata = QueryMetadata.newBuilder() + .setBookmark(bookmark) + .setPageSize(pageSize) + .build(); return executeGetStateByRangeWithMetadata("", start, end, queryMetadata.toByteString()); } - private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWithMetadata(final String collection, - final String startKey, final String endKey, final ByteString metadata) { + private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWithMetadata( + final String collection, final String startKey, final String endKey, final ByteString metadata) { - final ByteString payload = GetStateByRange.newBuilder().setCollection(collection).setStartKey(startKey) - .setEndKey(endKey).setMetadata(metadata).build().toByteString(); + final ByteString payload = GetStateByRange.newBuilder() + .setCollection(collection) + .setStartKey(startKey) + .setEndKey(endKey) + .setMetadata(metadata) + .build() + .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, - txId, payload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, payload); final ByteString response = this.handler.invoke(requestMessage); - return new QueryResultsIteratorWithMetadataImpl<>(this.handler, getChannelId(), getTxId(), response, - queryResultBytesToKv.andThen(KeyValueImpl::new)); - + return new QueryResultsIteratorWithMetadataImpl<>( + this.handler, getChannelId(), getTxId(), response, queryResultBytesToKv.andThen(KeyValueImpl::new)); } @Override @@ -337,8 +347,8 @@ public QueryResultsIterator getStateByPartialCompositeKey(final String } @Override - public QueryResultsIterator getStateByPartialCompositeKey(final String objectType, - final String... attributes) { + public QueryResultsIterator getStateByPartialCompositeKey( + final String objectType, final String... attributes) { return getStateByPartialCompositeKey(new CompositeKey(objectType, attributes)); } @@ -368,11 +378,13 @@ public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyW cKeyAsString = compositeKey.toString(); } - final QueryMetadata queryMetadata = QueryMetadata.newBuilder().setBookmark(bookmark) - .setPageSize(pageSize).build(); + final QueryMetadata queryMetadata = QueryMetadata.newBuilder() + .setBookmark(bookmark) + .setPageSize(pageSize) + .build(); - return executeGetStateByRangeWithMetadata("", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE, - queryMetadata.toByteString()); + return executeGetStateByRangeWithMetadata( + "", cKeyAsString, cKeyAsString + MAX_UNICODE_RUNE, queryMetadata.toByteString()); } @Override @@ -388,63 +400,82 @@ public CompositeKey splitCompositeKey(final String compositeKey) { @Override public QueryResultsIterator getQueryResult(final String query) { - final ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(query).build() + final ByteString requestPayload = GetQueryResult.newBuilder() + .setCollection("") + .setQuery(query) + .build() .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, - txId, requestPayload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, - queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorImpl( + this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); } @Override - public QueryResultsIteratorWithMetadata getQueryResultWithPagination(final String query, - final int pageSize, final String bookmark) { + public QueryResultsIteratorWithMetadata getQueryResultWithPagination( + final String query, final int pageSize, final String bookmark) { - final ByteString queryMetadataPayload = QueryMetadata.newBuilder().setBookmark(bookmark) - .setPageSize(pageSize).build().toByteString(); - final ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(query) - .setMetadata(queryMetadataPayload).build().toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, - txId, requestPayload); + final ByteString queryMetadataPayload = QueryMetadata.newBuilder() + .setBookmark(bookmark) + .setPageSize(pageSize) + .build() + .toByteString(); + final ByteString requestPayload = GetQueryResult.newBuilder() + .setCollection("") + .setQuery(query) + .setMetadata(queryMetadataPayload) + .build() + .toByteString(); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorWithMetadataImpl(this.handler, channelId, txId, response, - queryResultBytesToKv.andThen(KeyValueImpl::new)); - + return new QueryResultsIteratorWithMetadataImpl( + this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); } @Override public QueryResultsIterator getHistoryForKey(final String key) { - final ByteString requestPayload = GetQueryResult.newBuilder().setCollection("").setQuery(key).build() + final ByteString requestPayload = GetQueryResult.newBuilder() + .setCollection("") + .setQuery(key) + .build() .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_HISTORY_FOR_KEY, channelId, - txId, requestPayload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_HISTORY_FOR_KEY, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, + return new QueryResultsIteratorImpl( + this.handler, + channelId, + txId, + response, queryResultBytesToKeyModification.andThen(KeyModificationImpl::new)); - } - private final Function queryResultBytesToKeyModification = - new Function() { - @Override - public org.hyperledger.fabric.protos.ledger.queryresult.KeyModification apply(final QueryResultBytes queryResultBytes) { - try { - return org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.parseFrom(queryResultBytes.getResultBytes()); - } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } - } - }; + private final Function + queryResultBytesToKeyModification = + new Function() { + @Override + public org.hyperledger.fabric.protos.ledger.queryresult.KeyModification apply( + final QueryResultBytes queryResultBytes) { + try { + return org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.parseFrom( + queryResultBytes.getResultBytes()); + } catch (final InvalidProtocolBufferException e) { + throw new RuntimeException(e); + } + } + }; @Override public byte[] getPrivateData(final String collection, final String key) { validateCollection(collection); - return this.handler.invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, collection, key)) + return this.handler + .invoke(ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, collection, key)) .toByteArray(); } @@ -453,10 +484,13 @@ public byte[] getPrivateDataHash(final String collection, final String key) { validateCollection(collection); - final ByteString requestPayload = GetState.newBuilder().setCollection(collection).setKey(key).build() + final ByteString requestPayload = GetState.newBuilder() + .setCollection(collection) + .setKey(key) + .build() .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_PRIVATE_DATA_HASH, - channelId, txId, requestPayload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_PRIVATE_DATA_HASH, channelId, txId, requestPayload); return handler.invoke(requestMessage).toByteArray(); } @@ -465,16 +499,18 @@ public byte[] getPrivateDataHash(final String collection, final String key) { public byte[] getPrivateDataValidationParameter(final String collection, final String key) { validateCollection(collection); - final ByteString payload = handler - .invoke(ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, collection, key)); + final ByteString payload = handler.invoke( + ChaincodeMessageFactory.newGetStateMetadataEventMessage(channelId, txId, collection, key)); try { final StateMetadataResult stateMetadataResult = StateMetadataResult.parseFrom(payload); final Map stateMetadataMap = new HashMap<>(); - stateMetadataResult.getEntriesList() + stateMetadataResult + .getEntriesList() .forEach(entry -> stateMetadataMap.put(entry.getMetakey(), entry.getValue())); if (stateMetadataMap.containsKey(MetaDataKeys.VALIDATION_PARAMETER.toString())) { - return stateMetadataMap.get(MetaDataKeys.VALIDATION_PARAMETER.toString()) + return stateMetadataMap + .get(MetaDataKeys.VALIDATION_PARAMETER.toString()) .toByteArray(); } } catch (final InvalidProtocolBufferException e) { @@ -489,16 +525,20 @@ public byte[] getPrivateDataValidationParameter(final String collection, final S public void putPrivateData(final String collection, final String key, final byte[] value) { validateKey(key); validateCollection(collection); - this.handler.invoke(ChaincodeMessageFactory.newPutStateEventMessage(channelId, txId, collection, key, - ByteString.copyFrom(value))); + this.handler.invoke(ChaincodeMessageFactory.newPutStateEventMessage( + channelId, txId, collection, key, ByteString.copyFrom(value))); } @Override public void setPrivateDataValidationParameter(final String collection, final String key, final byte[] value) { validateKey(key); validateCollection(collection); - final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage(channelId, txId, - collection, key, MetaDataKeys.VALIDATION_PARAMETER.toString(), + final ChaincodeMessage msg = ChaincodeMessageFactory.newPutStateMetadataEventMessage( + channelId, + txId, + collection, + key, + MetaDataKeys.VALIDATION_PARAMETER.toString(), ByteString.copyFrom(value)); this.handler.invoke(msg); } @@ -506,22 +546,22 @@ public void setPrivateDataValidationParameter(final String collection, final Str @Override public void delPrivateData(final String collection, final String key) { validateCollection(collection); - final ChaincodeMessage msg = ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, collection, - key); + final ChaincodeMessage msg = + ChaincodeMessageFactory.newDeleteStateEventMessage(channelId, txId, collection, key); this.handler.invoke(msg); } @Override public void purgePrivateData(final String collection, final String key) { validateCollection(collection); - final ChaincodeMessage msg = ChaincodeMessageFactory.newPurgeStateEventMessage(channelId, txId, collection, - key); + final ChaincodeMessage msg = + ChaincodeMessageFactory.newPurgeStateEventMessage(channelId, txId, collection, key); this.handler.invoke(msg); } @Override - public QueryResultsIterator getPrivateDataByRange(final String collection, final String startKey, - final String endKey) { + public QueryResultsIterator getPrivateDataByRange( + final String collection, final String startKey, final String endKey) { String start = startKey; String end = endKey; @@ -538,8 +578,8 @@ public QueryResultsIterator getPrivateDataByRange(final String collect } @Override - public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, - final String compositeKey) { + public QueryResultsIterator getPrivateDataByPartialCompositeKey( + final String collection, final String compositeKey) { CompositeKey key; @@ -555,8 +595,8 @@ public QueryResultsIterator getPrivateDataByPartialCompositeKey(final } @Override - public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, - final CompositeKey compositeKey) { + public QueryResultsIterator getPrivateDataByPartialCompositeKey( + final String collection, final CompositeKey compositeKey) { String cKeyAsString; if (compositeKey == null) { cKeyAsString = new CompositeKey(UNSPECIFIED_START_KEY).toString(); @@ -568,26 +608,30 @@ public QueryResultsIterator getPrivateDataByPartialCompositeKey(final } @Override - public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, - final String objectType, final String... attributes) { + public QueryResultsIterator getPrivateDataByPartialCompositeKey( + final String collection, final String objectType, final String... attributes) { return getPrivateDataByPartialCompositeKey(collection, new CompositeKey(objectType, attributes)); } @Override public QueryResultsIterator getPrivateDataQueryResult(final String collection, final String query) { validateCollection(collection); - final ByteString requestPayload = GetQueryResult.newBuilder().setCollection(collection).setQuery(query).build() + final ByteString requestPayload = GetQueryResult.newBuilder() + .setCollection(collection) + .setQuery(query) + .build() .toByteString(); - final ChaincodeMessage requestMessage = ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, - txId, requestPayload); + final ChaincodeMessage requestMessage = + ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl(this.handler, channelId, txId, response, - queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorImpl( + this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); } @Override - public Chaincode.Response invokeChaincode(final String chaincodeName, final List args, final String channel) { + public Chaincode.Response invokeChaincode( + final String chaincodeName, final List args, final String channel) { // internally we handle chaincode name as a composite name final String compositeName; if (channel != null && !channel.trim().isEmpty()) { @@ -600,11 +644,13 @@ public Chaincode.Response invokeChaincode(final String chaincodeName, final List final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder() .setChaincodeId(ChaincodeID.newBuilder().setName(compositeName).build()) .setInput(ChaincodeInput.newBuilder() - .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())).build()) - .build().toByteString(); + .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())) + .build()) + .build() + .toByteString(); - final ChaincodeMessage invokeChaincodeMessage = ChaincodeMessageFactory - .newInvokeChaincodeMessage(this.channelId, this.txId, invocationSpecPayload); + final ChaincodeMessage invokeChaincodeMessage = + ChaincodeMessageFactory.newInvokeChaincodeMessage(this.channelId, this.txId, invocationSpecPayload); final ByteString response = this.handler.invoke(invokeChaincodeMessage); try { @@ -613,14 +659,15 @@ public Chaincode.Response invokeChaincode(final String chaincodeName, final List final ChaincodeMessage responseMessage = ChaincodeMessage.parseFrom(response); // the actual response message must be of type COMPLETED - LOGGER.fine(String.format("[%-8.8s] %s response received from other chaincode.", txId, - responseMessage.getType())); + LOGGER.fine(String.format( + "[%-8.8s] %s response received from other chaincode.", txId, responseMessage.getType())); if (responseMessage.getType() == COMPLETED) { // success - final Response r = Response - .parseFrom(responseMessage.getPayload()); - return new Chaincode.Response(Chaincode.Response.Status.forCode(r.getStatus()), r.getMessage(), + final Response r = Response.parseFrom(responseMessage.getPayload()); + return new Chaincode.Response( + Chaincode.Response.Status.forCode(r.getStatus()), + r.getMessage(), r.getPayload() == null ? null : r.getPayload().toByteArray()); } else { // error @@ -630,7 +677,6 @@ public Chaincode.Response invokeChaincode(final String chaincodeName, final List } catch (final InvalidProtocolBufferException e) { throw new RuntimeException(e); } - } @Override diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java index 97d68fbd..c2402e48 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java @@ -12,19 +12,13 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; - import org.hyperledger.fabric.metrics.TaskMetricsCollector; -/** - * - * - * - */ +/** */ public final class InvocationTaskExecutor extends ThreadPoolExecutor implements TaskMetricsCollector { private static Logger logger = Logger.getLogger(InvocationTaskExecutor.class.getName()); /** - * * @param corePoolSize * @param maximumPoolSize * @param keepAliveTime @@ -33,8 +27,14 @@ public final class InvocationTaskExecutor extends ThreadPoolExecutor implements * @param factory * @param handler */ - public InvocationTaskExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, - final BlockingQueue workQueue, final ThreadFactory factory, final RejectedExecutionHandler handler) { + public InvocationTaskExecutor( + final int corePoolSize, + final int maximumPoolSize, + final long keepAliveTime, + final TimeUnit unit, + final BlockingQueue workQueue, + final ThreadFactory factory, + final RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, factory, handler); prestartCoreThread(); logger.info("Thread pool created"); @@ -46,7 +46,6 @@ public InvocationTaskExecutor(final int corePoolSize, final int maximumPoolSize, protected void beforeExecute(final Thread thread, final Runnable task) { super.beforeExecute(thread, task); count.incrementAndGet(); - } @Override @@ -64,5 +63,4 @@ public int getCurrentTaskCount() { public int getCurrentQueueCount() { return this.getQueue().size(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java index 424f3a84..2de85597 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java @@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.logging.Logger; - import org.hyperledger.fabric.Logging; import org.hyperledger.fabric.metrics.Metrics; import org.hyperledger.fabric.protos.peer.ChaincodeID; @@ -31,13 +30,10 @@ import org.hyperledger.fabric.shim.ChaincodeBase; /** - * The InvocationTask Manager handles the message level communication with the - * peer. - * - * In the current 1.4 Fabric Protocol this is in practice a singleton - because - * the peer will ignore multiple 'register' calls. And an instance of this will - * be created per register call for a given chaincodeID. + * The InvocationTask Manager handles the message level communication with the peer. * + *

In the current 1.4 Fabric Protocol this is in practice a singleton - because the peer will ignore multiple + * 'register' calls. And an instance of this will be created per register call for a given chaincodeID. */ public final class InvocationTaskManager { @@ -47,7 +43,7 @@ public final class InvocationTaskManager { /** * Get an instance of the Invocation Task Manager. * - * @param chaincode Chaincode Instance + * @param chaincode Chaincode Instance * @param chaincodeId ID of the chaincode * @return InvocationTaskManager */ @@ -84,7 +80,6 @@ public Thread newThread(final Runnable r) { Thread thread = Executors.defaultThreadFactory().newThread(r); thread.setName("fabric-txinvoke:" + next.incrementAndGet()); return thread; - } }; @@ -102,7 +97,7 @@ public Thread newThread(final Runnable r) { /** * New InvocationTaskManager. * - * @param chaincode Chaincode Instance + * @param chaincode Chaincode Instance * @param chaincodeId ID of the chaincode */ public InvocationTaskManager(final ChaincodeBase chaincode, final ChaincodeID chaincodeId) { @@ -128,11 +123,10 @@ public InvocationTaskManager(final ChaincodeBase chaincode, final ChaincodeID ch logger.info(() -> "Keep Alive Time [TP_KEEP_ALIVE_MS]" + keepAliveTime); workQueue = new LinkedBlockingQueue(queueSize); - taskService = new InvocationTaskExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, - threadFactory, handler); + taskService = new InvocationTaskExecutor( + corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); Metrics.getProvider().setTaskMetricsCollector(taskService); - } /** @@ -145,35 +139,38 @@ public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) throws I if (chaincodeMessage == null) { throw new IllegalArgumentException("chaincodeMessage is null"); } - logger.fine(() -> String.format("[%-8.8s] %s", chaincodeMessage.getTxid(), ChaincodeBase.toJsonString(chaincodeMessage))); + logger.fine(() -> + String.format("[%-8.8s] %s", chaincodeMessage.getTxid(), ChaincodeBase.toJsonString(chaincodeMessage))); try { final Type msgType = chaincodeMessage.getType(); switch (chaincode.getState()) { case CREATED: if (msgType == REGISTERED) { chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.ESTABLISHED); - logger.fine(() -> String.format("[%-8.8s] Received REGISTERED: moving to established state", + logger.fine(() -> String.format( + "[%-8.8s] Received REGISTERED: moving to established state", chaincodeMessage.getTxid())); } else { - logger.warning(() -> String.format("[%-8.8s] Received %s: cannot handle", - chaincodeMessage.getTxid(), msgType)); + logger.warning(() -> String.format( + "[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); } break; case ESTABLISHED: if (msgType == READY) { chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.READY); - logger.fine(() -> String.format("[%-8.8s] Received READY: ready for invocations", - chaincodeMessage.getTxid())); + logger.fine(() -> String.format( + "[%-8.8s] Received READY: ready for invocations", chaincodeMessage.getTxid())); } else { - logger.warning(() -> String.format("[%-8.8s] Received %s: cannot handle", - chaincodeMessage.getTxid(), msgType)); + logger.warning(() -> String.format( + "[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); } break; case READY: handleMsg(chaincodeMessage, msgType); break; default: - logger.warning(() -> String.format("[%-8.8s] Received %s: cannot handle", + logger.warning(() -> String.format( + "[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), chaincodeMessage.getType())); break; } @@ -187,8 +184,7 @@ public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) throws I } /** - * Key method to take the message, determine if it is a new transaction or an - * answer (good or bad) to a stub api. + * Key method to take the message, determine if it is a new transaction or an answer (good or bad) to a stub api. * * @param message * @param msgType @@ -205,15 +201,14 @@ private void handleMsg(final ChaincodeMessage message, final Type msgType) { newTask(message, msgType); break; default: - logger.warning(() -> String.format("[%-8.8s] Received %s: cannot handle", message.getTxid(), - message.getType())); + logger.warning(() -> + String.format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); break; } } /** - * Send a message from the peer to the correct task. This will be a response to - * something like a getState() call. + * Send a message from the peer to the correct task. This will be a response to something like a getState() call. * * @param message ChaincodeMessage from the peer */ @@ -233,8 +228,8 @@ private void sendToTask(final ChaincodeMessage message) { logger.severe( () -> "Failed to send response to the task task " + message.getTxid() + Logging.formatError(e)); - final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), - message.getTxid(), "Failed to send response to task"); + final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage( + message.getChannelId(), message.getTxid(), "Failed to send response to task"); this.outgoingMessage.accept(m); } } @@ -243,14 +238,13 @@ private void sendToTask(final ChaincodeMessage message) { * Create a new task to handle this transaction function. * * @param message ChaincodeMessage to process - * @param type Type of message = INIT or INVOKE. INIT is deprecated in future - * versions + * @param type Type of message = INIT or INVOKE. INIT is deprecated in future versions * @throws InterruptedException */ private void newTask(final ChaincodeMessage message, final Type type) { String txid = message.getTxid(); - final ChaincodeInvocationTask task = new ChaincodeInvocationTask(message, type, this.outgoingMessage, - this.chaincode); + final ChaincodeInvocationTask task = + new ChaincodeInvocationTask(message, type, this.outgoingMessage, this.chaincode); perflogger.fine(() -> "> newTask:created TX::" + txid); @@ -260,9 +254,11 @@ private void newTask(final ChaincodeMessage message, final Type type) { // submit the task to run, with the taskService providing the // threading support. - final CompletableFuture response = CompletableFuture.runAsync(() -> { - task.call(); - }, taskService); + final CompletableFuture response = CompletableFuture.runAsync( + () -> { + task.call(); + }, + taskService); // we have a future of the chaincode message that should be returned. // but waiting for this does not need to block this thread @@ -281,11 +277,10 @@ private void newTask(final ChaincodeMessage message, final Type type) { // thread for processing, and there's no space left in the queue to hold // it pending - final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), txid, - "Failed to submit task for processing"); + final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage( + message.getChannelId(), txid, "Failed to submit task for processing"); this.outgoingMessage.accept(m); } - } /** @@ -320,9 +315,7 @@ public InvocationTaskManager register() throws IllegalArgumentException { private static final int SHUTDOWN_TIMEOUT = 60; - /** - * - */ + /** */ public void shutdown() { // Recommended shutdown process from // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html @@ -345,5 +338,4 @@ public void shutdown() { Thread.currentThread().interrupt(); } } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java index 42f77f73..2cecbf97 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java @@ -5,12 +5,10 @@ */ package org.hyperledger.fabric.shim.impl; +import com.google.protobuf.ByteString; import java.time.Instant; - import org.hyperledger.fabric.shim.ledger.KeyModification; -import com.google.protobuf.ByteString; - public final class KeyModificationImpl implements KeyModification { private final String txId; @@ -21,7 +19,8 @@ public final class KeyModificationImpl implements KeyModification { KeyModificationImpl(final org.hyperledger.fabric.protos.ledger.queryresult.KeyModification km) { this.txId = km.getTxId(); this.value = km.getValue(); - this.timestamp = Instant.ofEpochSecond(km.getTimestamp().getSeconds(), km.getTimestamp().getNanos()); + this.timestamp = Instant.ofEpochSecond( + km.getTimestamp().getSeconds(), km.getTimestamp().getNanos()); this.deleted = km.getIsDelete(); } @@ -87,5 +86,4 @@ public boolean equals(final Object obj) { } return true; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java index df9903cb..dbf1089f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java @@ -5,11 +5,10 @@ */ package org.hyperledger.fabric.shim.impl; +import com.google.protobuf.ByteString; import org.hyperledger.fabric.protos.ledger.queryresult.KV; import org.hyperledger.fabric.shim.ledger.KeyValue; -import com.google.protobuf.ByteString; - class KeyValueImpl implements KeyValue { private final String key; @@ -64,5 +63,4 @@ public boolean equals(final Object obj) { } return true; } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java index a319d84b..874ae4f7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java @@ -9,11 +9,12 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.QUERY_STATE_CLOSE; import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.QUERY_STATE_NEXT; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.function.Function; - import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.QueryResponse; import org.hyperledger.fabric.protos.peer.QueryResultBytes; @@ -21,17 +22,13 @@ import org.hyperledger.fabric.protos.peer.QueryStateNext; import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - /** * This class provides an ITERABLE object of query results. * - * NOTE the class name - * is misleading - as this class is not an iterator itself, rather it implements + *

NOTE the class name is misleading - as this class is not an iterator itself, rather it implements * java.lang.Iterable via the QueryResultsIterator * - * public interface QueryResultsIterator extends Iterable, AutoCloseable + *

public interface QueryResultsIterator extends Iterable, AutoCloseable * * @param */ @@ -44,7 +41,11 @@ class QueryResultsIteratorImpl implements QueryResultsIterator { private QueryResponse currentQueryResponse; private Function mapper; - QueryResultsIteratorImpl(final ChaincodeInvocationTask handler, final String channelId, final String txId, final ByteString responseBuffer, + QueryResultsIteratorImpl( + final ChaincodeInvocationTask handler, + final String channelId, + final String txId, + final ByteString responseBuffer, final Function mapper) { try { @@ -83,8 +84,12 @@ public T next() { // get more results from peer - final ByteString requestPayload = QueryStateNext.newBuilder().setId(currentQueryResponse.getId()).build().toByteString(); - final ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_NEXT, channelId, txId, requestPayload); + final ByteString requestPayload = QueryStateNext.newBuilder() + .setId(currentQueryResponse.getId()) + .build() + .toByteString(); + final ChaincodeMessage requestNextMessage = + ChaincodeMessageFactory.newEventMessage(QUERY_STATE_NEXT, channelId, txId, requestPayload); final ByteString responseMessage = QueryResultsIteratorImpl.this.handler.invoke(requestNextMessage); try { @@ -96,22 +101,23 @@ public T next() { // return next fetched result return mapper.apply(currentIterator.next()); - } - }; } @Override public void close() throws Exception { - final ByteString requestPayload = QueryStateClose.newBuilder().setId(currentQueryResponse.getId()).build().toByteString(); + final ByteString requestPayload = QueryStateClose.newBuilder() + .setId(currentQueryResponse.getId()) + .build() + .toByteString(); - final ChaincodeMessage requestNextMessage = ChaincodeMessageFactory.newEventMessage(QUERY_STATE_CLOSE, channelId, txId, requestPayload); + final ChaincodeMessage requestNextMessage = + ChaincodeMessageFactory.newEventMessage(QUERY_STATE_CLOSE, channelId, txId, requestPayload); this.handler.invoke(requestNextMessage); this.currentIterator = Collections.emptyIterator(); this.currentQueryResponse = QueryResponse.newBuilder().setHasMore(false).build(); } - } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java index 93b349db..26d24f55 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java @@ -6,41 +6,42 @@ package org.hyperledger.fabric.shim.impl; +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; import java.util.function.Function; import java.util.logging.Logger; - -import org.hyperledger.fabric.protos.peer.QueryResponseMetadata; import org.hyperledger.fabric.protos.peer.QueryResponse; +import org.hyperledger.fabric.protos.peer.QueryResponseMetadata; import org.hyperledger.fabric.protos.peer.QueryResultBytes; import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; - /** * QueryResult Iterator. * - * Implementation of {@link QueryResultsIteratorWithMetadata}, by extending - * {@link org.hyperledger.fabric.shim.ledger.QueryResultsIterator} - * implementations, {@link QueryResultsIteratorImpl} + *

Implementation of {@link QueryResultsIteratorWithMetadata}, by extending + * {@link org.hyperledger.fabric.shim.ledger.QueryResultsIterator} implementations, {@link QueryResultsIteratorImpl} * * @param */ -public final class QueryResultsIteratorWithMetadataImpl extends QueryResultsIteratorImpl implements QueryResultsIteratorWithMetadata { +public final class QueryResultsIteratorWithMetadataImpl extends QueryResultsIteratorImpl + implements QueryResultsIteratorWithMetadata { private static Logger logger = Logger.getLogger(QueryResultsIteratorWithMetadataImpl.class.getName()); private QueryResponseMetadata metadata; /** - * * @param handler * @param channelId * @param txId * @param responseBuffer * @param mapper */ - public QueryResultsIteratorWithMetadataImpl(final ChaincodeInvocationTask handler, final String channelId, final String txId, - final ByteString responseBuffer, final Function mapper) { + public QueryResultsIteratorWithMetadataImpl( + final ChaincodeInvocationTask handler, + final String channelId, + final String txId, + final ByteString responseBuffer, + final Function mapper) { super(handler, channelId, txId, responseBuffer, mapper); try { final QueryResponse queryResponse = QueryResponse.parseFrom(responseBuffer); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/package-info.java index ee6912ed..1147f629 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/package-info.java @@ -4,7 +4,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** - * - */ +/** */ package org.hyperledger.fabric.shim.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java index 8b47b39e..32335315 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java @@ -21,9 +21,7 @@ public class CompositeKey { private static final String INVALID_SEGMENT_CHAR = new String(Character.toChars(Character.MAX_CODE_POINT)); private static final String INVALID_SEGMENT_PATTERN = String.format("(?:%s|%s)", INVALID_SEGMENT_CHAR, DELIMITER); - /** - * - */ + /** */ public static final String NAMESPACE = DELIMITER; private final String objectType; @@ -31,7 +29,6 @@ public class CompositeKey { private final String compositeKey; /** - * * @param objectType * @param attributes */ @@ -40,7 +37,6 @@ public CompositeKey(final String objectType, final String... attributes) { } /** - * * @param objectType * @param attributes */ @@ -53,32 +49,23 @@ public CompositeKey(final String objectType, final List attributes) { this.compositeKey = generateCompositeKeyString(objectType, attributes); } - /** - * - * @return object type - */ + /** @return object type */ public String getObjectType() { return objectType; } - /** - * - * @return List of string arguments - */ + /** @return List of string arguments */ public List getAttributes() { return attributes; } - /** - * - */ + /** */ @Override public String toString() { return compositeKey; } /** - * * @param compositeKey * @return Composite Key */ @@ -95,9 +82,8 @@ public static CompositeKey parseCompositeKey(final String compositeKey) { } /** - * To ensure that simple keys do not go into composite key namespace, we - * validate simple key to check whether the key starts with 0x00 (which is the - * namespace for compositeKey). This helps in avoiding simple/composite key + * To ensure that simple keys do not go into composite key namespace, we validate simple key to check whether the + * key starts with 0x00 (which is the namespace for compositeKey). This helps in avoiding simple/composite key * collisions. * * @param keys the list of simple keys @@ -124,7 +110,6 @@ private String generateCompositeKeyString(final String objectType, final List the type of elements returned by the iterator */ -public interface QueryResultsIterator extends Iterable, AutoCloseable { -} - +public interface QueryResultsIterator extends Iterable, AutoCloseable {} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java index 80081c91..b5c45cfa 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java @@ -9,18 +9,13 @@ import org.hyperledger.fabric.protos.peer.QueryResponseMetadata; /** - * QueryResultsIteratorWithMetadata allows a chaincode to iterate over a set of - * key/value pairs returned by range, execute and history queries. In addition, - * it store - * {@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}, + * QueryResultsIteratorWithMetadata allows a chaincode to iterate over a set of key/value pairs returned by range, + * execute and history queries. In addition, it store {@link org.hyperledger.fabric.protos.peer.QueryResponseMetadata}, * returned by pagination range queries * * @param the type of elements returned by the iterator */ public interface QueryResultsIteratorWithMetadata extends Iterable, AutoCloseable { - /** - * - * @return Query Metadata - */ + /** @return Query Metadata */ QueryResponseMetadata getMetadata(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/package-info.java index ed1ee601..e47b1e4a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/package-info.java @@ -10,4 +10,3 @@ * @see org.hyperledger.fabric.shim.ChaincodeStub */ package org.hyperledger.fabric.shim.ledger; - diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java index 8ea4e804..2fd3f337 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/package-info.java @@ -7,11 +7,11 @@ /** * Provides interfaces and classes required for chaincode development and state variable access. * - *

- * It is possible to implement Java chaincode by extending the {@link org.hyperledger.fabric.shim.ChaincodeBase} class however new projects should should implement {@link org.hyperledger.fabric.contract.ContractInterface} and use the contract programming model instead. + *

It is possible to implement Java chaincode by extending the {@link org.hyperledger.fabric.shim.ChaincodeBase} + * class however new projects should should implement {@link org.hyperledger.fabric.contract.ContractInterface} and use + * the contract programming model instead. * * @see org.hyperledger.fabric.contract * @see org.hyperledger.fabric.shim.ChaincodeBase */ package org.hyperledger.fabric.shim; - diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java index 2986f169..28ba7b28 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java @@ -5,19 +5,18 @@ */ package org.hyperledger.fabric.traces; -import org.hyperledger.fabric.traces.impl.DefaultTracesProvider; -import org.hyperledger.fabric.traces.impl.NullProvider; - import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.logging.Logger; +import org.hyperledger.fabric.traces.impl.DefaultTracesProvider; +import org.hyperledger.fabric.traces.impl.NullProvider; /** * Traces Interface. * - * Traces setups up the provider in use from the configuration supplied + *

Traces setups up the provider in use from the configuration supplied * - * If not enabled, nothing happens. + *

If not enabled, nothing happens. */ public final class Traces { @@ -28,13 +27,9 @@ public final class Traces { private static TracesProvider provider; - - private Traces() { - - } + private Traces() {} /** - * * @param props the configuration of the chaincode * @return The traces provider */ @@ -46,32 +41,32 @@ public static TracesProvider initialize(final Properties props) { final String providerClass = (String) props.get(CHAINCODE_TRACES_PROVIDER); @SuppressWarnings("unchecked") // it must be this type otherwise an error - final - Class clazz = (Class) Class.forName(providerClass); + final Class clazz = (Class) Class.forName(providerClass); provider = clazz.getConstructor().newInstance(); } else { logger.info("Using default traces provider"); provider = new DefaultTracesProvider(); } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { + } catch (ClassNotFoundException + | InstantiationException + | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException + | NoSuchMethodException + | SecurityException e) { throw new RuntimeException("Unable to start traces", e); } } else { // return a 'null' provider logger.info("Traces disabled"); provider = new NullProvider(); - } provider.initialize(props); return provider; } - /** - * - * @return TracesProvider - */ + /** @return TracesProvider */ public static TracesProvider getProvider() { if (provider == null) { throw new IllegalStateException("No provider set, this should have been set"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java index 16712059..2083b4e9 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java @@ -8,25 +8,20 @@ import io.grpc.ClientInterceptor; import io.opentelemetry.api.trace.Span; -import org.hyperledger.fabric.shim.ChaincodeStub; - import java.util.Properties; +import org.hyperledger.fabric.shim.ChaincodeStub; /** - * Interface to be implemented to send traces on the chaincode to the - * 'backend-of-choice'. + * Interface to be implemented to send traces on the chaincode to the 'backend-of-choice'. * - * An instance of this will be created, and provided with the resources from - * which chaincode specific metrics can be collected. (via the no-argument - * constructor). + *

An instance of this will be created, and provided with the resources from which chaincode specific metrics can be + * collected. (via the no-argument constructor). * - * The choice of when, where and what to collect etc are within the remit of the - * provider. + *

The choice of when, where and what to collect etc are within the remit of the provider. * - * This is the effective call sequence. + *

This is the effective call sequence. * - * MyTracesProvider mmp = new MyTracesProvider() - * mmp.initialize(props_from_environment); // short while later.... + *

MyTracesProvider mmp = new MyTracesProvider() mmp.initialize(props_from_environment); // short while later.... * mmp.setTaskTracesCollector(taskService); */ public interface TracesProvider { @@ -36,22 +31,23 @@ public interface TracesProvider { * * @param props */ - default void initialize(final Properties props) { - }; + default void initialize(final Properties props) {} + ; /** * Creates a span with metadata of the current chaincode execution, possibly linked to the execution arguments. + * * @param stub the context of the chaincode execution - * @return a new span if traces are enabled, or null. - * The caller is responsible for closing explicitly the span. + * @return a new span if traces are enabled, or null. The caller is responsible for closing explicitly the span. */ default Span createSpan(ChaincodeStub stub) { return null; } /** - * Creates an interceptor of gRPC messages that can be injected in processing incoming messages to extract - * trace information. + * Creates an interceptor of gRPC messages that can be injected in processing incoming messages to extract trace + * information. + * * @return a new client interceptor, or null if no interceptor is set. */ default ClientInterceptor createInterceptor() { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/DefaultTracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/DefaultTracesProvider.java index 1ea5b982..0153cc9c 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/DefaultTracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/DefaultTracesProvider.java @@ -7,5 +7,4 @@ import org.hyperledger.fabric.traces.TracesProvider; -public final class DefaultTracesProvider implements TracesProvider { -} +public final class DefaultTracesProvider implements TracesProvider {} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/NullProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/NullProvider.java index 15818d5e..fa851edd 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/NullProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/NullProvider.java @@ -7,5 +7,4 @@ import org.hyperledger.fabric.traces.TracesProvider; -public final class NullProvider implements TracesProvider { -} +public final class NullProvider implements TracesProvider {} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java index 38c0fb72..7afa5c48 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java @@ -7,8 +7,6 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; - -import javax.annotation.Nullable; import java.time.Duration; import java.util.AbstractMap; import java.util.Arrays; @@ -20,6 +18,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.annotation.Nullable; final class OpenTelemetryProperties implements ConfigProperties { private final Map config; @@ -34,14 +33,12 @@ final class OpenTelemetryProperties implements ConfigProperties { } @Override - @Nullable - public String getString(final String name) { + @Nullable public String getString(final String name) { return config.get(name); } @Override - @Nullable - public Boolean getBoolean(final String name) { + @Nullable public Boolean getBoolean(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { return null; @@ -50,8 +47,7 @@ public Boolean getBoolean(final String name) { } @Override - @Nullable - @SuppressWarnings("UnusedException") + @Nullable @SuppressWarnings("UnusedException") public Integer getInt(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { @@ -65,8 +61,7 @@ public Integer getInt(final String name) { } @Override - @Nullable - @SuppressWarnings("UnusedException") + @Nullable @SuppressWarnings("UnusedException") public Long getLong(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { @@ -80,8 +75,7 @@ public Long getLong(final String name) { } @Override - @Nullable - @SuppressWarnings("UnusedException") + @Nullable @SuppressWarnings("UnusedException") public Double getDouble(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { @@ -95,8 +89,7 @@ public Double getDouble(final String name) { } @Override - @Nullable - @SuppressWarnings("UnusedException") + @Nullable @SuppressWarnings("UnusedException") public Duration getDuration(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { @@ -110,12 +103,7 @@ public Duration getDuration(final String name) { return Duration.ofMillis(TimeUnit.MILLISECONDS.convert(rawNumber, unit)); } catch (NumberFormatException ex) { throw new ConfigurationException( - "Invalid duration property " - + name - + "=" - + value - + ". Expected number, found: " - + numberString); + "Invalid duration property " + name + "=" + value + ". Expected number, found: " + numberString); } catch (ConfigurationException ex) { throw new ConfigurationException( "Invalid duration property " + name + "=" + value + ". " + ex.getMessage()); @@ -135,20 +123,16 @@ public List getList(final String name) { public Map getMap(final String name) { return getList(name).stream() .map(keyValuePair -> filterBlanksAndNulls(keyValuePair.split("=", 2))) - .map( - splitKeyValuePairs -> { - if (splitKeyValuePairs.size() != 2) { - throw new ConfigurationException( - "Invalid map property: " + name + "=" + config.get(name)); - } - return new AbstractMap.SimpleImmutableEntry<>( - splitKeyValuePairs.get(0), splitKeyValuePairs.get(1)); - }) + .map(splitKeyValuePairs -> { + if (splitKeyValuePairs.size() != 2) { + throw new ConfigurationException("Invalid map property: " + name + "=" + config.get(name)); + } + return new AbstractMap.SimpleImmutableEntry<>(splitKeyValuePairs.get(0), splitKeyValuePairs.get(1)); + }) // If duplicate keys, prioritize later ones similar to duplicate system properties on a // Java command line. - .collect( - Collectors.toMap( - Map.Entry::getKey, Map.Entry::getValue, (first, next) -> next, LinkedHashMap::new)); + .collect(Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (first, next) -> next, LinkedHashMap::new)); } private static ConfigurationException newInvalidPropertyException( @@ -158,14 +142,12 @@ private static ConfigurationException newInvalidPropertyException( } private static List filterBlanksAndNulls(final String[] values) { - return Arrays.stream(values) - .map(String::trim) - .filter(s -> !s.isEmpty()) - .collect(Collectors.toList()); + return Arrays.stream(values).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toList()); } /** * Returns the TimeUnit associated with a unit string. Defaults to milliseconds. + * * @param unitString the time unit as a string * @return the parsed TimeUnit */ @@ -191,6 +173,7 @@ private static TimeUnit getDurationUnit(final String unitString) { * Fragments the 'units' portion of a config value from the 'value' portion. * *

E.g. "1ms" would return the string "ms". + * * @param rawValue the raw value of a unit and value * @return the unit string */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java index 696aecec..54a3034f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java @@ -14,13 +14,11 @@ import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import io.opentelemetry.semconv.ResourceAttributes; - -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.traces.TracesProvider; - import java.util.HashMap; import java.util.Map; import java.util.Properties; +import org.hyperledger.fabric.shim.ChaincodeStub; +import org.hyperledger.fabric.traces.TracesProvider; public final class OpenTelemetryTracesProvider implements TracesProvider { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/package-info.java index b8aef10b..dd29ef78 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/package-info.java @@ -1,6 +1,6 @@ -/* - * Copyright 2023 IBM All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.traces.impl; +/* + * Copyright 2023 IBM All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.fabric.traces.impl; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/package-info.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/package-info.java index 07ffd3ee..147b5795 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/package-info.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/package-info.java @@ -5,15 +5,12 @@ */ /** - *

* Supports collection of traces - *

- * This creates traces at the root level of chaincode calls. * + *

This creates traces at the root level of chaincode calls. * - * To enable traces ensure that there is a standard format Java properties file - * called `config.props` in the root of your contract code. For example this - * path + *

To enable traces ensure that there is a standard format Java properties file called `config.props` in the root of + * your contract code. For example this path * *

  * myjava - contract - project / java / src / main / resources / config.props
@@ -25,15 +22,11 @@
  * CHAINCODE_TRACES_ENABLED=true
  * 
* - * The traces enabled flag will turn on default traces logging. (it's off by - * default). + * The traces enabled flag will turn on default traces logging. (it's off by default). * - * If no file is supplied traces are not enabled, the values shown for the - * thread pool are used. + *

If no file is supplied traces are not enabled, the values shown for the thread pool are used. * - *

Open Telemetry

- * - * To use Open Telemetry, set the following properties: + *

Open Telemetry To use Open Telemetry, set the following properties: * *

  * CHAINCODE_TRACES_ENABLED=true
@@ -43,7 +36,8 @@
  * Additionally, you can set properties after the specification:
  * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/sdk-environment-variables.md
  *
- * Example:
+ * 

Example: + * *

  * OTEL_EXPORTER_OTLP_ENDPOINT=otelcollector:4317
  * OTEL_EXPORTER_OTLP_INSECURE=true
diff --git a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java
index f62b044c..a97b3071 100644
--- a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java
+++ b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java
@@ -4,6 +4,13 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 import org.hyperledger.fabric.shim.ChaincodeBase;
 import org.hyperledger.fabric.shim.mock.peer.ChaincodeMockPeer;
 import org.hyperledger.fabric.shim.mock.peer.RegisterStep;
@@ -11,14 +18,6 @@
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
-
 public final class ChaincodeWithoutPackageTest {
     private ChaincodeMockPeer server;
 
@@ -39,12 +38,11 @@ public void testRegisterChaincodeWithoutPackage() throws Exception {
 
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         assertThat(server.getLastMessageSend().getType()).isEqualTo(READY);
         assertThat(server.getLastMessageRcvd().getType()).isEqualTo(REGISTER);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/contract/Greeting.java b/fabric-chaincode-shim/src/test/java/contract/Greeting.java
index b2c3bc7f..7f2a16f5 100644
--- a/fabric-chaincode-shim/src/test/java/contract/Greeting.java
+++ b/fabric-chaincode-shim/src/test/java/contract/Greeting.java
@@ -60,11 +60,9 @@ public static void validate(final Greeting greeting) {
         if (text.split(" ").length != greeting.wordCount) {
             throw new Error("Word count incorrectly set");
         }
-
     }
 
     public String toJSONString() {
         return new JSONObject(this).toString();
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java
index c10b4154..a28a2924 100644
--- a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java
+++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java
@@ -6,7 +6,6 @@
 package contract;
 
 import java.util.List;
-
 import org.hyperledger.fabric.contract.Context;
 import org.hyperledger.fabric.contract.ContractInterface;
 import org.hyperledger.fabric.contract.annotation.Contact;
@@ -19,14 +18,12 @@
 
 @Contract(
         name = "samplecontract",
-        info = @Info(
-                contact = @Contact(
-                        email = "fred@example.com"),
-                license = @License(
-                        name = "fred",
-                        url = "http://fred.me"),
-                version = "0.0.1",
-                title = "samplecontract"))
+        info =
+                @Info(
+                        contact = @Contact(email = "fred@example.com"),
+                        license = @License(name = "fred", url = "http://fred.me"),
+                        version = "0.0.1",
+                        title = "samplecontract"))
 @Default()
 public class SampleContract implements ContractInterface {
     public static int getBeforeInvoked() {
@@ -127,9 +124,7 @@ public String t2(final Context ctx) {
         return "Transaction 2";
     }
 
-    /**
-     * @param ctx
-     */
+    /** @param ctx */
     @Transaction
     public void noReturn(final Context ctx) {
         System.out.println("SampleContract::noReturn done");
@@ -150,17 +145,13 @@ public String t1(final Context ctx, final String arg1) {
         return args.get(1);
     }
 
-    /**
-     *
-     */
+    /** */
     @Override
     public void beforeTransaction(final Context ctx) {
         beforeInvoked++;
     }
 
-    /**
-     *
-     */
+    /** */
     @Override
     public void afterTransaction(final Context ctx, final Object value) {
         afterInvoked++;
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java
index cd99c74c..62751cef 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java
@@ -29,7 +29,6 @@ public void testContractException() {
 
         logger.error("all gone wrong");
         logger.error(() -> "all gone wrong");
-
     }
 
     @Test
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java
index 6c69de43..c4b22d47 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java
@@ -5,16 +5,15 @@
  */
 package org.hyperledger.fabric;
 
-import org.hamcrest.CoreMatchers;
-import org.junit.jupiter.api.Test;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.logging.Level;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.hamcrest.CoreMatchers;
+import org.junit.jupiter.api.Test;
 
 public final class LoggingTest {
     @Test
@@ -37,11 +36,13 @@ public Object proxyMapLevel(final Object... args) {
             final Method m = Logging.class.getDeclaredMethod("mapLevel", String.class);
             m.setAccessible(true);
             return m.invoke(null, args);
-        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+        } catch (NoSuchMethodException
+                | SecurityException
+                | IllegalAccessException
+                | IllegalArgumentException
                 | InvocationTargetException e) {
             throw new RuntimeException(e);
         }
-
     }
 
     @Test
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java
index ee448f66..8c48b8b5 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java
@@ -12,7 +12,6 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.Base64;
-
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cert.X509v3CertificateBuilder;
@@ -21,47 +20,66 @@
 
 public final class TestUtil {
 
-    private TestUtil() {
-
-    }
+    private TestUtil() {}
 
     public static final String CERT_WITHOUT_ATTRS = "MIICXTCCAgSgAwIBAgIUeLy6uQnq8wwyElU/jCKRYz3tJiQwCgYIKoZIzj0EAwIw"
-            + "eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh" + "biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT"
-            + "A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw" + "OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp"
-            + "bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV" + "BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa"
-            + "oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG" + "1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E"
-            + "FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr" + "TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI"
-            + "KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC" + "IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN";
+            + "eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh"
+            + "biBGcmFuY2lzY28xGTAXBgNVBAoTEEludGVybmV0IFdpZGdldHMxDDAKBgNVBAsT"
+            + "A1dXVzEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTcwOTA4MDAxNTAwWhcNMTgw"
+            + "OTA4MDAxNTAwWjBdMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xp"
+            + "bmExFDASBgNVBAoTC0h5cGVybGVkZ2VyMQ8wDQYDVQQLEwZGYWJyaWMxDjAMBgNV"
+            + "BAMTBWFkbWluMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFq/90YMuH4tWugHa"
+            + "oyZtt4Mbwgv6CkBSDfYulVO1CVInw1i/k16DocQ/KSDTeTfgJxrX1Ree1tjpaodG"
+            + "1wWyM6OBhTCBgjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4E"
+            + "FgQUhKs/VJ9IWJd+wer6sgsgtZmxZNwwHwYDVR0jBBgwFoAUIUd4i/sLTwYWvpVr"
+            + "TApzcT8zv/kwIgYDVR0RBBswGYIXQW5pbHMtTWFjQm9vay1Qcm8ubG9jYWwwCgYI"
+            + "KoZIzj0EAwIDRwAwRAIgCoXaCdU8ZiRKkai0QiXJM/GL5fysLnmG2oZ6XOIdwtsC"
+            + "IEmCsI8Mhrvx1doTbEOm7kmIrhQwUVDBNXCWX1t3kJVN";
 
     public static final String CERT_WITH_ATTRS = "MIIB6TCCAY+gAwIBAgIUHkmY6fRP0ANTvzaBwKCkMZZPUnUwCgYIKoZIzj0EAwIw"
-            + "GzEZMBcGA1UEAxMQZmFicmljLWNhLXNlcnZlcjAeFw0xNzA5MDgwMzQyMDBaFw0x" + "ODA5MDgwMzQyMDBaMB4xHDAaBgNVBAMTE015VGVzdFVzZXJXaXRoQXR0cnMwWTAT"
-            + "BgcqhkjOPQIBBggqhkjOPQMBBwNCAATmB1r3CdWvOOP3opB3DjJnW3CnN8q1ydiR" + "dzmuA6A2rXKzPIltHvYbbSqISZJubsy8gVL6GYgYXNdu69RzzFF5o4GtMIGqMA4G"
-            + "A1UdDwEB/wQEAwICBDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTYKLTAvJJK08OM" + "VGwIhjMQpo2DrjAfBgNVHSMEGDAWgBTEs/52DeLePPx1+65VhgTwu3/2ATAiBgNV"
-            + "HREEGzAZghdBbmlscy1NYWNCb29rLVByby5sb2NhbDAmBggqAwQFBgcIAQQaeyJh" + "dHRycyI6eyJhdHRyMSI6InZhbDEifX0wCgYIKoZIzj0EAwIDSAAwRQIhAPuEqWUp"
+            + "GzEZMBcGA1UEAxMQZmFicmljLWNhLXNlcnZlcjAeFw0xNzA5MDgwMzQyMDBaFw0x"
+            + "ODA5MDgwMzQyMDBaMB4xHDAaBgNVBAMTE015VGVzdFVzZXJXaXRoQXR0cnMwWTAT"
+            + "BgcqhkjOPQIBBggqhkjOPQMBBwNCAATmB1r3CdWvOOP3opB3DjJnW3CnN8q1ydiR"
+            + "dzmuA6A2rXKzPIltHvYbbSqISZJubsy8gVL6GYgYXNdu69RzzFF5o4GtMIGqMA4G"
+            + "A1UdDwEB/wQEAwICBDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTYKLTAvJJK08OM"
+            + "VGwIhjMQpo2DrjAfBgNVHSMEGDAWgBTEs/52DeLePPx1+65VhgTwu3/2ATAiBgNV"
+            + "HREEGzAZghdBbmlscy1NYWNCb29rLVByby5sb2NhbDAmBggqAwQFBgcIAQQaeyJh"
+            + "dHRycyI6eyJhdHRyMSI6InZhbDEifX0wCgYIKoZIzj0EAwIDSAAwRQIhAPuEqWUp"
             + "svTTvBqLR5JeQSctJuz3zaqGRqSs2iW+QB3FAiAIP0mGWKcgSGRMMBvaqaLytBYo" + "9v3hRt1r8j8vN0pMcg==";
 
     public static final String CERT_WITH_DNS = "MIICGjCCAcCgAwIBAgIRAIPRwJHVLhHK47XK0BbFZJswCgYIKoZIzj0EAwIwczEL"
-            + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG" + "cmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh"
-            + "Lm9yZzIuZXhhbXBsZS5jb20wHhcNMTcwNjIzMTIzMzE5WhcNMjcwNjIxMTIzMzE5" + "WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN"
-            + "U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWVXNlcjFAb3JnMi5leGFtcGxlLmNvbTBZ" + "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBd9SsEiFH1/JIb3qMEPLR2dygokFVKW"
-            + "eINcB0Ni4TBRkfIWWUJeCANTUY11Pm/+5gs+fBTqBz8M2UzpJDVX7+2jTTBLMA4G" + "A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIKfUfvpGproH"
-            + "cwyFD+0sE3XfJzYNcif0jNwvgOUFZ4AFMAoGCCqGSM49BAMCA0gAMEUCIQC8NIMw" + "e4ym/QRwCJb5umbONNLSVQuEpnPsJrM/ssBPvgIgQpe2oYa3yO3USro9nBHjpM3L"
+            + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG"
+            + "cmFuY2lzY28xGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh"
+            + "Lm9yZzIuZXhhbXBsZS5jb20wHhcNMTcwNjIzMTIzMzE5WhcNMjcwNjIxMTIzMzE5"
+            + "WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN"
+            + "U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWVXNlcjFAb3JnMi5leGFtcGxlLmNvbTBZ"
+            + "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBd9SsEiFH1/JIb3qMEPLR2dygokFVKW"
+            + "eINcB0Ni4TBRkfIWWUJeCANTUY11Pm/+5gs+fBTqBz8M2UzpJDVX7+2jTTBLMA4G"
+            + "A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIKfUfvpGproH"
+            + "cwyFD+0sE3XfJzYNcif0jNwvgOUFZ4AFMAoGCCqGSM49BAMCA0gAMEUCIQC8NIMw"
+            + "e4ym/QRwCJb5umbONNLSVQuEpnPsJrM/ssBPvgIgQpe2oYa3yO3USro9nBHjpM3L"
             + "KsFQrpVnF8O6hoHOYZQ=";
 
-    public static final String CERT_MULTIPLE_ATTRIBUTES = "MIIChzCCAi6gAwIBAgIURilAHeqwLu/fNUv8eZoGPRh3H4IwCgYIKoZIzj0EAwIw"
-            + "czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh" + "biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT"
-            + "E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkwNzMxMTYxNzAwWhcNMjAwNzMwMTYy" + "MjAwWjAgMQ8wDQYDVQQLEwZjbGllbnQxDTALBgNVBAMTBHRlc3QwWTATBgcqhkjO"
-            + "PQIBBggqhkjOPQMBBwNCAAR2taQK8w7D3hr3gBxCz+8eV4KSv7pFQfNjDHMMe9J9" + "LJwcLpVTT5hYiLLRaqQonLBxBE3Ey0FneySvFuBScas3o4HyMIHvMA4GA1UdDwEB"
-            + "/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQi3mhXS/WzcjBniwAmPdYP" + "kHqVVzArBgNVHSMEJDAigCC7VXjmSEugjAB/A0S6vfMxLsUIgag9WVNwtwwebnRC"
-            + "7TCBggYIKgMEBQYHCAEEdnsiYXR0cnMiOnsiYXR0cjEiOiJ2YWwxIiwiZm9vIjoi" + "YmFyIiwiaGVsbG8iOiJ3b3JsZCIsImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5y"
-            + "b2xsbWVudElEIjoidGVzdCIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYIKoZIzj0E" + "AwIDRwAwRAIgQxEFvnZTEsf3CSZmp9IYsxcnEOtVYleOd86LAKtk1wICIH7XOPwW"
-            + "/RE4Z8WLZzFei/78Oezbx6obOvBxPMsVWRe5";
+    public static final String CERT_MULTIPLE_ATTRIBUTES =
+            "MIIChzCCAi6gAwIBAgIURilAHeqwLu/fNUv8eZoGPRh3H4IwCgYIKoZIzj0EAwIw"
+                    + "czELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh"
+                    + "biBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT"
+                    + "E2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkwNzMxMTYxNzAwWhcNMjAwNzMwMTYy"
+                    + "MjAwWjAgMQ8wDQYDVQQLEwZjbGllbnQxDTALBgNVBAMTBHRlc3QwWTATBgcqhkjO"
+                    + "PQIBBggqhkjOPQMBBwNCAAR2taQK8w7D3hr3gBxCz+8eV4KSv7pFQfNjDHMMe9J9"
+                    + "LJwcLpVTT5hYiLLRaqQonLBxBE3Ey0FneySvFuBScas3o4HyMIHvMA4GA1UdDwEB"
+                    + "/wQEAwIHgDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQi3mhXS/WzcjBniwAmPdYP"
+                    + "kHqVVzArBgNVHSMEJDAigCC7VXjmSEugjAB/A0S6vfMxLsUIgag9WVNwtwwebnRC"
+                    + "7TCBggYIKgMEBQYHCAEEdnsiYXR0cnMiOnsiYXR0cjEiOiJ2YWwxIiwiZm9vIjoi"
+                    + "YmFyIiwiaGVsbG8iOiJ3b3JsZCIsImhmLkFmZmlsaWF0aW9uIjoiIiwiaGYuRW5y"
+                    + "b2xsbWVudElEIjoidGVzdCIsImhmLlR5cGUiOiJjbGllbnQifX0wCgYIKoZIzj0E"
+                    + "AwIDRwAwRAIgQxEFvnZTEsf3CSZmp9IYsxcnEOtVYleOd86LAKtk1wICIH7XOPwW"
+                    + "/RE4Z8WLZzFei/78Oezbx6obOvBxPMsVWRe5";
 
     /**
      * Function to create a certificate with dummy attributes
      *
-     * @param attributeValue {String} value to be written to the identity attributes
-     *                       section of the certificate
+     * @param attributeValue {String} value to be written to the identity attributes section of the certificate
      * @return encodedCert {String} encoded certificate with re-written attributes
      */
     public static String createCertWithIdentityAttributes(final String attributeValue) throws Exception {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java
index 6852d616..86cee5cf 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java
@@ -27,7 +27,8 @@ public final class AllTypesAsset {
     private float theFloat = 3.1415926535_8979323846_2643383279_5028841971_6939937510_5820974944_5923078164f;
 
     @Property
-    private double theDouble = 3.1415926535_8979323846_2643383279_5028841971_6939937510_5820974944_5923078164_0628620899_8628034825_3421170679d;
+    private double theDouble =
+            3.1415926535_8979323846_2643383279_5028841971_6939937510_5820974944_5923078164_0628620899_8628034825_3421170679d;
 
     @Property
     private boolean theBoolean = false;
@@ -122,8 +123,14 @@ public void setTheCustomObject(final MyType customObject) {
     }
 
     public boolean equals(final AllTypesAsset obj) {
-        return theByte == obj.getTheByte() && theShort == obj.getTheShort() && theInt == obj.getTheInt() && theLong == obj.getTheLong()
-                && theFloat == obj.getTheFloat() && theDouble == obj.getTheDouble() && theBoolean == obj.isTheBoolean() && theString.equals(obj.getTheString());
+        return theByte == obj.getTheByte()
+                && theShort == obj.getTheShort()
+                && theInt == obj.getTheInt()
+                && theLong == obj.getTheLong()
+                && theFloat == obj.getTheFloat()
+                && theDouble == obj.getTheDouble()
+                && theBoolean == obj.isTheBoolean()
+                && theString.equals(obj.getTheString());
     }
 
     @Override
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java
index dcd7c2ff..0054c1d6 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java
@@ -5,6 +5,7 @@
  */
 package org.hyperledger.fabric.contract;
 
+import com.google.protobuf.ByteString;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.ArrayList;
@@ -13,7 +14,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-
 import org.hyperledger.fabric.TestUtil;
 import org.hyperledger.fabric.protos.msp.SerializedIdentity;
 import org.hyperledger.fabric.protos.peer.ChaincodeEvent;
@@ -26,8 +26,6 @@
 import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
 import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata;
 
-import com.google.protobuf.ByteString;
-
 public final class ChaincodeStubNaiveImpl implements ChaincodeStub {
     private List args;
     private List argsAsByte;
@@ -93,7 +91,8 @@ public String getChannelId() {
     }
 
     @Override
-    public Chaincode.Response invokeChaincode(final String chaincodeName, final List args, final String channel) {
+    public Chaincode.Response invokeChaincode(
+            final String chaincodeName, final List args, final String channel) {
         return resp;
     }
 
@@ -110,13 +109,10 @@ public byte[] getStateValidationParameter(final String key) {
     @Override
     public void putState(final String key, final byte[] value) {
         state.put(key, ByteString.copyFrom(value));
-
     }
 
     @Override
-    public void setStateValidationParameter(final String key, final byte[] value) {
-
-    }
+    public void setStateValidationParameter(final String key, final byte[] value) {}
 
     @Override
     public void delState(final String key) {
@@ -129,8 +125,8 @@ public QueryResultsIterator getStateByRange(final String startKey, fin
     }
 
     @Override
-    public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(final String startKey, final String endKey, final int pageSize,
-            final String bookmark) {
+    public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(
+            final String startKey, final String endKey, final int pageSize, final String bookmark) {
         return null;
     }
 
@@ -140,7 +136,8 @@ public QueryResultsIterator getStateByPartialCompositeKey(final String
     }
 
     @Override
-    public QueryResultsIterator getStateByPartialCompositeKey(final String objectType, final String... attributes) {
+    public QueryResultsIterator getStateByPartialCompositeKey(
+            final String objectType, final String... attributes) {
         return null;
     }
 
@@ -150,8 +147,8 @@ public QueryResultsIterator getStateByPartialCompositeKey(final Compos
     }
 
     @Override
-    public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(final CompositeKey compositeKey, final int pageSize,
-            final String bookmark) {
+    public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(
+            final CompositeKey compositeKey, final int pageSize, final String bookmark) {
         return null;
     }
 
@@ -171,7 +168,8 @@ public QueryResultsIterator getQueryResult(final String query) {
     }
 
     @Override
-    public QueryResultsIteratorWithMetadata getQueryResultWithPagination(final String query, final int pageSize, final String bookmark) {
+    public QueryResultsIteratorWithMetadata getQueryResultWithPagination(
+            final String query, final int pageSize, final String bookmark) {
         return null;
     }
 
@@ -196,42 +194,38 @@ public byte[] getPrivateDataValidationParameter(final String collection, final S
     }
 
     @Override
-    public void putPrivateData(final String collection, final String key, final byte[] value) {
-
-    }
+    public void putPrivateData(final String collection, final String key, final byte[] value) {}
 
     @Override
-    public void setPrivateDataValidationParameter(final String collection, final String key, final byte[] value) {
-
-    }
+    public void setPrivateDataValidationParameter(final String collection, final String key, final byte[] value) {}
 
     @Override
-    public void delPrivateData(final String collection, final String key) {
-
-    }
+    public void delPrivateData(final String collection, final String key) {}
 
     @Override
-    public void purgePrivateData(final String collection, final String key) {
-
-    }
+    public void purgePrivateData(final String collection, final String key) {}
 
     @Override
-    public QueryResultsIterator getPrivateDataByRange(final String collection, final String startKey, final String endKey) {
+    public QueryResultsIterator getPrivateDataByRange(
+            final String collection, final String startKey, final String endKey) {
         return null;
     }
 
     @Override
-    public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final String compositeKey) {
+    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+            final String collection, final String compositeKey) {
         return null;
     }
 
     @Override
-    public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final CompositeKey compositeKey) {
+    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+            final String collection, final CompositeKey compositeKey) {
         return null;
     }
 
     @Override
-    public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final String objectType, final String... attributes) {
+    public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+            final String collection, final String objectType, final String... attributes) {
         return null;
     }
 
@@ -241,9 +235,7 @@ public QueryResultsIterator getPrivateDataQueryResult(final String col
     }
 
     @Override
-    public void setEvent(final String name, final byte[] payload) {
-
-    }
+    public void setEvent(final String name, final byte[] payload) {}
 
     @Override
     public ChaincodeEvent getEvent() {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java
index f9dae17a..9f85095d 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java
@@ -6,39 +6,38 @@
 
 package org.hyperledger.fabric.contract;
 
-import org.hyperledger.fabric.TestUtil;
-import org.hyperledger.fabric.shim.ChaincodeStub;
-import org.junit.jupiter.api.Test;
-
-import java.math.BigInteger;
-
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.math.BigInteger;
+import org.hyperledger.fabric.TestUtil;
+import org.hyperledger.fabric.shim.ChaincodeStub;
+import org.junit.jupiter.api.Test;
+
 public class ClientIdentityTest {
-    /**
-     * Test client identity can be created using certificate without attributes
-     */
+    /** Test client identity can be created using certificate without attributes */
     @Test
     public void clientIdentityWithoutAttributes() throws Exception {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
         final ClientIdentity identity = new ClientIdentity(stub);
         assertEquals(identity.getMSPID(), "testMSPID");
-        assertEquals(identity.getId(),
+        assertEquals(
+                identity.getId(),
                 "x509::CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina, C=US::CN=example.com,"
                         + " OU=WWW, O=Internet Widgets, L=San Francisco, ST=California, C=US");
         assertEquals(identity.getAttributeValue("attr1"), null);
         assertEquals(identity.getAttributeValue("val1"), null);
-        assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(),
+        assertEquals(
+                identity.getX509Certificate().getSubjectX500Principal().toString(),
                 "CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina, C=US");
-        assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("689287698446788666856807436918134903862142510628"));
+        assertEquals(
+                identity.getX509Certificate().getSerialNumber(),
+                new BigInteger("689287698446788666856807436918134903862142510628"));
     }
 
-    /**
-     * Test client identity can be created using certificate with attributes
-     */
+    /** Test client identity can be created using certificate with attributes */
     @Test
     public void clientIdentityWithAttributes() throws Exception {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
@@ -52,20 +51,21 @@ public void clientIdentityWithAttributes() throws Exception {
         assertEquals(identity.assertAttributeValue("attr1", "val2"), false);
         assertEquals(identity.assertAttributeValue("attr2", "val1"), false);
         assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=MyTestUserWithAttrs");
-        assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("172910998202207082780622887076293058980152824437"));
+        assertEquals(
+                identity.getX509Certificate().getSerialNumber(),
+                new BigInteger("172910998202207082780622887076293058980152824437"));
     }
 
-    /**
-     * Test client identity can be created using certificate with multiple
-     * attributes
-     */
+    /** Test client identity can be created using certificate with multiple attributes */
     @Test
     public void clientIdentityWithMultipleAttributes() throws Exception {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
         ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.CERT_MULTIPLE_ATTRIBUTES);
         final ClientIdentity identity = new ClientIdentity(stub);
         assertEquals(identity.getMSPID(), "testMSPID");
-        assertEquals(identity.getId(), "x509::CN=test, OU=client::CN=ca.org1.example.com, O=org1.example.com, L=San Francisco, ST=California, C=US");
+        assertEquals(
+                identity.getId(),
+                "x509::CN=test, OU=client::CN=ca.org1.example.com, O=org1.example.com, L=San Francisco, ST=California, C=US");
         assertEquals(identity.getAttributeValue("hello"), "world");
         assertEquals(identity.getAttributeValue("foo"), "bar");
         assertEquals(identity.getAttributeValue("attr1"), "val1");
@@ -74,30 +74,31 @@ public void clientIdentityWithMultipleAttributes() throws Exception {
         assertEquals(identity.assertAttributeValue("attr1", "val2"), false);
         assertEquals(identity.assertAttributeValue("hello", "val1"), false);
         assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=test, OU=client");
-        assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("400549269877250942864348502164024974865235124098"));
+        assertEquals(
+                identity.getX509Certificate().getSerialNumber(),
+                new BigInteger("400549269877250942864348502164024974865235124098"));
     }
 
-    /**
-     * Test client identity can be created using certificate with long distinguished
-     * name
-     */
+    /** Test client identity can be created using certificate with long distinguished name */
     @Test
     public void clientIdentityWithLongDNs() throws Exception {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
         ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.CERT_WITH_DNS);
         final ClientIdentity identity = new ClientIdentity(stub);
         assertEquals(identity.getMSPID(), "testMSPID");
-        assertEquals(identity.getId(),
+        assertEquals(
+                identity.getId(),
                 "x509::CN=User1@org2.example.com, L=San Francisco, ST=California,"
-                + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US");
-        assertEquals(identity.getX509Certificate().getSubjectX500Principal().toString(), "CN=User1@org2.example.com, L=San Francisco, ST=California, C=US");
-        assertEquals(identity.getX509Certificate().getSerialNumber(), new BigInteger("175217963267961225716341475631843075227"));
+                        + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US");
+        assertEquals(
+                identity.getX509Certificate().getSubjectX500Principal().toString(),
+                "CN=User1@org2.example.com, L=San Francisco, ST=California, C=US");
+        assertEquals(
+                identity.getX509Certificate().getSerialNumber(),
+                new BigInteger("175217963267961225716341475631843075227"));
     }
 
-    /**
-     * Test client identity throws a ContractRuntimeException when creating a
-     * serialized identity fails
-     */
+    /** Test client identity throws a ContractRuntimeException when creating a serialized identity fails */
     @Test
     public void catchInvalidProtocolBufferException() {
         final ChaincodeStub stub = mock(ChaincodeStub.class);
@@ -106,18 +107,15 @@ public void catchInvalidProtocolBufferException() {
         assertThatThrownBy(() -> ContextFactory.getInstance().createContext(stub))
                 .isInstanceOf(ContractRuntimeException.class)
                 .hasMessage("Could not create new client identity");
-
     }
 
-    /**
-     * Test client identity attributes are empty when using a certificate with dummy
-     * attributes
-     */
+    /** Test client identity attributes are empty when using a certificate with dummy attributes */
     @Test
     public void createClientIdentityWithDummyAttributesCert() throws Exception {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
         // Create a certificate with rubbish attributes
-        final String certWithDummyAttrs = TestUtil.createCertWithIdentityAttributes("{gsdhrlxhvcilgwoueglfs,djhzxo;vjs.dcx }");
+        final String certWithDummyAttrs =
+                TestUtil.createCertWithIdentityAttributes("{gsdhrlxhvcilgwoueglfs,djhzxo;vjs.dcx }");
         ((ChaincodeStubNaiveImpl) stub).setCertificate(certWithDummyAttrs);
         final ClientIdentity identity = new ClientIdentity(stub);
 
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java
index a10ef5de..d0c6c393 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java
@@ -5,15 +5,14 @@
  */
 package org.hyperledger.fabric.contract;
 
-import org.hyperledger.fabric.shim.ChaincodeStub;
-import org.junit.jupiter.api.Test;
-
-import java.util.Collections;
-
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.sameInstance;
-import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Collections;
+import org.hyperledger.fabric.shim.ChaincodeStub;
+import org.junit.jupiter.api.Test;
 
 public class ContextFactoryTest {
 
@@ -35,7 +34,8 @@ public void createContext() {
         assertThat(stub.getParameters(), is(equalTo(ctx.getStub().getParameters())));
         assertThat(stub.getTxId(), is(equalTo(ctx.getStub().getTxId())));
         assertThat(stub.getChannelId(), is(equalTo(ctx.getStub().getChannelId())));
-        assertThat(stub.invokeChaincode("cc", Collections.emptyList(), "ch0"),
+        assertThat(
+                stub.invokeChaincode("cc", Collections.emptyList(), "ch0"),
                 is(equalTo(ctx.getStub().invokeChaincode("cc", Collections.emptyList(), "ch0"))));
 
         assertThat(stub.getState("a"), is(equalTo(ctx.getStub().getState("a"))));
@@ -43,8 +43,9 @@ public void createContext() {
         assertThat(stub.getStringState("b"), is(equalTo(ctx.getStub().getStringState("b"))));
 
         assertThat(ctx.clientIdentity.getMSPID(), is(equalTo("testMSPID")));
-        assertThat(ctx.clientIdentity.getId(), is(equalTo(
-                "x509::CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina,"
-                + " C=US::CN=example.com, OU=WWW, O=Internet Widgets, L=San Francisco, ST=California, C=US")));
+        assertThat(
+                ctx.clientIdentity.getId(),
+                is(equalTo("x509::CN=admin, OU=Fabric, O=Hyperledger, ST=North Carolina,"
+                        + " C=US::CN=example.com, OU=WWW, O=Internet Widgets, L=San Francisco, ST=California, C=US")));
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java
index 2d3bf088..405e68ff 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java
@@ -5,17 +5,15 @@
  */
 package org.hyperledger.fabric.contract;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.sameInstance;
+
 import org.hyperledger.fabric.shim.ChaincodeStub;
 import org.junit.jupiter.api.Test;
 
-import static org.hamcrest.Matchers.sameInstance;
-import static org.hamcrest.MatcherAssert.assertThat;
-
 public class ContextTest {
 
-    /**
-     * Test creating a new context returns what we expect
-     */
+    /** Test creating a new context returns what we expect */
     @Test
     public void getInstance() {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
@@ -24,14 +22,11 @@ public void getInstance() {
         assertThat(context1.getStub(), sameInstance(context2.getStub()));
     }
 
-    /**
-     * Test identity created in Context constructor matches getClientIdentity
-     */
+    /** Test identity created in Context constructor matches getClientIdentity */
     @Test
     public void getSetClientIdentity() {
         final ChaincodeStub stub = new ChaincodeStubNaiveImpl();
         final Context context = ContextFactory.getInstance().createContext(stub);
         assertThat(context.getClientIdentity(), sameInstance(context.clientIdentity));
-
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java
index a3b468fe..e3fcdd6a 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java
@@ -5,25 +5,25 @@
  */
 package org.hyperledger.fabric.contract;
 
-import org.hyperledger.fabric.shim.ChaincodeException;
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.instanceOf;
 import static org.hamcrest.Matchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.hyperledger.fabric.shim.ChaincodeException;
+import org.junit.jupiter.api.Test;
 
 public class ContractInterfaceTest {
     @Test
     public void createContext() {
-        assertThat((new ContractInterface() {
-        }).createContext(new ChaincodeStubNaiveImpl()), is(instanceOf(Context.class)));
+        assertThat(
+                (new ContractInterface() {}).createContext(new ChaincodeStubNaiveImpl()),
+                is(instanceOf(Context.class)));
     }
 
     @Test
     public void unknownTransaction() {
-        final ContractInterface c = new ContractInterface() {
-        };
+        final ContractInterface c = new ContractInterface() {};
 
         assertThatThrownBy(() -> c.unknownTransaction(c.createContext(new ChaincodeStubNaiveImpl())))
                 .isInstanceOf(ChaincodeException.class)
@@ -32,16 +32,14 @@ public void unknownTransaction() {
 
     @Test
     public void beforeTransaction() {
-        final ContractInterface c = new ContractInterface() {
-        };
+        final ContractInterface c = new ContractInterface() {};
 
         c.beforeTransaction(c.createContext(new ChaincodeStubNaiveImpl()));
     }
 
     @Test
     public void afterTransaction() {
-        final ContractInterface c = new ContractInterface() {
-        };
+        final ContractInterface c = new ContractInterface() {};
         c.afterTransaction(c.createContext(new ChaincodeStubNaiveImpl()), "ReturnValue");
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java
index 987922f5..b5692cc2 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java
@@ -5,7 +5,19 @@
  */
 package org.hyperledger.fabric.contract;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
 import contract.SampleContract;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
 import org.hyperledger.fabric.contract.annotation.Contract;
 import org.hyperledger.fabric.contract.execution.ExecutionFactory;
 import org.hyperledger.fabric.contract.execution.InvocationRequest;
@@ -16,23 +28,10 @@
 import org.hyperledger.fabric.shim.NettyChaincodeServer;
 import org.junit.jupiter.api.Test;
 
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
-
 public class ContractRouterTest {
     @Test
     public void testCreateFailsWithoutValidOptions() {
-        assertThatThrownBy(() -> new ContractRouter(new String[]{}))
+        assertThatThrownBy(() -> new ContractRouter(new String[] {}))
                 .isInstanceOf(IllegalArgumentException.class)
                 .hasMessageContaining("The chaincode id must be specified using either the -i or --i command "
                         + "line options or the CORE_CHAINCODE_ID_NAME environment variable.");
@@ -40,7 +39,7 @@ public void testCreateFailsWithoutValidOptions() {
 
     @Test
     public void testCreateAndScan() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -50,7 +49,9 @@ public void testCreateAndScan() {
         args.add("asdf");
         ((ChaincodeStubNaiveImpl) s).setStringArgs(args);
         final InvocationRequest request = ExecutionFactory.getInstance().createRequest(s);
-        assertThat(request.getNamespace(), is(equalTo(SampleContract.class.getAnnotation(Contract.class).name())));
+        assertThat(
+                request.getNamespace(),
+                is(equalTo(SampleContract.class.getAnnotation(Contract.class).name())));
         assertThat(request.getMethod(), is(equalTo("t1")));
         assertThat(request.getRequestName(), is(equalTo("samplecontract:t1")));
         assertThat(request.getArgs(), is(contains(s.getArgs().get(1))));
@@ -58,7 +59,7 @@ public void testCreateAndScan() {
 
     @Test
     public void testInit() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -83,13 +84,10 @@ public void testInit() {
         assertThat(SampleContract.getT1Invoked(), is(1));
     }
 
-    /**
-     * Test invoking two transaction functions in a contract via fully qualified
-     * name
-     */
+    /** Test invoking two transaction functions in a contract via fully qualified name */
     @Test
     public void testInvokeTwoTxnsThatExist() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -136,7 +134,7 @@ public void testInvokeTwoTxnsThatExist() {
 
     @Test
     public void testInvokeTxnWithDefinedName() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -161,12 +159,10 @@ public void testInvokeTxnWithDefinedName() {
         assertThat(SampleContract.getT1Invoked(), is(0));
     }
 
-    /**
-     * Test invoking two transaction functions in a contract via default name name
-     */
+    /** Test invoking two transaction functions in a contract via default name name */
     @Test
     public void testInvokeTwoTxnsWithDefaultNamespace() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -213,7 +209,7 @@ public void testInvokeTwoTxnsWithDefaultNamespace() {
 
     @Test
     public void testInvokeTxnWithDefinedNameUsingMethodName() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -240,7 +236,7 @@ public void testInvokeTxnWithDefinedNameUsingMethodName() {
 
     @Test
     public void testInvokeContractThatDoesNotExist() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -267,7 +263,7 @@ public void testInvokeContractThatDoesNotExist() {
 
     @Test
     public void testInvokeTxnThatDoesNotExist() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -294,7 +290,7 @@ public void testInvokeTxnThatDoesNotExist() {
 
     @Test
     public void testInvokeTxnThatReturnsNullString() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -321,7 +317,7 @@ public void testInvokeTxnThatReturnsNullString() {
 
     @Test
     public void testInvokeTxnThatThrowsAnException() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -335,7 +331,6 @@ public void testInvokeTxnThatThrowsAnException() {
         SampleContract.setAfterInvoked(0);
         SampleContract.setDoWorkInvoked(0);
 
-
         final Chaincode.Response response = r.invoke(s);
         assertThat(response, is(notNullValue()));
         assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR));
@@ -348,7 +343,7 @@ public void testInvokeTxnThatThrowsAnException() {
 
     @Test
     public void testInvokeTxnThatThrowsAChaincodeException() {
-        final ContractRouter r = new ContractRouter(new String[]{"-a", "127.0.0.1:7052", "-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         r.findAllContracts();
         final ChaincodeStub s = new ChaincodeStubNaiveImpl();
 
@@ -362,7 +357,6 @@ public void testInvokeTxnThatThrowsAChaincodeException() {
         SampleContract.setAfterInvoked(0);
         SampleContract.setDoWorkInvoked(0);
 
-
         final Chaincode.Response response = r.invoke(s);
         assertThat(response, is(notNullValue()));
         assertThat(response.getStatus(), is(Chaincode.Response.Status.INTERNAL_SERVER_ERROR));
@@ -373,9 +367,7 @@ public void testInvokeTxnThatThrowsAChaincodeException() {
         assertThat(SampleContract.getDoWorkInvoked(), is(0));
     }
 
-    /**
-     * Test confirming ContractRuntimeExceptions can be created.
-     */
+    /** Test confirming ContractRuntimeExceptions can be created. */
     @Test
     public void createContractRuntimeExceptions() {
         final ContractRuntimeException cre1 = new ContractRuntimeException("failure");
@@ -387,17 +379,17 @@ public void createContractRuntimeExceptions() {
     public void testStartingContractRouterWithStartingAChaincodeServer() throws IOException {
         ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
         chaincodeServerProperties.setServerAddress(new InetSocketAddress("0.0.0.0", 9999));
-        final ContractRouter r = new ContractRouter(new String[]{"-i", "testId"});
+        final ContractRouter r = new ContractRouter(new String[] {"-i", "testId"});
         ChaincodeServer chaincodeServer = new NettyChaincodeServer(r, chaincodeServerProperties);
 
         new Thread(() -> {
-            try {
-                r.startRouterWithChaincodeServer(chaincodeServer);
-            } catch (IOException | InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-        ).start();
+                    try {
+                        r.startRouterWithChaincodeServer(chaincodeServer);
+                    } catch (IOException | InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                })
+                .start();
 
         try {
             Thread.sleep(5000);
@@ -419,8 +411,10 @@ public void testStartingContractRouterWithStartingAChaincodeServer() throws IOEx
 
         final Chaincode.Response response = r.init(s);
         assertThat(response, is(notNullValue()));
-        assertThat(response.getMessage() + " " + response.getStringPayload() + response.toString(),
-                response.getStatus(), is(Chaincode.Response.Status.SUCCESS));
+        assertThat(
+                response.getMessage() + " " + response.getStringPayload() + response.toString(),
+                response.getStatus(),
+                is(Chaincode.Response.Status.SUCCESS));
         assertThat(response.getMessage(), is(nullValue()));
         assertThat(response.getStringPayload(), is(equalTo("asdf")));
         assertThat(SampleContract.getBeforeInvoked(), is(1));
@@ -430,5 +424,4 @@ public void testStartingContractRouterWithStartingAChaincodeServer() throws IOEx
 
         chaincodeServer.stop();
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java
index 956f774a..893aa81e 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java
@@ -18,8 +18,8 @@ public final class MyType {
 
     private String state = "";
 
-    public static final  String STARTED = "STARTED";
-    public static final  String STOPPED = "STOPPED";
+    public static final String STARTED = "STARTED";
+    public static final String STOPPED = "STOPPED";
 
     public void setState(final String state) {
         this.state = state;
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java
index 53cc5fcc..9da03bbc 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType2.java
@@ -15,7 +15,21 @@ public final class MyType2 {
     @Property()
     private String value;
 
-    @Property(schema = {"title", "MrProperty", "Pattern", "[a-z]", "uniqueItems", "false", "required", "true,false", "enum", "a,bee,cee,dee", "minimum", "42"})
+    @Property(
+            schema = {
+                "title",
+                "MrProperty",
+                "Pattern",
+                "[a-z]",
+                "uniqueItems",
+                "false",
+                "required",
+                "true,false",
+                "enum",
+                "a,bee,cee,dee",
+                "minimum",
+                "42"
+            })
     private String constrainedValue;
 
     public MyType2 setValue(final String value) {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java
index edd4e799..3cc4df28 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java
@@ -5,12 +5,12 @@
  */
 package org.hyperledger.fabric.contract;
 
-import org.hyperledger.fabric.shim.ChaincodeException;
-import org.junit.jupiter.api.Test;
-
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.nullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.hyperledger.fabric.shim.ChaincodeException;
+import org.junit.jupiter.api.Test;
 
 public class TransactionExceptionTest {
 
@@ -71,7 +71,8 @@ public void testMessageAndPayloadArgConstructor() {
 
     @Test
     public void testMessagePayloadAndCauseArgConstructor() {
-        final ChaincodeException e = new ChaincodeException("Failure", new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'}, new Error("Cause"));
+        final ChaincodeException e =
+                new ChaincodeException("Failure", new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'}, new Error("Cause"));
         assertThat(e.getMessage(), is("Failure"));
         assertThat(e.getPayload(), is(new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'}));
         assertThat(e.getCause().getMessage(), is("Cause"));
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java
index cbf1f2ce..67d006d3 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java
@@ -6,7 +6,19 @@
 
 package org.hyperledger.fabric.contract.execution;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import contract.SampleContract;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collections;
 import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl;
 import org.hyperledger.fabric.contract.Context;
 import org.hyperledger.fabric.contract.ContractInterface;
@@ -21,23 +33,11 @@
 import org.hyperledger.fabric.shim.ChaincodeStub;
 import org.junit.jupiter.api.Test;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.ArrayList;
-import java.util.Collections;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 public final class ContractExecutionServiceTest {
     @Test
     public void noReturnValue()
-            throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException {
+            throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException,
+                    SecurityException {
         JSONTransactionSerializer jts = new JSONTransactionSerializer();
         SerializerRegistryImpl serializerRegistry = spy(new SerializerRegistryImpl());
         ContractExecutionService ces = new ContractExecutionService(serializerRegistry);
@@ -51,18 +51,19 @@ public void noReturnValue()
 
         when(txFn.getRouting()).thenReturn(routing);
         when(req.getArgs()).thenReturn(new ArrayList());
-        when(routing.getMethod()).thenReturn(SampleContract.class.getMethod("noReturn", new Class[] {Context.class}));
+        when(routing.getMethod())
+                .thenReturn(SampleContract.class.getMethod("noReturn", new Class[] {Context.class}));
         when(routing.getContractInstance()).thenReturn(contract);
         when(serializerRegistry.getSerializer(any(), any())).thenReturn(jts);
         ces.executeRequest(txFn, req, stub);
 
         verify(contract).beforeTransaction(any());
-
     }
 
     @Test()
     public void failureToInvoke()
-            throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException {
+            throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException,
+                    SecurityException {
         JSONTransactionSerializer jts = new JSONTransactionSerializer();
         SerializerRegistryImpl serializerRegistry = spy(new SerializerRegistryImpl());
         ContractExecutionService ces = new ContractExecutionService(serializerRegistry);
@@ -74,10 +75,8 @@ public void failureToInvoke()
 
         ChaincodeStub stub = mock(ChaincodeStub.class);
 
-
         when(txFn.getRouting()).thenReturn(routing);
-        when(req.getArgs()).thenReturn(new ArrayList() {
-        });
+        when(req.getArgs()).thenReturn(new ArrayList() {});
 
         when(routing.getContractInstance()).thenThrow(IllegalAccessException.class);
         when(routing.toString()).thenReturn("MockMethodName:MockClassName");
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java
index 169ad41f..eb15c8c9 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java
@@ -6,12 +6,11 @@
 
 package org.hyperledger.fabric.contract.execution;
 
-import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.nio.charset.StandardCharsets;
-
 import org.hyperledger.fabric.contract.AllTypesAsset;
 import org.hyperledger.fabric.contract.MyType;
 import org.hyperledger.fabric.contract.metadata.MetadataBuilder;
@@ -224,7 +223,6 @@ public void fromBufferObject() {
         final MyType[] o = (MyType[]) serializer.fromBuffer(buffer, ts);
         assertThat(o[0].toString(), equalTo("++++ MyType: hello"));
         assertThat(o[1].toString(), equalTo("++++ MyType: world"));
-
     }
 
     @Test
@@ -279,8 +277,5 @@ public void fromBufferErrors() {
         serializer.toBuffer(null, ts);
     }
 
-    class MyTestObject {
-
-    }
-
+    class MyTestObject {}
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java
index 8204b343..903a287f 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java
@@ -6,6 +6,10 @@
 package org.hyperledger.fabric.contract.metadata;
 
 import contract.SampleContract;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.util.HashMap;
 import org.everit.json.schema.loader.SchemaClient;
 import org.everit.json.schema.loader.internal.DefaultSchemaClient;
 import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl;
@@ -18,19 +22,20 @@
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.io.InputStream;
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-
 public final class MetadataBuilderTest {
     private final String expectedMetadataString = "    {\n" + "       \"components\": {\"schemas\": {}},\n"
-            + "       \"$schema\": \"https://fabric-shim.github.io/contract-schema.json\",\n" + "       \"contracts\": {\"SampleContract\": {\n"
-            + "          \"name\": \"SampleContract\",\n" + "          \"transactions\": [],\n" + "          \"info\": {\n"
-            + "             \"license\": {\"name\": \"\"},\n" + "             \"description\": \"\",\n" + "             \"termsOfService\": \"\",\n"
-            + "             \"title\": \"\",\n" + "             \"version\": \"\",\n" + "             \"contact\": {\"email\": \"fred@example.com\"}\n"
-            + "          }\n" + "       }},\n" + "       \"info\": {\n" + "          \"license\": {\"name\": \"\"},\n" + "          \"description\": \"\",\n"
-            + "          \"termsOfService\": \"\",\n" + "          \"title\": \"\",\n" + "          \"version\": \"\",\n"
+            + "       \"$schema\": \"https://fabric-shim.github.io/contract-schema.json\",\n"
+            + "       \"contracts\": {\"SampleContract\": {\n"
+            + "          \"name\": \"SampleContract\",\n" + "          \"transactions\": [],\n"
+            + "          \"info\": {\n"
+            + "             \"license\": {\"name\": \"\"},\n" + "             \"description\": \"\",\n"
+            + "             \"termsOfService\": \"\",\n"
+            + "             \"title\": \"\",\n" + "             \"version\": \"\",\n"
+            + "             \"contact\": {\"email\": \"fred@example.com\"}\n"
+            + "          }\n" + "       }},\n" + "       \"info\": {\n" + "          \"license\": {\"name\": \"\"},\n"
+            + "          \"description\": \"\",\n"
+            + "          \"termsOfService\": \"\",\n" + "          \"title\": \"\",\n"
+            + "          \"version\": \"\",\n"
             + "          \"contact\": {\"email\": \"fred@example.com\"}\n" + "       }\n" + "    }\n" + "";
 
     // fields are private, so use reflection to bypass this for unit testing
@@ -53,7 +58,6 @@ public void beforeAndAfterEach() {
         setMetadataBuilderField("contractMap", new HashMap>());
         setMetadataBuilderField("overallInfoMap", new HashMap());
         setMetadataBuilderField("schemaClient", new DefaultSchemaClient());
-
     }
 
     @Test
@@ -74,9 +78,7 @@ public void defaultSchemasNotLoadedFromNetwork() {
             public InputStream get(final String uri) {
                 throw new RuntimeException("Refusing to load schema: " + uri);
             }
-
         });
         MetadataBuilder.validate();
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java
index d06e6d6d..4139c165 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java
@@ -5,8 +5,8 @@
  */
 package org.hyperledger.fabric.contract.metadata;
 
-import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import org.hyperledger.fabric.contract.annotation.DataType;
@@ -21,8 +21,7 @@
 public class TypeSchemaTest {
 
     @BeforeEach
-    public void beforeEach() {
-    }
+    public void beforeEach() {}
 
     @Test
     public void putIfNotNull() {
@@ -90,8 +89,7 @@ public void getItems() {
     }
 
     @DataType
-    class MyType {
-    }
+    class MyType {}
 
     @Test
     public void getTypeClass() {
@@ -138,7 +136,6 @@ public void getTypeClass() {
         array.put("type", "array");
         array.put("items", ts);
         assertThat(array.getTypeClass(mockRegistry), equalTo(MyType[].class));
-
     }
 
     @Test
@@ -188,7 +185,6 @@ public void typeConvertPrimitives() {
 
         rts = TypeSchema.typeConvert(boolean.class);
         assertThat(rts.getType(), equalTo("boolean"));
-
     }
 
     @Test
@@ -235,6 +231,5 @@ public void validate() {
         MetadataBuilder.addComponent(dtd);
         final JSONObject json = new JSONObject();
         ts.validate(json);
-
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java
index 0a564013..a948720c 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java
@@ -5,7 +5,14 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.startsWith;
+
 import contract.SampleContract;
+import java.lang.reflect.Method;
+import java.security.Permission;
 import org.hyperledger.fabric.contract.Context;
 import org.hyperledger.fabric.contract.ContractInterface;
 import org.hyperledger.fabric.contract.ContractRuntimeException;
@@ -14,14 +21,6 @@
 import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl;
 import org.junit.jupiter.api.Test;
 
-import java.lang.reflect.Method;
-import java.security.Permission;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.startsWith;
-
 public class ContractDefinitionTest {
     @Test
     public void constructor() throws NoSuchMethodException, SecurityException {
@@ -31,9 +30,7 @@ public void constructor() throws NoSuchMethodException, SecurityException {
     }
 
     @Contract(name = "", info = @Info())
-    public class FailureTestObject {
-
-    }
+    public class FailureTestObject {}
 
     private boolean fail;
     private final int step = 1;
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java
index 015357ec..f08e3bd4 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java
@@ -5,17 +5,16 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
-import org.hyperledger.fabric.contract.MyType2;
-import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl;
-import org.junit.jupiter.api.Test;
-
-import java.util.Map;
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasEntry;
 import static org.hamcrest.Matchers.hasKey;
 
+import java.util.Map;
+import org.hyperledger.fabric.contract.MyType2;
+import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl;
+import org.junit.jupiter.api.Test;
+
 public class DataTypeDefinitionTest {
     @Test
     public void constructor() {
@@ -38,7 +37,5 @@ public void constructor() {
         assertThat(ts, hasEntry("required", new String[] {"true", "false"}));
         assertThat(ts, hasEntry("enum", new String[] {"a", "bee", "cee", "dee"}));
         assertThat(ts, hasEntry("minimum", 42));
-
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java
index 823dd06f..84524443 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java
@@ -5,19 +5,19 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+import java.lang.reflect.Parameter;
 import org.hyperledger.fabric.contract.metadata.TypeSchema;
 import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl;
 import org.junit.jupiter.api.Test;
 
-import java.lang.reflect.Parameter;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-
 public class ParameterDefinitionTest {
     @Test
     public void constructor() throws NoSuchMethodException, SecurityException {
-        final Parameter[] params = String.class.getMethod("concat", String.class).getParameters();
+        final Parameter[] params =
+                String.class.getMethod("concat", String.class).getParameters();
         final ParameterDefinition pd = new ParameterDefinitionImpl("test", String.class, new TypeSchema(), params[0]);
         assertThat(pd.toString(), equalTo("test-class java.lang.String-{}-java.lang.String arg0"));
         assertThat(pd.getTypeClass(), equalTo(String.class));
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java
index 28cd785e..9ec68a68 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java
@@ -5,15 +5,14 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+import java.lang.reflect.Field;
 import org.hyperledger.fabric.contract.metadata.TypeSchema;
 import org.hyperledger.fabric.contract.routing.impl.PropertyDefinitionImpl;
 import org.junit.jupiter.api.Test;
 
-import java.lang.reflect.Field;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-
 public class PropertyDefinitionTest {
     @Test
     public void constructor() throws NoSuchMethodException, SecurityException {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java
index 1096ceac..428a9483 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java
@@ -5,6 +5,14 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
 import org.hyperledger.fabric.contract.Context;
 import org.hyperledger.fabric.contract.ContractInterface;
 import org.hyperledger.fabric.contract.ContractRuntimeException;
@@ -16,32 +24,18 @@
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.mock;
-
 public class TxFunctionTest {
     @Contract()
     class TestObject implements ContractInterface {
 
         @Transaction()
-        public void testMethod1(final Context ctx) {
-
-        }
+        public void testMethod1(final Context ctx) {}
 
         @Transaction()
-        public void testMethod2(final Context ctx, @Property(schema = {"a", "b"}) final int arg) {
-
-        }
+        public void testMethod2(final Context ctx, @Property(schema = {"a", "b"}) final int arg) {}
 
         @Transaction()
-        public void wibble(final String arg1) {
-
-        }
+        public void wibble(final String arg1) {}
     }
 
     @Test
@@ -50,7 +44,8 @@ public void constructor() throws NoSuchMethodException, SecurityException {
         final ContractDefinition cd = mock(ContractDefinition.class);
         Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class));
 
-        final TxFunction txfn = new TxFunctionImpl(test.getClass().getMethod("testMethod1", new Class[] {Context.class}), cd);
+        final TxFunction txfn =
+                new TxFunctionImpl(test.getClass().getMethod("testMethod1", new Class[] {Context.class}), cd);
         final String name = txfn.getName();
         assertEquals(name, "testMethod1");
 
@@ -62,7 +57,8 @@ public void property() throws NoSuchMethodException, SecurityException {
         final TestObject test = new TestObject();
         final ContractDefinition cd = mock(ContractDefinition.class);
         Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class));
-        final TxFunction txfn = new TxFunctionImpl(test.getClass().getMethod("testMethod2", new Class[] {Context.class, int.class}), cd);
+        final TxFunction txfn = new TxFunctionImpl(
+                test.getClass().getMethod("testMethod2", new Class[] {Context.class, int.class}), cd);
         final String name = txfn.getName();
         assertEquals(name, "testMethod2");
 
@@ -76,7 +72,6 @@ public void property() throws NoSuchMethodException, SecurityException {
         final TypeSchema rts = txfn.getReturnSchema();
         System.out.println(ts);
         assertEquals(ts, rts);
-
     }
 
     @Test
@@ -88,5 +83,4 @@ public void invaldtxfn() throws NoSuchMethodException, SecurityException {
         assertThatThrownBy(() -> new TxFunctionImpl(test.getClass().getMethod("wibble", String.class), cd))
                 .isInstanceOf(ContractRuntimeException.class);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java
index 0fc5f419..16c59648 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java
@@ -5,15 +5,14 @@
  */
 package org.hyperledger.fabric.contract.routing;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+import java.util.Collection;
 import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl;
 import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl;
 import org.junit.jupiter.api.Test;
 
-import java.util.Collection;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-
 public class TypeRegistryTest {
     @Test
     public void addDataType() {
@@ -45,5 +44,4 @@ public void getAllDataTypes() {
         final Collection c = tr.getAllDataTypes();
         assertThat(c.size(), equalTo(3));
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java
index 2286435d..489919d4 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java
@@ -5,7 +5,15 @@
  */
 package org.hyperledger.fabric.contract.simplepath;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION;
+
 import com.google.protobuf.ByteString;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 import org.hyperledger.fabric.contract.ContractRouter;
 import org.hyperledger.fabric.protos.peer.ChaincodeInput;
 import org.hyperledger.fabric.protos.peer.ChaincodeInput.Builder;
@@ -22,15 +30,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION;
-
 @ExtendWith(SystemStubsExtension.class)
 public final class ContractSimplePathTest {
     @SystemStub
@@ -73,7 +72,8 @@ public ChaincodeMessage newInvokeFn(final String[] args) {
             invokePayload.addArgs(ByteString.copyFromUtf8(arg));
         }
 
-        return MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload.build().toByteString(), null);
+        return MessageUtil.newEventMessage(
+                TRANSACTION, "testChannel", "0", invokePayload.build().toByteString(), null);
     }
 
     public String getLastReturnString() throws Exception {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java
index daa3a511..42800291 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java
@@ -68,5 +68,4 @@ public void getOrganizationCollection() {
         final Collection collection2 = ledger.getOrganizationCollection("org1");
         assertThat(collection2).isNotSameAs(collection);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java
index b57c9e5c..eb562ade 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java
@@ -10,7 +10,6 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Properties;
-
 import org.hyperledger.fabric.metrics.impl.DefaultProvider;
 import org.hyperledger.fabric.metrics.impl.NullProvider;
 import org.junit.jupiter.api.DisplayName;
@@ -21,18 +20,13 @@ public class MetricsTest {
 
     public static class TestProvider implements MetricsProvider {
 
-        public TestProvider() {
-
-        }
+        public TestProvider() {}
 
         @Override
-        public void setTaskMetricsCollector(final TaskMetricsCollector taskService) {
-        }
+        public void setTaskMetricsCollector(final TaskMetricsCollector taskService) {}
 
         @Override
-        public void initialize(final Properties props) {
-        }
-
+        public void initialize(final Properties props) {}
     }
 
     @Nested
@@ -51,9 +45,12 @@ public void metricsEnabledUnknownProvider() {
             props.put("CHAINCODE_METRICS_PROVIDER", "org.example.metrics.provider");
             props.put("CHAINCODE_METRICS_ENABLED", "true");
 
-            assertThrows(RuntimeException.class, () -> {
-                final MetricsProvider provider = Metrics.initialize(props);
-            }, "Unable to start metrics");
+            assertThrows(
+                    RuntimeException.class,
+                    () -> {
+                        final MetricsProvider provider = Metrics.initialize(props);
+                    },
+                    "Unable to start metrics");
         }
 
         @Test
@@ -63,7 +60,6 @@ public void metricsNoProvider() {
 
             final MetricsProvider provider = Metrics.initialize(props);
             assertTrue(provider instanceof DefaultProvider);
-
         }
 
         @Test
@@ -75,7 +71,5 @@ public void metricsValid() {
 
             assertThat(provider).isExactlyInstanceOf(MetricsTest.TestProvider.class);
         }
-
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java
index 985e4be4..0da931aa 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java
@@ -13,7 +13,6 @@
 import java.util.logging.LogManager;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
-
 import org.hyperledger.fabric.metrics.MetricsProvider;
 import org.hyperledger.fabric.metrics.TaskMetricsCollector;
 import org.junit.jupiter.api.Test;
@@ -84,10 +83,11 @@ public int getActiveCount() {
             Mockito.verify(mockHandler, Mockito.atLeast(1)).publish(argumentCaptor.capture());
             LogRecord lr = argumentCaptor.getValue();
             String msg = lr.getMessage();
-            assertThat(msg).contains("{ \"active_count\":0 , \"pool_size\":0 , \"core_pool_size\":0 , \"current_task_count\":0 , \"current_queue_depth\":0 ");
+            assertThat(msg)
+                    .contains(
+                            "{ \"active_count\":0 , \"pool_size\":0 , \"core_pool_size\":0 , \"current_task_count\":0 , \"current_queue_depth\":0 ");
         } finally {
             perfLogger.setLevel(original);
         }
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java
index 6fd7ef03..7cd97a1a 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java
@@ -6,8 +6,19 @@
 
 package org.hyperledger.fabric.shim;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
 import io.grpc.ManagedChannelBuilder;
 import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Properties;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.shim.chaincode.EmptyChaincode;
@@ -22,18 +33,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.Properties;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
 @ExtendWith(SystemStubsExtension.class)
 public class ChaincodeBaseTest {
     @SystemStub
@@ -42,81 +41,115 @@ public class ChaincodeBaseTest {
     @Test
     public void testNewSuccessResponseEmpty() {
         final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse();
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
         assertThat(response.getMessage()).as("Response message").isNull();
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
 
     @Test
     public void testNewSuccessResponseWithMessage() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message");
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newSuccessResponse("Simple message");
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message");
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
 
     @Test
     public void testNewSuccessResponseWithPayload() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset()));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
         assertThat(response.getMessage()).as("Response message").isNull();
-        assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getPayload())
+                .as("Response payload")
+                .isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
     }
 
     @Test
     public void testNewSuccessResponseWithMessageAndPayload() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message",
-                "Simple payload".getBytes(Charset.defaultCharset()));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newSuccessResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.SUCCESS);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message");
-        assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getPayload())
+                .as("Response payload")
+                .isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
     }
 
     @Test
     public void testNewErrorResponseEmpty() {
         final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse();
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isNull();
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
 
     @Test
     public void testNewErrorResponseWithMessage() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message");
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newErrorResponse("Simple message");
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message");
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
 
     @Test
     public void testNewErrorResponseWithPayload() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset()));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isNull();
-        assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getPayload())
+                .as("Response payload")
+                .isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
     }
 
     @Test
     public void testNewErrorResponseWithMessageAndPayload() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message",
-                "Simple payload".getBytes(Charset.defaultCharset()));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newErrorResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Simple message");
-        assertThat(response.getPayload()).as("Response payload").isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
+        assertThat(response.getPayload())
+                .as("Response payload")
+                .isEqualTo("Simple payload".getBytes(Charset.defaultCharset()));
     }
 
     @Test
     public void testNewErrorResponseWithException() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new Exception("Simple exception"));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newErrorResponse(new Exception("Simple exception"));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Unexpected error");
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
 
     @Test
     public void testNewErrorResponseWithChaincodeException() {
-        final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new ChaincodeException("Chaincode exception"));
-        assertThat(response.getStatus()).as("Response status").isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
+        final org.hyperledger.fabric.shim.Chaincode.Response response =
+                ResponseUtils.newErrorResponse(new ChaincodeException("Chaincode exception"));
+        assertThat(response.getStatus())
+                .as("Response status")
+                .isEqualTo(org.hyperledger.fabric.shim.Chaincode.Response.Status.INTERNAL_SERVER_ERROR);
         assertThat(response.getMessage()).as("Response message").isEqualTo("Chaincode exception");
         assertThat(response.getPayload()).as("Response payload").isNull();
     }
@@ -273,11 +306,15 @@ public void testStartFailsWithoutValidOptions() {
         String msg = lr.getMessage();
 
         assertThat(msg).doesNotContain("java.lang.NullPointerException");
-        assertThat(msg).contains(
-            "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable.");
+        assertThat(msg)
+                .contains(
+                        "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable.");
     }
 
-    public static void setLogLevelForChaincode(final EnvironmentVariables environmentVariables, final ChaincodeBase cb, final String shimLevel,
+    public static void setLogLevelForChaincode(
+            final EnvironmentVariables environmentVariables,
+            final ChaincodeBase cb,
+            final String shimLevel,
             final String chaincodeLevel) {
         environmentVariables.set(ChaincodeBase.CORE_CHAINCODE_LOGGING_SHIM, shimLevel);
         environmentVariables.set(ChaincodeBase.CORE_CHAINCODE_LOGGING_LEVEL, chaincodeLevel);
@@ -302,19 +339,13 @@ public void connectChaincodeBase() throws IOException {
 
         cb.connectToPeer(new StreamObserver() {
             @Override
-            public void onNext(final ChaincodeMessage value) {
-
-            }
+            public void onNext(final ChaincodeMessage value) {}
 
             @Override
-            public void onError(final Throwable t) {
-
-            }
+            public void onError(final Throwable t) {}
 
             @Override
-            public void onCompleted() {
-
-            }
+            public void onCompleted() {}
         });
 
         environmentVariables.remove("CORE_CHAINCODE_ID_NAME");
@@ -324,12 +355,9 @@ public void onCompleted() {
 
     @Test
     public void connectChaincodeBaseNull() {
-        Assertions.assertThrows(
-                IllegalArgumentException.class,
-                () -> {
-                    final ChaincodeBase cb = new EmptyChaincode();
-                    cb.connectToPeer(null);
-                }
-        );
+        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+            final ChaincodeBase cb = new EmptyChaincode();
+            cb.connectToPeer(null);
+        });
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java
index 8b52bbfd..3ab40706 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java
@@ -5,6 +5,8 @@
  */
 package org.hyperledger.fabric.shim;
 
+import java.io.IOException;
+import java.net.URISyntaxException;
 import org.hyperledger.fabric.contract.ContractRouter;
 import org.hyperledger.fabric.shim.chaincode.EmptyChaincode;
 import org.junit.jupiter.api.AfterEach;
@@ -15,9 +17,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-
 @ExtendWith(SystemStubsExtension.class)
 class ChaincodeServerImplTest {
     @SystemStub
@@ -49,7 +48,8 @@ void clearEnv() {
     void init() {
         try {
             final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -60,7 +60,8 @@ void initEnvNotSet() {
         clearEnv();
         try {
             final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -69,16 +70,18 @@ void initEnvNotSet() {
     @Test
     void startAndStop() {
         try {
-            final ChaincodeBase chaincodeBase = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            final ChaincodeBase chaincodeBase =
+                    new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
             new Thread(() -> {
-                try {
-                    chaincodeServer.start();
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-            ).start();
+                        try {
+                            chaincodeServer.start();
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    })
+                    .start();
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java
index 37b8db4d..ccf3185a 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java
@@ -9,7 +9,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeEvent;
 import org.hyperledger.fabric.protos.peer.SignedProposal;
 import org.hyperledger.fabric.shim.Chaincode.Response;
@@ -102,8 +101,8 @@ public QueryResultsIterator getStateByRange(final String startKey, fin
         }
 
         @Override
-        public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(final String startKey, final String endKey, final int pageSize,
-                final String bookmark) {
+        public QueryResultsIteratorWithMetadata getStateByRangeWithPagination(
+                final String startKey, final String endKey, final int pageSize, final String bookmark) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -115,7 +114,8 @@ public QueryResultsIterator getStateByPartialCompositeKey(final String
         }
 
         @Override
-        public QueryResultsIterator getStateByPartialCompositeKey(final String objectType, final String... attributes) {
+        public QueryResultsIterator getStateByPartialCompositeKey(
+                final String objectType, final String... attributes) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -127,8 +127,8 @@ public QueryResultsIterator getStateByPartialCompositeKey(final Compos
         }
 
         @Override
-        public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(final CompositeKey compositeKey, final int pageSize,
-                final String bookmark) {
+        public QueryResultsIteratorWithMetadata getStateByPartialCompositeKeyWithPagination(
+                final CompositeKey compositeKey, final int pageSize, final String bookmark) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -152,7 +152,8 @@ public QueryResultsIterator getQueryResult(final String query) {
         }
 
         @Override
-        public QueryResultsIteratorWithMetadata getQueryResultWithPagination(final String query, final int pageSize, final String bookmark) {
+        public QueryResultsIteratorWithMetadata getQueryResultWithPagination(
+                final String query, final int pageSize, final String bookmark) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -205,26 +206,29 @@ public void purgePrivateData(final String collection, final String key) {
         }
 
         @Override
-        public QueryResultsIterator getPrivateDataByRange(final String collection, final String startKey, final String endKey) {
+        public QueryResultsIterator getPrivateDataByRange(
+                final String collection, final String startKey, final String endKey) {
             // TODO Auto-generated method stub
             return null;
         }
 
         @Override
-        public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final String compositeKey) {
+        public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+                final String collection, final String compositeKey) {
             // TODO Auto-generated method stub
             return null;
         }
 
         @Override
-        public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final CompositeKey compositeKey) {
+        public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+                final String collection, final CompositeKey compositeKey) {
             // TODO Auto-generated method stub
             return null;
         }
 
         @Override
-        public QueryResultsIterator getPrivateDataByPartialCompositeKey(final String collection, final String objectType,
-                final String... attributes) {
+        public QueryResultsIterator getPrivateDataByPartialCompositeKey(
+                final String collection, final String objectType, final String... attributes) {
             // TODO Auto-generated method stub
             return null;
         }
@@ -282,7 +286,6 @@ public String getMspId() {
             // TODO Auto-generated method stub
             return null;
         }
-
     }
 
     @Test
@@ -300,5 +303,4 @@ public void testDefaultMethods() {
         stub.getPrivateDataUTF8("collection", "key");
         stub.putStringState("key", "value");
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java
index 800ec670..7b70b388 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java
@@ -5,17 +5,17 @@
  */
 package org.hyperledger.fabric.shim;
 
-import org.junit.jupiter.api.Test;
-
-import java.nio.charset.StandardCharsets;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+
 public class ChaincodeTest {
     @Test
     public void testResponse() {
-        final Chaincode.Response resp = new Chaincode.Response(Chaincode.Response.Status.SUCCESS, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
+        final Chaincode.Response resp = new Chaincode.Response(
+                Chaincode.Response.Status.SUCCESS, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
         assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus());
         assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage());
         assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload());
@@ -23,7 +23,8 @@ public void testResponse() {
 
     @Test
     public void testResponseWithCode() {
-        Chaincode.Response resp = new Chaincode.Response(200, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
+        Chaincode.Response resp =
+                new Chaincode.Response(200, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
         assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus());
         assertThat(200).as("Incorrect status").isEqualTo(resp.getStatusCode());
         assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage());
@@ -34,8 +35,11 @@ public void testResponseWithCode() {
         assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage());
         assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload());
 
-        resp = new Chaincode.Response(Chaincode.Response.Status.ERROR_THRESHOLD, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
-        assertThat(Chaincode.Response.Status.ERROR_THRESHOLD).as("Incorrect status").isEqualTo(resp.getStatus());
+        resp = new Chaincode.Response(
+                Chaincode.Response.Status.ERROR_THRESHOLD, "No message", "no payload".getBytes(StandardCharsets.UTF_8));
+        assertThat(Chaincode.Response.Status.ERROR_THRESHOLD)
+                .as("Incorrect status")
+                .isEqualTo(resp.getStatus());
         assertThat(400).as("Incorrect status").isEqualTo(resp.getStatusCode());
         assertThat("No message").as("Incorrect message").isEqualTo(resp.getMessage());
         assertThat("no payload").as("Incorrect payload").isEqualTo(resp.getStringPayload());
@@ -43,11 +47,16 @@ public void testResponseWithCode() {
 
     @Test
     public void testStatus() {
-        assertThat(Chaincode.Response.Status.SUCCESS).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(200));
-        assertThat(Chaincode.Response.Status.ERROR_THRESHOLD).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(400));
-        assertThat(Chaincode.Response.Status.INTERNAL_SERVER_ERROR).as("Wrong status").isEqualTo(Chaincode.Response.Status.forCode(500));
-
-        assertThatThrownBy(() -> Chaincode.Response.Status.forCode(501))
-                .isInstanceOf(IllegalArgumentException.class);
+        assertThat(Chaincode.Response.Status.SUCCESS)
+                .as("Wrong status")
+                .isEqualTo(Chaincode.Response.Status.forCode(200));
+        assertThat(Chaincode.Response.Status.ERROR_THRESHOLD)
+                .as("Wrong status")
+                .isEqualTo(Chaincode.Response.Status.forCode(400));
+        assertThat(Chaincode.Response.Status.INTERNAL_SERVER_ERROR)
+                .as("Wrong status")
+                .isEqualTo(Chaincode.Response.Status.forCode(500));
+
+        assertThatThrownBy(() -> Chaincode.Response.Status.forCode(501)).isInstanceOf(IllegalArgumentException.class);
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java
index 5e7108f3..d3832502 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java
@@ -5,8 +5,25 @@
  */
 package org.hyperledger.fabric.shim;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INVOKE_CHAINCODE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import com.google.protobuf.ByteString;
 import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeInput;
@@ -24,27 +41,10 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.Properties;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.stream.Collectors.toList;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INVOKE_CHAINCODE;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 @ExtendWith(SystemStubsExtension.class)
 class ChatChaincodeWithPeerTest {
     private static final String TEST_CHANNEL = "testChannel";
+
     @SystemStub
     private final EnvironmentVariables environmentVariables = new EnvironmentVariables();
 
@@ -75,8 +75,7 @@ void initNull() throws IOException {
                 () -> {
                     ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(null);
                 },
-                "chaincodeBase can't be null"
-        );
+                "chaincodeBase can't be null");
     }
 
     @Test
@@ -112,21 +111,17 @@ void initEmptyId() throws IOException {
                     Traces.initialize(props);
                     ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
                 },
-                "chaincode id not set, set env 'CORE_CHAINCODE_ID_NAME', for example 'CORE_CHAINCODE_ID_NAME=mycc'"
-        );
+                "chaincode id not set, set env 'CORE_CHAINCODE_ID_NAME', for example 'CORE_CHAINCODE_ID_NAME=mycc'");
     }
 
     @Test
     void connectEnvNotSet() throws IOException {
         clearEnv();
 
-        Assertions.assertThrows(
-                IllegalArgumentException.class,
-                () -> {
-                    ChaincodeBase chaincodeBase = new EmptyChaincode();
-                    ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
-                }
-        );
+        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+            ChaincodeBase chaincodeBase = new EmptyChaincode();
+            ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
+        });
     }
 
     @Test
@@ -154,41 +149,50 @@ void connectAndReceiveRegister() throws IOException {
         Metrics.initialize(props);
 
         ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
-        final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver() {
-            @Override
-            public void onNext(final ChaincodeMessage value) {
-                assertEquals(ChaincodeMessage.Type.REGISTER, value.getType());
-                assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8());
-            }
-
-            @Override
-            public void onError(final Throwable t) {
-                assertNull(t);
-            }
-
-            @Override
-            public void onCompleted() {
-            }
-        });
+        final StreamObserver connect =
+                chatChaincodeWithPeer.connect(new StreamObserver() {
+                    @Override
+                    public void onNext(final ChaincodeMessage value) {
+                        assertEquals(ChaincodeMessage.Type.REGISTER, value.getType());
+                        assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8());
+                    }
+
+                    @Override
+                    public void onError(final Throwable t) {
+                        assertNull(t);
+                    }
+
+                    @Override
+                    public void onCompleted() {}
+                });
         assertNotNull(connect);
 
         final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("")).build()
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
                 .toByteString();
         final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, TEST_CHANNEL, "0", payload, null);
         connect.onNext(initMsg);
 
         try {
-            final List args = Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList());
+            final List args =
+                    Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList());
             final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder()
-                    .setChaincodeId(ChaincodeID.newBuilder().setName(chaincodeBase.getId()).build())
-                    .setInput(ChaincodeInput.newBuilder().addAllArgs(args.stream().map(ByteString::copyFrom)
-                            .collect(Collectors.toList())).build()).build()
+                    .setChaincodeId(ChaincodeID.newBuilder()
+                            .setName(chaincodeBase.getId())
+                            .build())
+                    .setInput(ChaincodeInput.newBuilder()
+                            .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList()))
+                            .build())
+                    .build()
                     .toByteString();
 
             final ChaincodeMessage invokeChaincodeMessage = ChaincodeMessage.newBuilder()
-                    .setType(INVOKE_CHAINCODE).setChannelId(TEST_CHANNEL)
-                    .setTxid("1").setPayload(invocationSpecPayload).build();
+                    .setType(INVOKE_CHAINCODE)
+                    .setChannelId(TEST_CHANNEL)
+                    .setTxid("1")
+                    .setPayload(invocationSpecPayload)
+                    .build();
             connect.onNext(invokeChaincodeMessage);
             System.out.println(invokeChaincodeMessage.getPayload().toStringUtf8());
         } catch (Exception e) {
@@ -196,16 +200,24 @@ public void onCompleted() {
         }
 
         try {
-            final List args = Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList());
+            final List args =
+                    Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList());
             final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder()
-                    .setChaincodeId(ChaincodeID.newBuilder().setName(chaincodeBase.getId()).build())
-                    .setInput(ChaincodeInput.newBuilder().addAllArgs(args.stream().map(ByteString::copyFrom)
-                            .collect(Collectors.toList())).build()).build()
+                    .setChaincodeId(ChaincodeID.newBuilder()
+                            .setName(chaincodeBase.getId())
+                            .build())
+                    .setInput(ChaincodeInput.newBuilder()
+                            .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList()))
+                            .build())
+                    .build()
                     .toByteString();
 
             final ChaincodeMessage invokeChaincodeMessage = ChaincodeMessage.newBuilder()
-                    .setType(INVOKE_CHAINCODE).setChannelId(TEST_CHANNEL)
-                    .setTxid("2").setPayload(invocationSpecPayload).build();
+                    .setType(INVOKE_CHAINCODE)
+                    .setChannelId(TEST_CHANNEL)
+                    .setTxid("2")
+                    .setPayload(invocationSpecPayload)
+                    .build();
             connect.onNext(invokeChaincodeMessage);
             System.out.println(invokeChaincodeMessage.getPayload().toStringUtf8());
         } catch (Exception e) {
@@ -225,22 +237,22 @@ void connectAndReceiveRegisterComplete() throws IOException {
         Metrics.initialize(props);
 
         ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
-        final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver() {
-            @Override
-            public void onNext(final ChaincodeMessage value) {
-                assertEquals(ChaincodeMessage.Type.REGISTER, value.getType());
-                assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8());
-            }
-
-            @Override
-            public void onError(final Throwable t) {
-                assertNull(t);
-            }
-
-            @Override
-            public void onCompleted() {
-            }
-        });
+        final StreamObserver connect =
+                chatChaincodeWithPeer.connect(new StreamObserver() {
+                    @Override
+                    public void onNext(final ChaincodeMessage value) {
+                        assertEquals(ChaincodeMessage.Type.REGISTER, value.getType());
+                        assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8());
+                    }
+
+                    @Override
+                    public void onError(final Throwable t) {
+                        assertNull(t);
+                    }
+
+                    @Override
+                    public void onCompleted() {}
+                });
         connect.onCompleted();
     }
 
@@ -256,19 +268,17 @@ void connectAndReceiveRegisterException() throws IOException {
         Metrics.initialize(props);
 
         ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase);
-        final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver() {
-            @Override
-            public void onNext(final ChaincodeMessage value) {
-            }
+        final StreamObserver connect =
+                chatChaincodeWithPeer.connect(new StreamObserver() {
+                    @Override
+                    public void onNext(final ChaincodeMessage value) {}
 
-            @Override
-            public void onError(final Throwable t) {
-            }
+                    @Override
+                    public void onError(final Throwable t) {}
 
-            @Override
-            public void onCompleted() {
-            }
-        });
+                    @Override
+                    public void onCompleted() {}
+                });
         connect.onError(new Exception("some_error"));
     }
 
@@ -287,24 +297,21 @@ void connectOnCompletedException() throws IOException {
 
         Assertions.assertDoesNotThrow(
                 () -> {
-                    final StreamObserver connect = chatChaincodeWithPeer
-                            .connect(new StreamObserver() {
-                        @Override
-                        public void onNext(final ChaincodeMessage value) {
-                        }
-
-                        @Override
-                        public void onError(final Throwable t) {
-                        }
-
-                        @Override
-                        public void onCompleted() {
-                            throw new RuntimeException("some_error");
-                        }
-                    });
+                    final StreamObserver connect =
+                            chatChaincodeWithPeer.connect(new StreamObserver() {
+                                @Override
+                                public void onNext(final ChaincodeMessage value) {}
+
+                                @Override
+                                public void onError(final Throwable t) {}
+
+                                @Override
+                                public void onCompleted() {
+                                    throw new RuntimeException("some_error");
+                                }
+                            });
                 },
-                "some_error"
-        );
+                "some_error");
     }
 
     @Test
@@ -318,16 +325,13 @@ void testMockChaincodeBase() throws IOException {
 
         assertNull(chatChaincodeWithPeer.connect(new StreamObserver() {
             @Override
-            public void onNext(final ChaincodeMessage value) {
-            }
+            public void onNext(final ChaincodeMessage value) {}
 
             @Override
-            public void onError(final Throwable t) {
-            }
+            public void onError(final Throwable t) {}
 
             @Override
-            public void onCompleted() {
-            }
+            public void onCompleted() {}
         }));
     }
 
@@ -344,8 +348,7 @@ void testMockChaincodeBaseThrowIOException() throws IOException {
 
         assertNull(chatChaincodeWithPeer.connect(new StreamObserver() {
             @Override
-            public void onNext(final ChaincodeMessage value) {
-            }
+            public void onNext(final ChaincodeMessage value) {}
 
             @Override
             public void onError(final Throwable t) {
@@ -353,8 +356,7 @@ public void onError(final Throwable t) {
             }
 
             @Override
-            public void onCompleted() {
-            }
+            public void onCompleted() {}
         }));
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java
index c14163e7..87e8474e 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java
@@ -5,6 +5,9 @@
  */
 package org.hyperledger.fabric.shim;
 
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Properties;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.shim.chaincode.EmptyChaincode;
 import org.hyperledger.fabric.traces.Traces;
@@ -17,10 +20,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Properties;
-
 @ExtendWith(SystemStubsExtension.class)
 class NettyGrpcServerTest {
     @SystemStub
@@ -53,7 +52,8 @@ void initNoTls() {
         try {
             final ChaincodeBase chaincodeBase = new EmptyChaincode();
             chaincodeBase.processEnvironmentOptions();
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
         } catch (IOException | URISyntaxException e) {
             e.printStackTrace();
         }
@@ -61,100 +61,138 @@ void initNoTls() {
 
     @Test
     void validationNoChaincodeServerPropertiesg() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, null);
-        }, "ChaincodeServerProperties must be specified");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, null);
+                },
+                "ChaincodeServerProperties must be specified");
     }
 
     @Test
     void validationPortChaincodeServer() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setServerAddress(null);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getServerAddress() must be set");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setServerAddress(null);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getServerAddress() must be set");
     }
 
     @Test
     void validationKeepAliveTimeMinutes() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setKeepAliveTimeMinutes(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getKeepAliveTimeMinutes() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setKeepAliveTimeMinutes(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getKeepAliveTimeMinutes() must be more then 0");
     }
 
     @Test
     void validationKeepAliveTimeoutSeconds() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setKeepAliveTimeoutSeconds(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getKeepAliveTimeoutSeconds() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setKeepAliveTimeoutSeconds(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getKeepAliveTimeoutSeconds() must be more then 0");
     }
 
     @Test
     void validationPermitKeepAliveTimeMinutes() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setPermitKeepAliveTimeMinutes(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getPermitKeepAliveTimeMinutes() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setPermitKeepAliveTimeMinutes(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getPermitKeepAliveTimeMinutes() must be more then 0");
     }
 
     @Test
     void validationMaxConnectionAgeSeconds() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setMaxConnectionAgeSeconds(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getMaxConnectionAgeSeconds() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setMaxConnectionAgeSeconds(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getMaxConnectionAgeSeconds() must be more then 0");
     }
 
     @Test
     void validationMaxInboundMetadataSize() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setMaxInboundMetadataSize(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getMaxInboundMetadataSize() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setMaxInboundMetadataSize(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getMaxInboundMetadataSize() must be more then 0");
     }
 
     @Test
     void validationMaxInboundMessageSize() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setMaxInboundMessageSize(-1);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getMaxInboundMessageSize() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setMaxInboundMessageSize(-1);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getMaxInboundMessageSize() must be more then 0");
     }
 
     @Test
     void validationTlsEnabledButKeyNotSet() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            final ChaincodeBase chaincodeBase = new EmptyChaincode();
-            final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
-            chaincodeServerProperties.setTlsEnabled(true);
-            chaincodeServerProperties.setKeyFile(null);
-            chaincodeServerProperties.setKeyCertChainFile(null);
-            chaincodeServerProperties.setKeyPassword(null);
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
-        }, "ChaincodeServerProperties.getMaxInboundMessageSize() must be more then 0");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    final ChaincodeBase chaincodeBase = new EmptyChaincode();
+                    final ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties();
+                    chaincodeServerProperties.setTlsEnabled(true);
+                    chaincodeServerProperties.setKeyFile(null);
+                    chaincodeServerProperties.setKeyCertChainFile(null);
+                    chaincodeServerProperties.setKeyPassword(null);
+                    ChaincodeServer chaincodeServer =
+                            new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
+                },
+                "ChaincodeServerProperties.getMaxInboundMessageSize() must be more then 0");
     }
 
     @Test
     void initNull() {
-        Assertions.assertThrows(IllegalArgumentException.class, () -> {
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(null, new ChaincodeServerProperties());
-        }, "chaincode must be specified");
+        Assertions.assertThrows(
+                IllegalArgumentException.class,
+                () -> {
+                    ChaincodeServer chaincodeServer = new NettyChaincodeServer(null, new ChaincodeServerProperties());
+                },
+                "chaincode must be specified");
     }
 
     @Test
@@ -163,7 +201,6 @@ void initNullEnvNotSet() {
         Assertions.assertThrows(IllegalArgumentException.class, () -> {
             ChaincodeServer chaincodeServer = new NettyChaincodeServer(null, new ChaincodeServerProperties());
         });
-
     }
 
     @Test
@@ -187,8 +224,8 @@ void initEnvSetPortChaincodeServerAndCoreChaincodeIdName() throws IOException, U
         Metrics.initialize(props);
         Traces.initialize(props);
 
-        ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
-
+        ChaincodeServer chaincodeServer =
+                new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
     }
 
     @Test
@@ -203,14 +240,16 @@ void startAndStopSetCoreChaincodeIdName() {
             Metrics.initialize(props);
             Traces.initialize(props);
 
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
             new Thread(() -> {
-                try {
-                    chaincodeServer.start();
-                } catch (IOException | InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }).start();
+                        try {
+                            chaincodeServer.start();
+                        } catch (IOException | InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    })
+                    .start();
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
@@ -218,7 +257,7 @@ void startAndStopSetCoreChaincodeIdName() {
             }
 
             chaincodeServer.stop();
-        } catch (IOException | URISyntaxException  e) {
+        } catch (IOException | URISyntaxException e) {
             e.printStackTrace();
         }
     }
@@ -228,14 +267,16 @@ void startAndStop() {
         try {
             final ChaincodeBase chaincodeBase = new EmptyChaincode();
             chaincodeBase.processEnvironmentOptions();
-            ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
+            ChaincodeServer chaincodeServer =
+                    new NettyChaincodeServer(chaincodeBase, chaincodeBase.getChaincodeServerConfig());
             new Thread(() -> {
-                try {
-                    chaincodeServer.start();
-                } catch (IOException | InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }).start();
+                        try {
+                            chaincodeServer.start();
+                        } catch (IOException | InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    })
+                    .start();
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
@@ -260,12 +301,13 @@ void startAndStopTlsPassword() {
             chaincodeServerProperties.setKeyPassword("test");
             ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
             new Thread(() -> {
-                try {
-                    chaincodeServer.start();
-                } catch (IOException | InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }).start();
+                        try {
+                            chaincodeServer.start();
+                        } catch (IOException | InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    })
+                    .start();
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
@@ -289,12 +331,13 @@ void startAndStopTlsWithoutPassword() {
             chaincodeServerProperties.setKeyCertChainFile("src/test/resources/client.crt");
             ChaincodeServer chaincodeServer = new NettyChaincodeServer(chaincodeBase, chaincodeServerProperties);
             new Thread(() -> {
-                try {
-                    chaincodeServer.start();
-                } catch (IOException | InterruptedException e) {
-                    e.printStackTrace();
-                }
-            }).start();
+                        try {
+                            chaincodeServer.start();
+                        } catch (IOException | InterruptedException e) {
+                            e.printStackTrace();
+                        }
+                    })
+                    .start();
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java
index d1d23adb..3983ce57 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java
@@ -5,19 +5,20 @@
  */
 package org.hyperledger.fabric.shim.ext.sbe;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.junit.jupiter.api.Test;
+
 public class StateBasedEndorsementTest {
     @Test
     public void testRoleType() {
-        assertThat(StateBasedEndorsement.RoleType.forVal("MEMBER")).isEqualTo(StateBasedEndorsement.RoleType.RoleTypeMember);
-        assertThat(StateBasedEndorsement.RoleType.forVal("PEER")).isEqualTo(StateBasedEndorsement.RoleType.RoleTypePeer);
+        assertThat(StateBasedEndorsement.RoleType.forVal("MEMBER"))
+                .isEqualTo(StateBasedEndorsement.RoleType.RoleTypeMember);
+        assertThat(StateBasedEndorsement.RoleType.forVal("PEER"))
+                .isEqualTo(StateBasedEndorsement.RoleType.RoleTypePeer);
 
         assertThatThrownBy(() -> StateBasedEndorsement.RoleType.forVal("NONEXIST"))
                 .isInstanceOf(IllegalArgumentException.class);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java
index 08896e60..750e24f0 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java
@@ -5,12 +5,11 @@
  */
 package org.hyperledger.fabric.shim.ext.sbe.impl;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
+import org.junit.jupiter.api.Test;
 
 public class StateBasedEndorsementFactoryTest {
     @Test
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java
index 332fa347..195a672e 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java
@@ -5,13 +5,6 @@
  */
 package org.hyperledger.fabric.shim.ext.sbe.impl;
 
-import org.hyperledger.fabric.protos.common.MSPRole.MSPRoleType;
-import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement;
-import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement.RoleType;
-import org.junit.jupiter.api.Test;
-
-import java.util.List;
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.hasSize;
@@ -21,26 +14,38 @@
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.util.List;
+import org.hyperledger.fabric.protos.common.MSPRole.MSPRoleType;
+import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement;
+import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement.RoleType;
+import org.junit.jupiter.api.Test;
+
 public class StateBasedEndorsementImplTest {
 
     @Test
     public void addOrgs() {
         // add an org
-        final StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null);
+        final StateBasedEndorsement ep =
+                StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null);
         ep.addOrgs(RoleType.RoleTypePeer, "Org1");
 
         final byte[] epBytes = ep.policy();
         assertThat(epBytes, is(not(nullValue())));
         assertTrue(epBytes.length > 0);
-        final byte[] expectedEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER).toByteString().toByteArray();
+        final byte[] expectedEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER)
+                .toByteString()
+                .toByteArray();
         assertArrayEquals(expectedEPBytes, epBytes);
     }
 
     @Test
     public void delOrgs() {
 
-        final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER).toByteString().toByteArray();
-        final StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(initEPBytes);
+        final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER)
+                .toByteString()
+                .toByteArray();
+        final StateBasedEndorsement ep =
+                StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(initEPBytes);
         final List listOrgs = ep.listOrgs();
 
         assertThat(listOrgs, is(not(nullValue())));
@@ -54,14 +59,19 @@ public void delOrgs() {
 
         assertThat(epBytes, is(not(nullValue())));
         assertTrue(epBytes.length > 0);
-        final byte[] expectedEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org2", MSPRoleType.MEMBER).toByteString().toByteArray();
+        final byte[] expectedEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org2", MSPRoleType.MEMBER)
+                .toByteString()
+                .toByteArray();
         assertArrayEquals(expectedEPBytes, epBytes);
     }
 
     @Test
     public void listOrgs() {
-        final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER).toByteString().toByteArray();
-        final StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(initEPBytes);
+        final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER)
+                .toByteString()
+                .toByteArray();
+        final StateBasedEndorsement ep =
+                StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(initEPBytes);
         final List listOrgs = ep.listOrgs();
 
         assertThat(listOrgs, is(not(nullValue())));
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java
index 0ebd3c6b..490be49b 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java
@@ -5,7 +5,25 @@
  */
 package org.hyperledger.fabric.shim.fvt;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.COMPLETED;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.RESPONSE;
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
 import com.google.protobuf.ByteString;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import org.hyperledger.fabric.protos.peer.ChaincodeInput;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.Response;
@@ -42,25 +60,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.COMPLETED;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.INIT;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTER;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.RESPONSE;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.TRANSACTION;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
-
 @ExtendWith(SystemStubsExtension.class)
 public final class ChaincodeFVTest {
 
@@ -86,7 +85,7 @@ public void testRegister() throws Exception {
 
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
@@ -109,9 +108,10 @@ public Response invoke(final ChaincodeStub stub) {
         };
 
         final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("")).build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload,
-                null);
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -119,7 +119,7 @@ public Response invoke(final ChaincodeStub stub) {
 
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -153,10 +153,13 @@ public Response invoke(final ChaincodeStub stub) {
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8("init"))
-                .addArgs(ByteString.copyFromUtf8("a")).addArgs(ByteString.copyFromUtf8("100")).build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8("init"))
+                .addArgs(ByteString.copyFromUtf8("a"))
+                .addArgs(ByteString.copyFromUtf8("100"))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -170,7 +173,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -178,14 +181,16 @@ public Response invoke(final ChaincodeStub stub) {
 
         assertThat(server.getLastMessageSend().getType(), is(INIT));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response1"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response1"));
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).addArgs(ByteString.copyFromUtf8("a"))
-                .addArgs(ByteString.copyFromUtf8("10")).build().toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .addArgs(ByteString.copyFromUtf8("a"))
+                .addArgs(ByteString.copyFromUtf8("10"))
+                .build()
+                .toByteString();
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         server.send(invokeMsg);
 
@@ -210,20 +215,22 @@ public Response init(final ChaincodeStub stub) {
             public Response invoke(final ChaincodeStub stub) {
                 final String aKey = stub.getStringArgs().get(1);
                 final byte[] epBytes = stub.getStateValidationParameter(aKey);
-                final StateBasedEndorsement stateBasedEndorsement = StateBasedEndorsementFactory.getInstance()
-                        .newStateBasedEndorsement(epBytes);
+                final StateBasedEndorsement stateBasedEndorsement =
+                        StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(epBytes);
                 assertThat(stateBasedEndorsement.listOrgs().size(), is(2));
                 stub.setStateValidationParameter(aKey, stateBasedEndorsement.policy());
                 return ResponseUtils.newSuccessResponse("OK response2");
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8("init"))
-                .build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8("init"))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
-        final StateBasedEndorsement sbe = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null);
+        final StateBasedEndorsement sbe =
+                StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null);
         sbe.addOrgs(StateBasedEndorsement.RoleType.RoleTypePeer, "Org1");
         sbe.addOrgs(StateBasedEndorsement.RoleType.RoleTypeMember, "Org2");
 
@@ -238,7 +245,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -246,22 +253,22 @@ public Response invoke(final ChaincodeStub stub) {
 
         assertThat(server.getLastMessageSend().getType(), is(INIT));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response1"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response1"));
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).addArgs(ByteString.copyFromUtf8("a")).build()
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .addArgs(ByteString.copyFromUtf8("a"))
+                .build()
                 .toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         server.send(invokeMsg);
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
     }
 
     @Test
@@ -293,16 +300,20 @@ public Response invoke(final ChaincodeStub stub) {
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8(""))
-                .build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).addArgs(ByteString.copyFromUtf8("a"))
-                .addArgs(ByteString.copyFromUtf8("b")).build().toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .addArgs(ByteString.copyFromUtf8("a"))
+                .addArgs(ByteString.copyFromUtf8("b"))
+                .build()
+                .toByteString();
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -318,7 +329,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -329,16 +340,14 @@ public Response invoke(final ChaincodeStub stub) {
         ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
 
         server.send(invokeMsg);
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 9, 30000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
     }
 
     @Test
@@ -367,16 +376,19 @@ public Response invoke(final ChaincodeStub stub) {
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8(""))
-                .build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).addArgs(ByteString.copyFromUtf8("query")).build()
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .addArgs(ByteString.copyFromUtf8("query"))
+                .build()
                 .toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -392,7 +404,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -403,16 +415,14 @@ public Response invoke(final ChaincodeStub stub) {
         ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
 
         server.send(invokeMsg);
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 9, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
     }
 
     @Test
@@ -441,16 +451,19 @@ public Response invoke(final ChaincodeStub stub) {
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8(""))
-                .build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).addArgs(ByteString.copyFromUtf8("key1")).build()
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .addArgs(ByteString.copyFromUtf8("key1"))
+                .build()
                 .toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -462,7 +475,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -473,9 +486,7 @@ public Response invoke(final ChaincodeStub stub) {
         ChaincodeMockPeer.checkScenarioStepEnded(server, 5, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(RESPONSE));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(),
-                is("OK response2"));
-
+        assertThat(Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage(), is("OK response2"));
     }
 
     @Test
@@ -493,15 +504,18 @@ public Response invoke(final ChaincodeStub stub) {
             }
         };
 
-        final ByteString initPayload = ChaincodeInput.newBuilder().addArgs(ByteString.copyFromUtf8(""))
-                .build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0",
-                initPayload, null);
+        final ByteString initPayload = ChaincodeInput.newBuilder()
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", initPayload, null);
 
         final ByteString invokePayload = ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("invoke")).build().toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+                .addArgs(ByteString.copyFromUtf8("invoke"))
+                .build()
+                .toByteString();
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -512,7 +526,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -540,9 +554,10 @@ public Response invoke(final ChaincodeStub stub) {
         };
 
         final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("")).build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload,
-                null);
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -552,7 +567,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
 
         server.send(initMsg);
@@ -560,19 +575,23 @@ public Response invoke(final ChaincodeStub stub) {
 
         assertThat(server.getLastMessageSend().getType(), is(INIT));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        String resp1 = (Response.parseFrom(server.getLastMessageRcvd().getPayload()).getPayload().toStringUtf8());
+        String resp1 = (Response.parseFrom(server.getLastMessageRcvd().getPayload())
+                .getPayload()
+                .toStringUtf8());
         assertThat(resp1, is("Wrong response1"));
 
         final ByteString invokePayload = ChaincodeInput.newBuilder().build().toByteString();
-        final ChaincodeMessage invokeMsg = MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0",
-                invokePayload, null);
+        final ChaincodeMessage invokeMsg =
+                MessageUtil.newEventMessage(TRANSACTION, "testChannel", "0", invokePayload, null);
 
         server.send(invokeMsg);
 
         ChaincodeMockPeer.checkScenarioStepEnded(server, 3, 5000, TimeUnit.MILLISECONDS);
         assertThat(server.getLastMessageSend().getType(), is(TRANSACTION));
         assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED));
-        String resp2 = Response.parseFrom(server.getLastMessageRcvd().getPayload()).getMessage().toString();
+        String resp2 = Response.parseFrom(server.getLastMessageRcvd().getPayload())
+                .getMessage()
+                .toString();
         assertThat(resp2, is("Wrong response2"));
     }
 
@@ -595,9 +614,10 @@ public Response invoke(final ChaincodeStub stub) {
         };
 
         final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder()
-                .addArgs(ByteString.copyFromUtf8("")).build().toByteString();
-        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload,
-                null);
+                .addArgs(ByteString.copyFromUtf8(""))
+                .build()
+                .toByteString();
+        final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, "testChannel", "0", payload, null);
 
         final List scenario = new ArrayList<>();
         scenario.add(new RegisterStep());
@@ -606,7 +626,7 @@ public Response invoke(final ChaincodeStub stub) {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
         ChaincodeMockPeer.checkScenarioStepEnded(server, 1, 5000, TimeUnit.MILLISECONDS);
         server.send(initMsg);
         server.stop();
@@ -624,9 +644,10 @@ public void testChaincodeLogLevel() throws Exception {
         setLogLevel("DEBUG");
         server = ChaincodeMockPeer.startServer(scenario);
 
-        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId" });
+        cb.start(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"});
 
-        assertEquals(Level.FINEST,
+        assertEquals(
+                Level.FINEST,
                 Logger.getLogger(cb.getClass().getPackage().getName()).getLevel(),
                 "Wrong debug level for " + cb.getClass().getPackage().getName());
     }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java
index 97da696b..2a7c561e 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java
@@ -6,16 +6,15 @@
 
 package org.hyperledger.fabric.shim.impl;
 
-import org.hyperledger.fabric.protos.peer.ChaincodeID;
+import com.google.protobuf.ByteString;
 import org.hyperledger.fabric.protos.peer.ChaincodeEvent;
+import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type;
 import org.hyperledger.fabric.shim.Chaincode.Response;
 import org.hyperledger.fabric.shim.ResponseUtils;
 import org.junit.jupiter.api.Test;
 
-import com.google.protobuf.ByteString;
-
 class ChaincodeMessageFactoryTest {
 
     private final String txId = "txid";
@@ -29,7 +28,8 @@ class ChaincodeMessageFactoryTest {
     private ChaincodeEvent event;
     private final Response response = ResponseUtils.newSuccessResponse();
     private final ByteString payload = ByteString.copyFromUtf8("Hello");
-    private final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("test").build();
+    private final ChaincodeID chaincodeId =
+            ChaincodeID.newBuilder().setName("test").build();
     private final Type type = ChaincodeMessage.Type.COMPLETED;
 
     @Test
@@ -90,5 +90,4 @@ void testNewEventMessageTypeStringStringByteString() {
         ChaincodeMessageFactory.newEventMessage(type, channelId, txId, payload);
         ChaincodeMessageFactory.newEventMessage(type, channelId, txId, payload, event);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java
index c3cf24d8..2bdf9c87 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java
@@ -5,8 +5,12 @@
  */
 package org.hyperledger.fabric.shim.impl;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
 import io.grpc.ManagedChannelBuilder;
 import io.grpc.stub.StreamObserver;
+import java.io.IOException;
+import java.util.Properties;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
@@ -19,11 +23,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.util.Properties;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
 @ExtendWith(SystemStubsExtension.class)
 class ChaincodeSupportClientTest {
     @SystemStub
@@ -44,15 +43,18 @@ void testStartInvocationTaskManagerAndRequestObserverNull() throws IOException {
         ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(managedChannelBuilder);
 
         assertThatThrownBy(
-                () -> {
-                    final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
-                    final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
-
-                    final StreamObserver requestObserver = null;
-                    chaincodeSupportClient.start(itm, requestObserver);
-                },
-                "StreamObserver 'requestObserver' for chat with peer can't be null"
-        ).isInstanceOf(IOException.class);
+                        () -> {
+                            final ChaincodeID chaincodeId = ChaincodeID.newBuilder()
+                                    .setName("chaincodeIdNumber12345")
+                                    .build();
+                            final InvocationTaskManager itm =
+                                    InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
+
+                            final StreamObserver requestObserver = null;
+                            chaincodeSupportClient.start(itm, requestObserver);
+                        },
+                        "StreamObserver 'requestObserver' for chat with peer can't be null")
+                .isInstanceOf(IOException.class);
         environmentVariables.remove("CORE_CHAINCODE_ID_NAME");
     }
 
@@ -71,26 +73,20 @@ void testStartInvocationTaskManagerNullAndRequestObserver() throws IOException {
         ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(managedChannelBuilder);
 
         assertThatThrownBy(
-                () -> {
-                    chaincodeSupportClient.start(null, new StreamObserver() {
-                        @Override
-                        public void onNext(final ChaincodeMessage value) {
-
-                        }
-
-                        @Override
-                        public void onError(final Throwable t) {
-
-                        }
-
-                        @Override
-                        public void onCompleted() {
-
-                        }
-                    });
-                },
-                "InvocationTaskManager 'itm' can't be null"
-        ).isInstanceOf(IOException.class);
+                        () -> {
+                            chaincodeSupportClient.start(null, new StreamObserver() {
+                                @Override
+                                public void onNext(final ChaincodeMessage value) {}
+
+                                @Override
+                                public void onError(final Throwable t) {}
+
+                                @Override
+                                public void onCompleted() {}
+                            });
+                        },
+                        "InvocationTaskManager 'itm' can't be null")
+                .isInstanceOf(IOException.class);
         environmentVariables.remove("CORE_CHAINCODE_ID_NAME");
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java
index 6ef01199..fd51e718 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java
@@ -5,8 +5,13 @@
  */
 package org.hyperledger.fabric.shim.impl;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import com.google.protobuf.ByteString;
 import io.grpc.ManagedChannelBuilder;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.function.Consumer;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
@@ -22,12 +27,6 @@
 import uk.org.webcompere.systemstubs.jupiter.SystemStub;
 import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension;
 
-import java.io.IOException;
-import java.util.Properties;
-import java.util.function.Consumer;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 @ExtendWith(SystemStubsExtension.class)
 class InnvocationTaskManagerTest {
     @SystemStub
@@ -64,7 +63,8 @@ void getManager() throws IOException {
         Traces.initialize(props);
         Metrics.initialize(props);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
     }
 
@@ -80,24 +80,25 @@ void getManagerChaincodeIDNull() throws IOException {
         Traces.initialize(props);
 
         Assertions.assertThrows(
-                IllegalArgumentException.class, () -> {
+                IllegalArgumentException.class,
+                () -> {
                     final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, null);
                 },
-                "chaincodeId can't be null"
-        );
+                "chaincodeId can't be null");
     }
 
     @Test
     void getManagerChaincodeBaseNull() throws IOException {
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
 
         Assertions.assertThrows(
-                IllegalArgumentException.class, () -> {
+                IllegalArgumentException.class,
+                () -> {
                     final InvocationTaskManager itm = InvocationTaskManager.getManager(null, chaincodeId);
                 },
-                "chaincode is null"
-        );
+                "chaincode is null");
     }
 
     @Test
@@ -111,13 +112,12 @@ void onChaincodeMessage() throws IOException {
         Metrics.initialize(props);
         Traces.initialize(props);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
 
         Assertions.assertThrows(
-                IllegalArgumentException.class, () -> itm.onChaincodeMessage(null),
-            "chaincodeMessage is null"
-        );
+                IllegalArgumentException.class, () -> itm.onChaincodeMessage(null), "chaincodeMessage is null");
     }
 
     @Test
@@ -131,7 +131,8 @@ void setResponseConsumer() throws IOException {
         Metrics.initialize(props);
         Traces.initialize(props);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
         itm.setResponseConsumer(null);
     }
@@ -147,14 +148,11 @@ void registerException() {
         Metrics.initialize(props);
         Traces.initialize(props);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
 
-        Assertions.assertThrows(
-                IllegalArgumentException.class, itm::register,
-                "outgoingMessage is null"
-        );
-
+        Assertions.assertThrows(IllegalArgumentException.class, itm::register, "outgoingMessage is null");
     }
 
     @Test
@@ -168,7 +166,8 @@ void onChaincodeMessageREGISTER() {
         Metrics.initialize(props);
         Traces.initialize(props);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
         final Consumer consumer = t -> {
             assertEquals(ChaincodeMessageFactory.newRegisterChaincodeMessage(chaincodeId), t);
@@ -191,15 +190,16 @@ void onChaincodeMessageInvokeChaincode() {
         Traces.initialize(props);
 
         final String chaincodeIdNumber = "chaincodeIdNumber12345";
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(chaincodeIdNumber).build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName(chaincodeIdNumber).build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
         final Consumer consumer = t -> {
             assertEquals(ChaincodeMessageFactory.newRegisterChaincodeMessage(chaincodeId), t);
         };
 
         itm.setResponseConsumer(consumer);
-        final ChaincodeMessage chaincodeMessage = ChaincodeMessageFactory
-                .newInvokeChaincodeMessage(chaincodeIdNumber, "txid", ByteString.copyFromUtf8(""));
+        final ChaincodeMessage chaincodeMessage = ChaincodeMessageFactory.newInvokeChaincodeMessage(
+                chaincodeIdNumber, "txid", ByteString.copyFromUtf8(""));
         itm.onChaincodeMessage(chaincodeMessage);
     }
 
@@ -215,15 +215,16 @@ void onChaincodeMessagePutState() {
         Traces.initialize(props);
 
         final String chaincodeIdNumber = "chaincodeIdNumber12345";
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName(chaincodeIdNumber).build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName(chaincodeIdNumber).build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
         final Consumer consumer = t -> {
             assertEquals(ChaincodeMessageFactory.newRegisterChaincodeMessage(chaincodeId), t);
         };
 
         itm.setResponseConsumer(consumer);
-        final ChaincodeMessage chaincodeMessage = ChaincodeMessageFactory
-                .newPutStateEventMessage(chaincodeIdNumber, "txid", "collection", "key", ByteString.copyFromUtf8("value"));
+        final ChaincodeMessage chaincodeMessage = ChaincodeMessageFactory.newPutStateEventMessage(
+                chaincodeIdNumber, "txid", "collection", "key", ByteString.copyFromUtf8("value"));
         itm.onChaincodeMessage(chaincodeMessage);
     }
 
@@ -241,7 +242,8 @@ void shutdown() throws IOException {
         final ManagedChannelBuilder managedChannelBuilder = chaincodeBase.newChannelBuilder();
         ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(managedChannelBuilder);
 
-        final ChaincodeID chaincodeId = ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
+        final ChaincodeID chaincodeId =
+                ChaincodeID.newBuilder().setName("chaincodeIdNumber12345").build();
         final InvocationTaskManager itm = InvocationTaskManager.getManager(chaincodeBase, chaincodeId);
         itm.shutdown();
     }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java
index 8d2b4720..b053a869 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java
@@ -15,7 +15,6 @@
 
 import com.google.protobuf.ByteString;
 import com.google.protobuf.InvalidProtocolBufferException;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.GetStateByRange;
 import org.hyperledger.fabric.protos.peer.QueryResponse;
@@ -41,8 +40,8 @@ class GetStateByRangeTests {
 
         @BeforeEach
         public void beforeEach() throws Exception {
-            final ChaincodeMessage mockMessage = ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "",
-                    "key");
+            final ChaincodeMessage mockMessage =
+                    ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", "key");
             mockHandler = mock(ChaincodeInvocationTask.class);
             final ByteString mockString = QueryResponse.newBuilder().build().toByteString();
 
@@ -105,12 +104,10 @@ public void unbounded() throws InvalidProtocolBufferException {
         @Test
         public void simplekeys() {
             assertThatThrownBy(() -> {
-                final QueryResultsIterator qri = stubImpl
-                        .getStateByRange(new String(Character.toChars(Character.MIN_CODE_POINT)), "");
-            }).hasMessageContaining("not allowed");
-
+                        final QueryResultsIterator qri =
+                                stubImpl.getStateByRange(new String(Character.toChars(Character.MIN_CODE_POINT)), "");
+                    })
+                    .hasMessageContaining("not allowed");
         }
-
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java
index ae4ee29a..7fd6b760 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java
@@ -5,7 +5,14 @@
  */
 package org.hyperledger.fabric.shim.impl;
 
+import static org.mockito.Mockito.when;
+
 import com.google.protobuf.ByteString;
+import java.io.UnsupportedEncodingException;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
 import org.hyperledger.fabric.metrics.Metrics;
 import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
@@ -16,14 +23,6 @@
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
-import java.io.UnsupportedEncodingException;
-import java.util.Properties;
-import java.util.logging.Level;
-import java.util.logging.LogManager;
-import java.util.logging.Logger;
-
-import static org.mockito.Mockito.when;
-
 public final class InvocationTaskManagerTest {
 
     private InvocationTaskManager itm;
@@ -42,8 +41,7 @@ public void setup() {
 
         perfLogger = LogManager.getLogManager().getLogger("org.hyperledger.Performance");
         perfLogger.setLevel(Level.ALL);
-        this.itm.setResponseConsumer((value) -> {
-        });
+        this.itm.setResponseConsumer((value) -> {});
     }
 
     @AfterEach
@@ -61,51 +59,47 @@ public void register() throws UnsupportedEncodingException {
     @Test
     public void onMessageTestTx() throws UnsupportedEncodingException {
 
-        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION,
-                "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
+        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(
+                ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
 
         when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.READY);
 
         itm.onChaincodeMessage(msg);
-
     }
 
     @Test
     public void onWrongCreatedState() throws UnsupportedEncodingException {
 
         perfLogger.setLevel(Level.ALL);
-        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION,
-                "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
+        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(
+                ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
 
         when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.CREATED);
 
         itm.onChaincodeMessage(msg);
-
     }
 
     @Test
     public void onWrongEstablishedState() throws UnsupportedEncodingException {
 
-        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.TRANSACTION,
-                "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
+        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(
+                ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
 
         when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.ESTABLISHED);
 
         // final InvocationTaskManager itm =
         // InvocationTaskManager.getManager(chaincode, id);
         itm.onChaincodeMessage(msg);
-
     }
 
     @Test
     public void onErrorResponse() throws UnsupportedEncodingException {
 
-        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(ChaincodeMessage.Type.ERROR, "mychannel",
-                "txid", ByteString.copyFrom("Hello", "UTF-8"));
+        final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage(
+                ChaincodeMessage.Type.ERROR, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8"));
 
         when(chaincode.getState()).thenReturn(ChaincodeBase.CCState.READY);
 
         itm.onChaincodeMessage(msg);
-
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java
index 51fc0193..2dc72dc9 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java
@@ -6,14 +6,6 @@
 
 package org.hyperledger.fabric.shim.impl;
 
-import com.google.protobuf.ByteString;
-import com.google.protobuf.Timestamp;
-import org.hyperledger.fabric.shim.ledger.KeyModification;
-import org.junit.jupiter.api.Test;
-
-import java.time.Instant;
-import java.util.stream.Stream;
-
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
@@ -23,6 +15,13 @@
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import com.google.protobuf.ByteString;
+import com.google.protobuf.Timestamp;
+import java.time.Instant;
+import java.util.stream.Stream;
+import org.hyperledger.fabric.shim.ledger.KeyModification;
+import org.junit.jupiter.api.Test;
+
 public class KeyModificationImplTest {
 
     @Test
@@ -30,64 +29,66 @@ public void testKeyModificationImpl() {
         new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
                 .setTxId("txid")
                 .setValue(ByteString.copyFromUtf8("value"))
-                .setTimestamp(Timestamp.newBuilder()
-                        .setSeconds(1234567890)
-                        .setNanos(123456789))
+                .setTimestamp(Timestamp.newBuilder().setSeconds(1234567890).setNanos(123456789))
                 .setIsDelete(true)
                 .build());
     }
 
     @Test
     public void testGetTxId() {
-        final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setTxId("txid")
-                .build());
+        final KeyModification km =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setTxId("txid")
+                        .build());
         assertThat(km.getTxId(), is(equalTo("txid")));
     }
 
     @Test
     public void testGetValue() {
-        final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setValue(ByteString.copyFromUtf8("value"))
-                .build());
+        final KeyModification km =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setValue(ByteString.copyFromUtf8("value"))
+                        .build());
         assertThat(km.getValue(), is(equalTo("value".getBytes(UTF_8))));
     }
 
     @Test
     public void testGetStringValue() {
-        final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setValue(ByteString.copyFromUtf8("value"))
-                .build());
+        final KeyModification km =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setValue(ByteString.copyFromUtf8("value"))
+                        .build());
         assertThat(km.getStringValue(), is(equalTo("value")));
     }
 
     @Test
     public void testGetTimestamp() {
-        final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setTimestamp(Timestamp.newBuilder()
-                        .setSeconds(1234567890L)
-                        .setNanos(123456789))
-                .build());
+        final KeyModification km =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setTimestamp(
+                                Timestamp.newBuilder().setSeconds(1234567890L).setNanos(123456789))
+                        .build());
         assertThat(km.getTimestamp(), hasProperty("epochSecond", equalTo(1234567890L)));
         assertThat(km.getTimestamp(), hasProperty("nano", equalTo(123456789)));
     }
 
     @Test
     public void testIsDeleted() {
-        Stream.of(true, false)
-                .forEach(b -> {
-                    final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+        Stream.of(true, false).forEach(b -> {
+            final KeyModification km = new KeyModificationImpl(
+                    org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
                             .setIsDelete(b)
                             .build());
-                    assertThat(km.isDeleted(), is(b));
-                });
+            assertThat(km.isDeleted(), is(b));
+        });
     }
 
     @Test
     public void testHashCode() {
-        final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setIsDelete(false)
-                .build());
+        final KeyModification km =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setIsDelete(false)
+                        .build());
 
         int expectedHashCode = 31;
         expectedHashCode = expectedHashCode + 1237;
@@ -96,24 +97,25 @@ public void testHashCode() {
         expectedHashCode = expectedHashCode * 31 + ByteString.copyFromUtf8("").hashCode();
 
         assertEquals(expectedHashCode, km.hashCode(), "Wrong hash code");
-
     }
 
     @Test
     public void testEquals() {
-        final KeyModification km1 = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setIsDelete(false)
-                .build());
-        final KeyModification km2 = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setIsDelete(true)
-                .build());
-
-        final KeyModification km3 = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
-                .setIsDelete(false)
-                .build());
+        final KeyModification km1 =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setIsDelete(false)
+                        .build());
+        final KeyModification km2 =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setIsDelete(true)
+                        .build());
+
+        final KeyModification km3 =
+                new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder()
+                        .setIsDelete(false)
+                        .build());
 
         assertFalse(km1.equals(km2));
         assertTrue(km1.equals(km3));
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java
index 216398d6..3b8bbf43 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java
@@ -6,17 +6,17 @@
 
 package org.hyperledger.fabric.shim.impl;
 
-import com.google.protobuf.ByteString;
-import org.hyperledger.fabric.protos.ledger.queryresult.KV;
-import org.junit.jupiter.api.Test;
-
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.google.protobuf.ByteString;
+import org.hyperledger.fabric.protos.ledger.queryresult.KV;
+import org.junit.jupiter.api.Test;
 
 public class KeyValueImplTest {
 
@@ -57,8 +57,7 @@ public void testGetStringValue() {
 
     @Test
     public void testHashCode() {
-        final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder()
-                .build());
+        final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder().build());
 
         int expectedHashCode = 31;
         expectedHashCode = expectedHashCode + "".hashCode();
@@ -92,7 +91,5 @@ public void testEquals() {
         assertFalse(kv1.equals(kv2));
         assertFalse(kv1.equals(kv3));
         assertTrue(kv1.equals(kv4));
-
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java
index 9f312564..3d1b299f 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java
@@ -6,25 +6,23 @@
 
 package org.hyperledger.fabric.shim.impl;
 
-import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import com.google.protobuf.ByteString;
 import java.util.function.Function;
-
 import org.hyperledger.fabric.protos.peer.QueryResponse;
-import org.hyperledger.fabric.protos.peer.QueryResultBytes;
 import org.hyperledger.fabric.protos.peer.QueryResponseMetadata;
+import org.hyperledger.fabric.protos.peer.QueryResultBytes;
 import org.junit.jupiter.api.Test;
 
-import com.google.protobuf.ByteString;
-
 public class QueryResultsIteratorWithMetadataImplTest {
 
     @Test
     public void getMetadata() {
-        final QueryResultsIteratorWithMetadataImpl testIter = new QueryResultsIteratorWithMetadataImpl<>(null, "", "",
-                prepareQueryResponse().toByteString(), queryResultBytesToKv);
+        final QueryResultsIteratorWithMetadataImpl testIter = new QueryResultsIteratorWithMetadataImpl<>(
+                null, "", "", prepareQueryResponse().toByteString(), queryResultBytesToKv);
         assertThat(testIter.getMetadata().getBookmark(), is("asdf"));
         assertThat(testIter.getMetadata().getFetchedRecordsCount(), is(2));
     }
@@ -32,7 +30,8 @@ public void getMetadata() {
     @Test
     public void getInvalidMetadata() {
         try {
-            new QueryResultsIteratorWithMetadataImpl<>(null, "", "", prepareQueryResponseWrongMeta().toByteString(), queryResultBytesToKv);
+            new QueryResultsIteratorWithMetadataImpl<>(
+                    null, "", "", prepareQueryResponseWrongMeta().toByteString(), queryResultBytesToKv);
             fail();
         } catch (final RuntimeException e) {
         }
@@ -55,16 +54,11 @@ private QueryResponse prepareQueryResponse() {
                 .setHasMore(false)
                 .setMetadata(qrm.toByteString())
                 .build();
-
     }
 
     private QueryResponse prepareQueryResponseWrongMeta() {
         final ByteString bs = ByteString.copyFrom(new byte[] {0, 0});
 
-        return QueryResponse.newBuilder()
-                .setHasMore(false)
-                .setMetadata(bs)
-                .build();
-
+        return QueryResponse.newBuilder().setHasMore(false).setMetadata(bs).build();
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java
index 2fce7d4f..d2bac2f8 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java
@@ -6,10 +6,6 @@
 
 package org.hyperledger.fabric.shim.ledger;
 
-import org.junit.jupiter.api.Test;
-
-import java.util.Arrays;
-
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
@@ -17,6 +13,9 @@
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
 public class CompositeKeyTest {
     @Test
     public void testValidateSimpleKeys() {
@@ -108,14 +107,15 @@ public void testParseCompositeKey() {
 
     @Test
     public void testParseCompositeKeyInvalidObjectType() {
-        assertThatThrownBy(() -> CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))
+        assertThatThrownBy(() ->
+                        CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))
                 .isInstanceOf(CompositeKeyFormatException.class);
     }
 
     @Test
     public void testParseCompositeKeyInvalidAttribute() {
-        assertThatThrownBy(() -> CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000"))
+        assertThatThrownBy(() ->
+                        CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000"))
                 .isInstanceOf(CompositeKeyFormatException.class);
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java
index badf8ca6..710b9eb0 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java
@@ -6,27 +6,23 @@
 
 package org.hyperledger.fabric.shim.mock.peer;
 
+import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.PUT_STATE;
+
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
 import java.io.IOException;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.logging.Logger;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc;
 import org.hyperledger.fabric.shim.utils.TimeoutUtil;
 
-import io.grpc.Server;
-import io.grpc.ServerBuilder;
-import io.grpc.stub.StreamObserver;
-import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.PUT_STATE;
-
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Mock peer implementation
- */
+/** Mock peer implementation */
 public final class ChaincodeMockPeer {
     private static final Logger LOGGER = Logger.getLogger(ChaincodeMockPeer.class.getName());
 
@@ -38,7 +34,7 @@ public final class ChaincodeMockPeer {
      * Constructor
      *
      * @param scenario list of scenario steps
-     * @param port     mock peer communication port
+     * @param port mock peer communication port
      * @throws IOException
      */
     public ChaincodeMockPeer(final List scenario, final int port) {
@@ -48,9 +44,7 @@ public ChaincodeMockPeer(final List scenario, final int port) {
         this.server = sb.addService(this.service).build();
     }
 
-    /**
-     * Start serving requests.
-     */
+    /** Start serving requests. */
     public void start() throws IOException {
         server.start();
         LOGGER.info("Server started, listening on " + port);
@@ -65,9 +59,7 @@ public void run() {
         });
     }
 
-    /**
-     * Stop serving requests and shutdown resources.
-     */
+    /** Stop serving requests and shutdown resources. */
     public void stop() {
         if (server != null) {
             server.shutdownNow();
@@ -99,21 +91,16 @@ public int getLastExecutedStep() {
         return this.service.lastExecutedStepNumber;
     }
 
-    /**
-     * @return last received message from chaincode
-     */
+    /** @return last received message from chaincode */
     public ChaincodeMessage getLastMessageRcvd() {
         return this.service.lastMessageRcvd;
-
     }
 
     public ArrayList getAllReceivedMessages() {
         return this.service.allMessages;
     }
 
-    /**
-     * @return last message sent by peer to chaincode
-     */
+    /** @return last message sent by peer to chaincode */
     public ChaincodeMessage getLastMessageSend() {
         return this.service.lastMessageSend;
     }
@@ -161,8 +148,7 @@ public void send(final ChaincodeMessage msg) {
          * @return
          */
         @Override
-        public StreamObserver register(
-                final StreamObserver responseObserver) {
+        public StreamObserver register(final StreamObserver responseObserver) {
             observer = responseObserver;
             return new StreamObserver() {
 
@@ -180,7 +166,8 @@ public void onNext(final ChaincodeMessage chaincodeMessage) {
                         if (chaincodeMessage.getType().equals(PUT_STATE)) {
                             final ChaincodeMessage m = ChaincodeMessage.newBuilder()
                                     .setType(ChaincodeMessage.Type.RESPONSE)
-                                    .setChannelId(chaincodeMessage.getChannelId()).setTxid(chaincodeMessage.getTxid())
+                                    .setChannelId(chaincodeMessage.getChannelId())
+                                    .setTxid(chaincodeMessage.getTxid())
                                     .build();
                             Thread.sleep(500);
                             ChaincodeMockPeerService.this.send(m);
@@ -195,7 +182,8 @@ public void onNext(final ChaincodeMessage chaincodeMessage) {
                                     ChaincodeMockPeerService.this.send(m);
                                 }
                             } else {
-                                LOGGER.warning("Non expected message rcvd in step " + step.getClass().getSimpleName());
+                                LOGGER.warning("Non expected message rcvd in step "
+                                        + step.getClass().getSimpleName());
                             }
                             ChaincodeMockPeerService.this.lastExecutedStepNumber++;
                         }
@@ -210,30 +198,30 @@ public void onError(final Throwable throwable) {
                 }
 
                 @Override
-                public void onCompleted() {
-
-                }
+                public void onCompleted() {}
             };
         }
     }
 
-    public static void checkScenarioStepEnded(final ChaincodeMockPeer s, final int step, final int timeout,
-            final TimeUnit units) throws Exception {
+    public static void checkScenarioStepEnded(
+            final ChaincodeMockPeer s, final int step, final int timeout, final TimeUnit units) throws Exception {
         try {
-            TimeoutUtil.runWithTimeout(new Thread(() -> {
-                while (true) {
-                    if (s.getLastExecutedStep() == step) {
-                        return;
-                    }
-                    try {
-                        Thread.sleep(500);
-                    } catch (final InterruptedException e) {
-                    }
-                }
-            }), timeout, units);
+            TimeoutUtil.runWithTimeout(
+                    new Thread(() -> {
+                        while (true) {
+                            if (s.getLastExecutedStep() == step) {
+                                return;
+                            }
+                            try {
+                                Thread.sleep(500);
+                            } catch (final InterruptedException e) {
+                            }
+                        }
+                    }),
+                    timeout,
+                    units);
         } catch (final TimeoutException e) {
             System.out.println("Got timeout, step " + step + " not finished");
         }
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java
index 625de587..34ea010b 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/CompleteStep.java
@@ -8,12 +8,9 @@
 
 import java.util.Collections;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
-/**
- * Waits for COMPLETED message, sends nothing back
- */
+/** Waits for COMPLETED message, sends nothing back */
 public final class CompleteStep implements ScenarioStep {
     @Override
     public boolean expected(final ChaincodeMessage msg) {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/DelValueStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/DelValueStep.java
index 95b31012..37ef42b0 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/DelValueStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/DelValueStep.java
@@ -7,12 +7,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates delState() invocation in chaincode Waits for DEL_STATE message from
- * chaincode and sends back response with empty payload
+ * Simulates delState() invocation in chaincode Waits for DEL_STATE message from chaincode and sends back response with
+ * empty payload
  */
 public final class DelValueStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java
index fae2dd60..96e63c7a 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ErrorResponseStep.java
@@ -7,12 +7,9 @@
 
 import java.util.Collections;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
-/**
- * Error message from chaincode side, no response sent
- */
+/** Error message from chaincode side, no response sent */
 public final class ErrorResponseStep implements ScenarioStep {
     @Override
     public boolean expected(final ChaincodeMessage msg) {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java
index 813732ee..96e2fcc0 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java
@@ -7,16 +7,14 @@
 
 import static java.util.stream.Collectors.toList;
 
+import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.ledger.queryresult.KeyModification;
+import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.QueryResponse;
 import org.hyperledger.fabric.protos.peer.QueryResultBytes;
-import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
-
-import com.google.protobuf.ByteString;
 
 public final class GetHistoryForKeyStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
@@ -27,7 +25,7 @@ public final class GetHistoryForKeyStep implements ScenarioStep {
      * Initiate step
      *
      * @param hasNext is response message QueryResponse hasMore field set
-     * @param vals    list of keys to generate ("key" => "key Value") pairs
+     * @param vals list of keys to generate ("key" => "key Value") pairs
      */
     public GetHistoryForKeyStep(final boolean hasNext, final String... vals) {
         this.values = vals;
@@ -42,14 +40,17 @@ public boolean expected(final ChaincodeMessage msg) {
 
     @Override
     public List next() {
-        final List keyModifications = Arrays.asList(values).stream().map(x -> KeyModification.newBuilder()
-                .setTxId(x)
-                .setValue(ByteString.copyFromUtf8(x + " Value"))
-                .build()).collect(toList());
+        final List keyModifications = Arrays.asList(values).stream()
+                .map(x -> KeyModification.newBuilder()
+                        .setTxId(x)
+                        .setValue(ByteString.copyFromUtf8(x + " Value"))
+                        .build())
+                .collect(toList());
 
         final QueryResponse.Builder builder = QueryResponse.newBuilder();
         builder.setHasMore(hasNext);
-        keyModifications.stream().forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString())));
+        keyModifications.stream()
+                .forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString())));
         final ByteString historyPayload = builder.build().toByteString();
 
         final List list = new ArrayList<>();
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetQueryResultStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetQueryResultStep.java
index 00207270..2c137d93 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetQueryResultStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetQueryResultStep.java
@@ -8,8 +8,8 @@
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates query invocation. Waits for GET_QUERY_RESULT Returns message that
- * contains list of results in form ("key" => "key Value")*
+ * Simulates query invocation. Waits for GET_QUERY_RESULT Returns message that contains list of results in form ("key"
+ * => "key Value")*
  */
 public final class GetQueryResultStep extends QueryResultStep {
 
@@ -17,7 +17,7 @@ public final class GetQueryResultStep extends QueryResultStep {
      * Initiate step
      *
      * @param hasNext is response message QueryResponse hasMore field set
-     * @param vals    list of keys to generate ("key" => "key Value") pairs
+     * @param vals list of keys to generate ("key" => "key Value") pairs
      */
     public GetQueryResultStep(final boolean hasNext, final String... vals) {
         super(hasNext, vals);
@@ -28,5 +28,4 @@ public boolean expected(final ChaincodeMessage msg) {
         super.orgMsg = msg;
         return msg.getType() == ChaincodeMessage.Type.GET_QUERY_RESULT;
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateByRangeStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateByRangeStep.java
index fc87811d..0acebac6 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateByRangeStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateByRangeStep.java
@@ -8,8 +8,8 @@
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates getStateByRange Waits for GET_STATE_BY_RANGE message Returns
- * message that contains list of results in form ("key" => "key Value")*
+ * Simulates getStateByRange Waits for GET_STATE_BY_RANGE message Returns message that contains list of results in form
+ * ("key" => "key Value")*
  */
 public final class GetStateByRangeStep extends QueryResultStep {
 
@@ -17,7 +17,7 @@ public final class GetStateByRangeStep extends QueryResultStep {
      * Initiate step
      *
      * @param hasNext is response message QueryResponse hasMore field set
-     * @param vals    list of keys to generate ("key" => "key Value") pairs
+     * @param vals list of keys to generate ("key" => "key Value") pairs
      */
     public GetStateByRangeStep(final boolean hasNext, final String... vals) {
         super(hasNext, vals);
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateMetadata.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateMetadata.java
index 6d085fe5..8419ee2d 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateMetadata.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetStateMetadata.java
@@ -5,28 +5,23 @@
  */
 package org.hyperledger.fabric.shim.mock.peer;
 
+import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import java.util.List;
-
-import org.hyperledger.fabric.protos.peer.StateMetadata;
-import org.hyperledger.fabric.protos.peer.StateMetadataResult;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.MetaDataKeys;
+import org.hyperledger.fabric.protos.peer.StateMetadata;
+import org.hyperledger.fabric.protos.peer.StateMetadataResult;
 import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement;
 
-import com.google.protobuf.ByteString;
-
 /**
- * simulates Handler.getStateMetadata Waits for GET_STATE_METADATA message
- * Returns response message with stored metadata
+ * simulates Handler.getStateMetadata Waits for GET_STATE_METADATA message Returns response message with stored metadata
  */
 public final class GetStateMetadata implements ScenarioStep {
     private ChaincodeMessage orgMsg;
     private final byte[] val;
 
-    /**
-     * @param sbe StateBasedEndorsement to return as one and only one metadata entry
-     */
+    /** @param sbe StateBasedEndorsement to return as one and only one metadata entry */
     public GetStateMetadata(final StateBasedEndorsement sbe) {
         val = sbe.policy();
     }
@@ -45,9 +40,8 @@ public List next() {
                 .setValue(ByteString.copyFrom(val))
                 .build();
         entriesList.add(validationValue);
-        final StateMetadataResult stateMetadataResult = StateMetadataResult.newBuilder()
-                .addAllEntries(entriesList)
-                .build();
+        final StateMetadataResult stateMetadataResult =
+                StateMetadataResult.newBuilder().addAllEntries(entriesList).build();
         final List list = new ArrayList<>();
         list.add(ChaincodeMessage.newBuilder()
                 .setType(ChaincodeMessage.Type.RESPONSE)
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetValueStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetValueStep.java
index 67070196..6bac3ac3 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetValueStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetValueStep.java
@@ -5,25 +5,17 @@
  */
 package org.hyperledger.fabric.shim.mock.peer;
 
+import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
-import com.google.protobuf.ByteString;
-
-/**
- * Simulates getState Waits for GET_STATE message Returns response message with
- * value as payload
- */
+/** Simulates getState Waits for GET_STATE message Returns response message with value as payload */
 public final class GetValueStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
     private final String val;
 
-    /**
-     *
-     * @param val value to return
-     */
+    /** @param val value to return */
     public GetValueStep(final String val) {
         this.val = val;
     }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/InvokeChaincodeStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/InvokeChaincodeStep.java
index 9ca3b547..dceae3b3 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/InvokeChaincodeStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/InvokeChaincodeStep.java
@@ -5,18 +5,16 @@
  */
 package org.hyperledger.fabric.shim.mock.peer;
 
+import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.Response;
 import org.hyperledger.fabric.shim.Chaincode;
 
-import com.google.protobuf.ByteString;
-
 /**
- * Simulates another chaincode invocation Waits for INVOKE_CHAINCODE Sends back
- * RESPONSE message with chaincode response inside
+ * Simulates another chaincode invocation Waits for INVOKE_CHAINCODE Sends back RESPONSE message with chaincode response
+ * inside
  */
 public final class InvokeChaincodeStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
@@ -28,22 +26,22 @@ public boolean expected(final ChaincodeMessage msg) {
     }
 
     /**
-     *
-     * @return Chaincode response packed as payload inside COMPLETE message packed
-     *         as payload inside RESPONSE message
+     * @return Chaincode response packed as payload inside COMPLETE message packed as payload inside RESPONSE message
      */
     @Override
     public List next() {
         final ByteString chaincodeResponse = Response.newBuilder()
                 .setStatus(Chaincode.Response.Status.SUCCESS.getCode())
                 .setMessage("OK")
-                .build().toByteString();
+                .build()
+                .toByteString();
         final ByteString completePayload = ChaincodeMessage.newBuilder()
                 .setType(ChaincodeMessage.Type.COMPLETED)
                 .setChannelId(orgMsg.getChannelId())
                 .setTxid(orgMsg.getTxid())
                 .setPayload(chaincodeResponse)
-                .build().toByteString();
+                .build()
+                .toByteString();
         final List list = new ArrayList<>();
         list.add(ChaincodeMessage.newBuilder()
                 .setType(ChaincodeMessage.Type.RESPONSE)
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PurgeValueStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PurgeValueStep.java
index b048295d..e6eed042 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PurgeValueStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PurgeValueStep.java
@@ -7,12 +7,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates purgePrivateData() invocation in chaincode Waits for PURGE_PRIVATE_DATA message from
- * chaincode and sends back response with empty payload
+ * Simulates purgePrivateData() invocation in chaincode Waits for PURGE_PRIVATE_DATA message from chaincode and sends
+ * back response with empty payload
  */
 public final class PurgeValueStep implements ScenarioStep {
 
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutStateMetadata.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutStateMetadata.java
index 156f7353..95d80e03 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutStateMetadata.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutStateMetadata.java
@@ -5,20 +5,17 @@
  */
 package org.hyperledger.fabric.shim.mock.peer;
 
+import com.google.protobuf.InvalidProtocolBufferException;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.MetaDataKeys;
 import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement;
 import org.hyperledger.fabric.shim.ext.sbe.impl.StateBasedEndorsementFactory;
 
-import com.google.protobuf.InvalidProtocolBufferException;
-
 /**
- * * Simulates Handler.putStateMetadata() invocation from chaincode side * Waits
- * for PUT_STATE_METADATA message from chaincode, including metadata entry with
- * validation metadata and sends back response with empty payload
+ * * Simulates Handler.putStateMetadata() invocation from chaincode side * Waits for PUT_STATE_METADATA message from
+ * chaincode, including metadata entry with validation metadata and sends back response with empty payload
  */
 public final class PutStateMetadata implements ScenarioStep {
     private ChaincodeMessage orgMsg;
@@ -29,8 +26,7 @@ public PutStateMetadata(final StateBasedEndorsement sbe) {
     }
 
     /**
-     * Check incoming message If message type is PUT_STATE_METADATA and payload
-     * match to passed in constructor
+     * Check incoming message If message type is PUT_STATE_METADATA and payload match to passed in constructor
      *
      * @param msg message from chaincode
      * @return
@@ -44,9 +40,12 @@ public boolean expected(final ChaincodeMessage msg) {
         } catch (final InvalidProtocolBufferException e) {
             return false;
         }
-        final StateBasedEndorsement msgSbe = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(psm.getMetadata().getValue().toByteArray());
+        final StateBasedEndorsement msgSbe = StateBasedEndorsementFactory.getInstance()
+                .newStateBasedEndorsement(psm.getMetadata().getValue().toByteArray());
         return msg.getType() == ChaincodeMessage.Type.PUT_STATE_METADATA
-                && MetaDataKeys.VALIDATION_PARAMETER.toString().equals(psm.getMetadata().getMetakey())
+                && MetaDataKeys.VALIDATION_PARAMETER
+                        .toString()
+                        .equals(psm.getMetadata().getMetakey())
                 && (msgSbe.listOrgs().size() == val.listOrgs().size());
     }
 
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutValueStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutValueStep.java
index 6dc16d47..b96e7425 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutValueStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/PutValueStep.java
@@ -6,18 +6,16 @@
 
 package org.hyperledger.fabric.shim.mock.peer;
 
+import com.google.protobuf.InvalidProtocolBufferException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
-
-import org.hyperledger.fabric.protos.peer.PutState;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
-
-import com.google.protobuf.InvalidProtocolBufferException;
+import org.hyperledger.fabric.protos.peer.PutState;
 
 /**
- * Simulates putState() invocation in chaincode Waits for PUT_STATE message from
- * chaincode, including value and sends back response with empty payload
+ * Simulates putState() invocation in chaincode Waits for PUT_STATE message from chaincode, including value and sends
+ * back response with empty payload
  */
 public final class PutValueStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
@@ -33,8 +31,7 @@ public PutValueStep(final String val) {
     }
 
     /**
-     * Check incoming message If message type is PUT_STATE and payload equal to
-     * passed in constructor
+     * Check incoming message If message type is PUT_STATE and payload equal to passed in constructor
      *
      * @param msg message from chaincode
      * @return
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryCloseStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryCloseStep.java
index e282b23d..501ed1ce 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryCloseStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryCloseStep.java
@@ -7,12 +7,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulate last query (close) step. Happens after passing over all query result
- * Waits for QUERY_STATE_CLOSE Sends back response with empty payload
+ * Simulate last query (close) step. Happens after passing over all query result Waits for QUERY_STATE_CLOSE Sends back
+ * response with empty payload
  */
 public final class QueryCloseStep implements ScenarioStep {
     private ChaincodeMessage orgMsg;
@@ -23,10 +22,7 @@ public boolean expected(final ChaincodeMessage msg) {
         return msg.getType() == ChaincodeMessage.Type.QUERY_STATE_CLOSE;
     }
 
-    /**
-     *
-     * @return RESPONSE message with empty payload
-     */
+    /** @return RESPONSE message with empty payload */
     @Override
     public List next() {
         final List list = new ArrayList<>();
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryNextStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryNextStep.java
index fced5b3e..331b15e3 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryNextStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryNextStep.java
@@ -8,9 +8,8 @@
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates requesting/receiving next set of results for query Waits for
- * QUERY_STATE_NEXT Returns message that contains list of results in form ("key"
- * => "key Value")*
+ * Simulates requesting/receiving next set of results for query Waits for QUERY_STATE_NEXT Returns message that contains
+ * list of results in form ("key" => "key Value")*
  */
 public final class QueryNextStep extends QueryResultStep {
 
@@ -18,7 +17,7 @@ public final class QueryNextStep extends QueryResultStep {
      * Initiate step
      *
      * @param hasNext is response message QueryResponse hasMore field set
-     * @param vals    list of keys to generate ("key" => "key Value") pairs
+     * @param vals list of keys to generate ("key" => "key Value") pairs
      */
     public QueryNextStep(final boolean hasNext, final String... vals) {
         super(hasNext, vals);
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java
index cab82313..26c52724 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java
@@ -7,20 +7,16 @@
 
 import static java.util.stream.Collectors.toList;
 
+import com.google.protobuf.ByteString;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.ledger.queryresult.KV;
-import org.hyperledger.fabric.protos.peer.QueryResultBytes;
-import org.hyperledger.fabric.protos.peer.QueryResponse;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
+import org.hyperledger.fabric.protos.peer.QueryResponse;
+import org.hyperledger.fabric.protos.peer.QueryResultBytes;
 
-import com.google.protobuf.ByteString;
-
-/**
- * Base class for multi result query steps/messages
- */
+/** Base class for multi result query steps/messages */
 public abstract class QueryResultStep implements ScenarioStep {
     protected ChaincodeMessage orgMsg;
     protected final String[] values;
@@ -30,7 +26,7 @@ public abstract class QueryResultStep implements ScenarioStep {
      * Initiate step
      *
      * @param hasNext is response message QueryResponse hasMore field set
-     * @param vals    list of keys to generate ("key" => "key Value") pairs
+     * @param vals list of keys to generate ("key" => "key Value") pairs
      */
     QueryResultStep(final boolean hasNext, final String... vals) {
         this.values = vals;
@@ -44,14 +40,17 @@ public abstract class QueryResultStep implements ScenarioStep {
      */
     @Override
     public List next() {
-        final List keyValues = Arrays.asList(values).stream().map(x -> KV.newBuilder()
-                .setKey(x)
-                .setValue(ByteString.copyFromUtf8(x + " Value"))
-                .build()).collect(toList());
+        final List keyValues = Arrays.asList(values).stream()
+                .map(x -> KV.newBuilder()
+                        .setKey(x)
+                        .setValue(ByteString.copyFromUtf8(x + " Value"))
+                        .build())
+                .collect(toList());
 
         final QueryResponse.Builder builder = QueryResponse.newBuilder();
         builder.setHasMore(hasNext);
-        keyValues.stream().forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString())));
+        keyValues.stream()
+                .forEach(kv -> builder.addResults(QueryResultBytes.newBuilder().setResultBytes(kv.toByteString())));
         final ByteString rangePayload = builder.build().toByteString();
 
         final List list = new ArrayList<>();
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/RegisterStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/RegisterStep.java
index 81f823bd..25c66c42 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/RegisterStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/RegisterStep.java
@@ -8,12 +8,11 @@
 
 import java.util.ArrayList;
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 /**
- * Simulates chaincode registration after start Waits for REGISTER message from
- * chaincode Sends back pair of messages: REGISTERED and READY
+ * Simulates chaincode registration after start Waits for REGISTER message from chaincode Sends back pair of messages:
+ * REGISTERED and READY
  */
 public final class RegisterStep implements ScenarioStep {
 
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ScenarioStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ScenarioStep.java
index f913ea6c..d219b405 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ScenarioStep.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ScenarioStep.java
@@ -7,7 +7,6 @@
 package org.hyperledger.fabric.shim.mock.peer;
 
 import java.util.List;
-
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
 public interface ScenarioStep {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/MessageUtil.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/MessageUtil.java
index dc0f4fa0..b6ab6a5c 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/MessageUtil.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/MessageUtil.java
@@ -6,16 +6,13 @@
 
 package org.hyperledger.fabric.shim.utils;
 
+import com.google.protobuf.ByteString;
 import org.hyperledger.fabric.protos.peer.ChaincodeEvent;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 
-import com.google.protobuf.ByteString;
-
 public final class MessageUtil {
 
-    private MessageUtil() {
-
-    }
+    private MessageUtil() {}
 
     /**
      * Generate chaincode messages
@@ -27,8 +24,12 @@ private MessageUtil() {
      * @param event
      * @return
      */
-    public static ChaincodeMessage newEventMessage(final ChaincodeMessage.Type type, final String channelId, final String txId,
-            final ByteString payload, final ChaincodeEvent event) {
+    public static ChaincodeMessage newEventMessage(
+            final ChaincodeMessage.Type type,
+            final String channelId,
+            final String txId,
+            final ByteString payload,
+            final ChaincodeEvent event) {
         final ChaincodeMessage.Builder builder = ChaincodeMessage.newBuilder()
                 .setType(type)
                 .setChannelId(channelId)
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/TimeoutUtil.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/TimeoutUtil.java
index 6216363d..12836483 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/TimeoutUtil.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/utils/TimeoutUtil.java
@@ -11,16 +11,13 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-/**
- * Give possibility to stop runnable execution after specific time, if not ended
- */
+/** Give possibility to stop runnable execution after specific time, if not ended */
 public final class TimeoutUtil {
 
-    private TimeoutUtil() {
-
-    }
+    private TimeoutUtil() {}
 
-    public static void runWithTimeout(final Runnable callable, final long timeout, final TimeUnit timeUnit) throws Exception {
+    public static void runWithTimeout(final Runnable callable, final long timeout, final TimeUnit timeUnit)
+            throws Exception {
         final ExecutorService executor = Executors.newSingleThreadExecutor();
         final CountDownLatch latch = new CountDownLatch(1);
         final Thread t = new Thread(() -> {
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java
index 38bf768a..51e0a1bf 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java
@@ -5,33 +5,28 @@
  */
 package org.hyperledger.fabric.traces;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import io.opentelemetry.api.trace.Span;
-import org.hyperledger.fabric.traces.impl.DefaultTracesProvider;
+import java.util.Properties;
 import org.hyperledger.fabric.shim.ChaincodeStub;
+import org.hyperledger.fabric.traces.impl.DefaultTracesProvider;
 import org.hyperledger.fabric.traces.impl.NullProvider;
 import org.hyperledger.fabric.traces.impl.OpenTelemetryTracesProvider;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
-import java.util.Properties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 public class TracesTest {
 
     public static final class TestProvider implements TracesProvider {
 
-        public TestProvider() {
-
-        }
+        public TestProvider() {}
 
         @Override
-        public void initialize(final Properties props) {
-        }
+        public void initialize(final Properties props) {}
 
         @Override
         public Span createSpan(final ChaincodeStub stub) {
@@ -55,9 +50,12 @@ public void tracesEnabledUnknownProvider() {
             props.put("CHAINCODE_TRACES_PROVIDER", "org.example.traces.provider");
             props.put("CHAINCODE_TRACES_ENABLED", "true");
 
-            assertThrows(RuntimeException.class, () -> {
-                final TracesProvider provider = Traces.initialize(props);
-            }, "Unable to start traces");
+            assertThrows(
+                    RuntimeException.class,
+                    () -> {
+                        final TracesProvider provider = Traces.initialize(props);
+                    },
+                    "Unable to start traces");
         }
 
         @Test
@@ -67,7 +65,6 @@ public void tracesNoProvider() {
 
             final TracesProvider provider = Traces.initialize(props);
             assertTrue(provider instanceof DefaultTracesProvider);
-
         }
 
         @Test
@@ -78,7 +75,6 @@ public void tracesOpenTelemetryProvider() {
 
             final TracesProvider provider = Traces.initialize(props);
             assertTrue(provider instanceof OpenTelemetryTracesProvider);
-
         }
 
         @Test
@@ -90,6 +86,5 @@ public void tracesValid() {
 
             assertThat(provider).isExactlyInstanceOf(TracesTest.TestProvider.class);
         }
-
     }
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java
index 7740b341..e36075fd 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java
@@ -5,13 +5,13 @@
  */
 package org.hyperledger.fabric.traces.impl;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 import io.opentelemetry.api.trace.Span;
 import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl;
 import org.hyperledger.fabric.shim.ChaincodeStub;
 import org.junit.jupiter.api.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 public class DefaultProviderTest {
 
     @Test
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java
index fca985db..9c9278be 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java
@@ -5,15 +5,6 @@
  */
 package org.hyperledger.fabric.traces.impl;
 
-import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
-import org.junit.jupiter.api.Test;
-
-import java.time.Duration;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
 import static java.time.temporal.ChronoUnit.DAYS;
 import static java.time.temporal.ChronoUnit.HOURS;
 import static java.time.temporal.ChronoUnit.MILLIS;
@@ -22,11 +13,20 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
 public class OpenTelemetryPropertiesTest {
 
     @Test
     public void testOverrideValue() {
-        OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "bar"), Collections.singletonMap("foo", "foobar"));
+        OpenTelemetryProperties props = new OpenTelemetryProperties(
+                Collections.singletonMap("foo", "bar"), Collections.singletonMap("foo", "foobar"));
         assertThat(props.getString("foo")).isEqualTo("foobar");
     }
 
@@ -42,7 +42,6 @@ public void testCanGetDurationHours() {
         assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, HOURS));
     }
 
-
     @Test
     public void testCanGetDurationMinutes() {
         OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5m"));
@@ -87,7 +86,6 @@ public void testGetLong() {
         assertThat(props.getLong("bar")).isNull();
     }
 
-
     @Test
     public void testGetInt() {
         OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "500003"));
@@ -111,7 +109,8 @@ public void testGetList() {
 
     @Test
     public void testGetMap() {
-        OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "foo=bar,foobar=noes"));
+        OpenTelemetryProperties props =
+                new OpenTelemetryProperties(Collections.singletonMap("foo", "foo=bar,foobar=noes"));
         Map expected = new HashMap<>();
         expected.put("foo", "bar");
         expected.put("foobar", "noes");
@@ -120,7 +119,8 @@ public void testGetMap() {
 
     @Test
     public void testGetMapInvalid() {
-        OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "foo/bar,foobar/noes"));
+        OpenTelemetryProperties props =
+                new OpenTelemetryProperties(Collections.singletonMap("foo", "foo/bar,foobar/noes"));
         Map expected = new HashMap<>();
         assertThatThrownBy(() -> props.getMap("foo")).isInstanceOf(ConfigurationException.class);
     }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java
index 7b03a3f2..6aeda3e8 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java
@@ -5,6 +5,8 @@
  */
 package org.hyperledger.fabric.traces.impl;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 import io.grpc.ManagedChannelBuilder;
 import io.grpc.Server;
 import io.grpc.ServerCall;
@@ -17,10 +19,14 @@
 import io.grpc.stub.StreamObserver;
 import io.opentelemetry.api.trace.Span;
 import io.opentelemetry.sdk.trace.data.SpanData;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 import org.hyperledger.fabric.contract.ChaincodeStubNaiveImpl;
 import org.hyperledger.fabric.metrics.Metrics;
-import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeGrpc;
+import org.hyperledger.fabric.protos.peer.ChaincodeID;
 import org.hyperledger.fabric.protos.peer.ChaincodeMessage;
 import org.hyperledger.fabric.protos.peer.ChaincodeSupportGrpc;
 import org.hyperledger.fabric.shim.ChaincodeBase;
@@ -31,13 +37,6 @@
 import org.hyperledger.fabric.traces.Traces;
 import org.junit.jupiter.api.Test;
 
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
 public final class OpenTelemetryTracesProviderTest {
 
     private final class ContextGetterChaincode extends ChaincodeBase {
@@ -58,7 +57,6 @@ public Properties getChaincodeConfig() {
         }
     }
 
-
     @Test
     public void testProvider() {
         OpenTelemetryTracesProvider provider = new OpenTelemetryTracesProvider();
@@ -84,33 +82,35 @@ public void testTracing() throws Exception {
         // set up a grpc server in process
         ServerCallHandler handler = (call, headers) -> {
             call.close(Status.OK, headers);
-            return new ServerCall.Listener() {
-            };
+            return new ServerCall.Listener() {};
         };
 
-        ServerServiceDefinition.Builder builder = ServerServiceDefinition.builder(ChaincodeGrpc.getServiceDescriptor()).
-                addMethod(ServerMethodDefinition.create(ChaincodeGrpc.getConnectMethod(), handler));
-        ServerServiceDefinition.Builder supportBuilder = ServerServiceDefinition.builder(ChaincodeSupportGrpc.getServiceDescriptor()).
-                addMethod(ServerMethodDefinition.create(ChaincodeSupportGrpc.getRegisterMethod(), handler));
+        ServerServiceDefinition.Builder builder = ServerServiceDefinition.builder(ChaincodeGrpc.getServiceDescriptor())
+                .addMethod(ServerMethodDefinition.create(ChaincodeGrpc.getConnectMethod(), handler));
+        ServerServiceDefinition.Builder supportBuilder = ServerServiceDefinition.builder(
+                        ChaincodeSupportGrpc.getServiceDescriptor())
+                .addMethod(ServerMethodDefinition.create(ChaincodeSupportGrpc.getRegisterMethod(), handler));
 
         String uniqueName = InProcessServerBuilder.generateName();
         Server server = InProcessServerBuilder.forName(uniqueName)
                 .directExecutor()
                 .addService(builder.build())
                 .addService(supportBuilder.build())
-                .build().start();
+                .build()
+                .start();
 
         // create our client
         ManagedChannelBuilder channelBuilder = InProcessChannelBuilder.forName(uniqueName);
         ContextGetterChaincode chaincode = new ContextGetterChaincode();
         ChaincodeSupportClient chaincodeSupportClient = new ChaincodeSupportClient(channelBuilder);
 
-        InvocationTaskManager itm = InvocationTaskManager.getManager(chaincode, ChaincodeID.newBuilder().setName("foo").build());
+        InvocationTaskManager itm = InvocationTaskManager.getManager(
+                chaincode, ChaincodeID.newBuilder().setName("foo").build());
 
         CompletableFuture wait = new CompletableFuture<>();
-        StreamObserver requestObserver = chaincodeSupportClient.getStub().register(
-
-                new StreamObserver() {
+        StreamObserver requestObserver = chaincodeSupportClient
+                .getStub()
+                .register(new StreamObserver() {
                     @Override
                     public void onNext(final ChaincodeMessage chaincodeMessage) {
                         // message off to the ITM...
@@ -128,9 +128,7 @@ public void onCompleted() {
                         chaincodeSupportClient.shutdown(itm);
                         wait.complete(null);
                     }
-                }
-
-        );
+                });
 
         chaincodeSupportClient.start(itm, requestObserver);
         wait.get(5, TimeUnit.SECONDS);
@@ -141,5 +139,4 @@ public void onCompleted() {
         chaincodeSupportClient.shutdown(itm);
         server.shutdown();
     }
-
 }
diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java
index 2bfa9bd6..5baa2ff9 100644
--- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java
+++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java
@@ -10,7 +10,6 @@
 import io.opentelemetry.sdk.common.CompletableResultCode;
 import io.opentelemetry.sdk.trace.data.SpanData;
 import io.opentelemetry.sdk.trace.export.SpanExporter;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd4917707c1f8861d8cb53dd15194d4248596..a4b76b9530d66f5e68d973ea569d8e19de379189 100644
GIT binary patch
delta 34592
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 delta 34555 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0aaefbca..df97d72b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e4..9b42019c 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/settings.gradle b/settings.gradle index c384cfad..3837c43e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,4 @@ rootProject.name = 'fabric-chaincode-java' include 'fabric-chaincode-shim' include 'fabric-chaincode-docker' -include 'fabric-chaincode-integration-test' \ No newline at end of file +include 'fabric-chaincode-integration-test' From d5aa6c5e21bba289b7cfe72245fa13f49e56c585 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 25 Oct 2024 04:32:19 +0100 Subject: [PATCH 015/178] Update microfab (#360) Update microfab used for integration tests from ibmcom/ibp-microfab to use ghcr.io/hyperledger-labs/microfab. This updates the Fabric runtime for v2.4 to v2.5. Signed-off-by: Mark S. Lewis --- .../org/hyperleder/fabric/shim/integration/util/Peer.java | 2 ++ .../src/test/resources/docker-compose-microfab.yaml | 4 ++-- .../src/test/resources/scripts/mfsetup.sh | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java index 65f045b3..dbbc53ad 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/Peer.java @@ -146,6 +146,8 @@ public Peer build(Map additionalEnv) { list.add("--waitForEvent"); } + list.add("--orderer"); + list.add("orderer-api.127-0-0-1.nip.io:8080"); list.add("--peerAddresses"); list.add("org1peer-api.127-0-0-1.nip.io:8080"); list.add("--peerAddresses"); diff --git a/fabric-chaincode-integration-test/src/test/resources/docker-compose-microfab.yaml b/fabric-chaincode-integration-test/src/test/resources/docker-compose-microfab.yaml index 1139861b..79dfc2d7 100644 --- a/fabric-chaincode-integration-test/src/test/resources/docker-compose-microfab.yaml +++ b/fabric-chaincode-integration-test/src/test/resources/docker-compose-microfab.yaml @@ -9,10 +9,10 @@ services: microfab: container_name: microfab - image: ibmcom/ibp-microfab + image: ghcr.io/hyperledger-labs/microfab tty: true environment: - - MICROFAB_CONFIG={"couchdb":false,"endorsing_organizations":[{"name":"org1"},{"name":"org2"}],"channels":[{"name":"sachannel","endorsing_organizations":["org1","org2"]}],"capability_level":"V2_0"} + - MICROFAB_CONFIG={"couchdb":false,"endorsing_organizations":[{"name":"org1"},{"name":"org2"}],"channels":[{"name":"sachannel","endorsing_organizations":["org1","org2"]}],"capability_level":"V2_5"} - FABRIC_LOGGING_SPEC=info ports: - 8080:8080 diff --git a/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh b/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh index bfed2332..6d03c869 100755 --- a/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh +++ b/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh @@ -11,7 +11,7 @@ mkdir -p "${CFG}" # using the IBM tagged version until labs workflow is updated docker rm -f microfab || true -export MICROFAB_CONFIG='{"couchdb":false,"endorsing_organizations":[{"name":"org1"},{"name":"org2"}],"channels":[{"name":"sachannel","endorsing_organizations":["org1","org2"]}],"capability_level":"V2_0"}' +export MICROFAB_CONFIG='{"couchdb":false,"endorsing_organizations":[{"name":"org1"},{"name":"org2"}],"channels":[{"name":"sachannel","endorsing_organizations":["org1","org2"]}],"capability_level":"V2_5"}' docker run --name microfab \ -d \ @@ -20,7 +20,7 @@ docker run --name microfab \ --rm \ -e MICROFAB_CONFIG="${MICROFAB_CONFIG}" \ -e FABRIC_LOGGING_SPEC=info \ - ibmcom/ibp-microfab + ghcr.io/hyperledger-labs/microfab sleep 10 From 85188b74c94469868b59484837613434d8b895e1 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 12 Nov 2024 09:03:08 +0000 Subject: [PATCH 016/178] Update maintainers (#356) - Retire inactive maintainers: Artem Barger, Matthew B White - Add active maintainer: Dave Enyeart Signed-off-by: Mark S. Lewis --- MAINTAINERS.md | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index afe22827..4cf93e41 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,25 +1,23 @@ -Maintainers -=========== +# Maintainers +| Name | GitHub | Chat | email | +| ------------ | ----------------------------------------------------- | --------------- | -------------------------- | +| Dave Enyeart | [denyeart](https://github.com/denyeart) | denyeart | | +| Mark Lewis | [bestbeforetoday](https://github.com/bestbeforetoday) | bestbeforetoday | | -| Name | GitHub | Chat | email | -|---------------------------|------------------|-----------------|---------------------------| -| Artem Barger | c0rwin | c0rwin | bartem@il.ibm.com | -| Matthew B White | mbwhite | mbwhite | whitemat@uk.ibm.com | -| Mark Lewis | bestbeforetoday | bestbeforetoday | Mark.S.Lewis@outlook.com | +# Retired Maintainers -Retired Maintainers -=================== - -| Name | GitHub | Chat | email | -|---------------------------|------------------|---------------|---------------------------| -| James Taylor | jt-nti | jtonline | jamest@uk.ibm.com | -| Gari Singh | mastersingh24 | mastersingh24 | gari.r.singh@gmail.com | -| Gennady Laventman | gennadylaventman | gennadyl | gennady@il.ibm.com | -| Jim Zhang | jimthematrix | jimthematrix | jim\_the\_matrix@hotmail.com | -| Luis Sanchez | sanchezl | sanchezl | sanchezl@us.ibm.com | -| Srinivasan Muralidharan | muralisrini | muralisr | srinivasan.muralidharan99@gmail.com | -| Yacov Manevich | yacovm | yacovm | yacovm@il.ibm.com | +| Name | GitHub | Chat | email | +| ----------------------- | ------------------------------------------------------- | ------------- | ------------------------------------- | +| Artem Barger | [c0rwin](https://github.com/c0rwin) | c0rwin | | +| Matthew B White | [mbwhite](https://github.com/mbwhite) | mbwhite | | +| James Taylor | [jt-nti](https://github.com/jt-nti) | jtonline | | +| Gari Singh | [mastersingh24](https://github.com/mastersingh24) | mastersingh24 | | +| Gennady Laventman | [gennadylaventman](https://github.com/gennadylaventman) | gennadyl | | +| Jim Zhang | [jimthematrix](https://github.com/jimthematrix) | jimthematrix | | +| Luis Sanchez | [sanchezl](https://github.com/sanchezl) | sanchezl | | +| Srinivasan Muralidharan | [muralisrini](https://github.com/muralisrini) | muralisr | | +| Yacov Manevich | [yacovm](https://github.com/yacovm) | yacovm | | Also: Please see the [Release Manager section](https://github.com/hyperledger/fabric/blob/main/MAINTAINERS.md) From 4939a15c6611be6f8f313fcd8ef00be428bc3d5e Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 4 Nov 2024 17:50:49 +0000 Subject: [PATCH 017/178] Replace checkstyle with PMD Also update Java language version to 11, which has been the target runtime and documented as the required version since v2.1. Signed-off-by: Mark S. Lewis --- build.gradle | 5 +- ci/checkstyle/checkstyle.xml | 108 ----- ci/checkstyle/java-copyright-header.txt | 5 - fabric-chaincode-docker/Dockerfile | 4 +- .../src/contracts/bare-gradle/build.gradle | 7 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../contracts/fabric-ledger-api/build.gradle | 7 +- .../contracts/fabric-shim-api/build.gradle | 7 +- .../.mvn/wrapper/maven-wrapper.jar | Bin 59925 -> 63028 bytes .../.mvn/wrapper/maven-wrapper.properties | 8 +- .../src/contracts/wrapper-maven/mvnw | 356 ++++++++-------- .../src/contracts/wrapper-maven/mvnw.cmd | 388 ++++++++++-------- .../src/contracts/wrapper-maven/pom.xml | 2 +- .../contractinstall/ContractInstallTest.java | 2 +- .../ledgertests/LedgerIntegrationTest.java | 2 +- .../shimtests/SACCIntegrationTest.java | 2 +- .../shimtests/SBECCIntegrationTest.java | 4 +- .../shim/integration/util/FabricState.java | 14 +- fabric-chaincode-shim/build.gradle | 20 +- .../java/org/hyperledger/fabric/Logger.java | 8 +- .../java/org/hyperledger/fabric/Logging.java | 11 +- .../fabric/contract/ClientIdentity.java | 25 +- .../fabric/contract/ContextFactory.java | 12 +- .../fabric/contract/ContractInterface.java | 8 +- .../fabric/contract/ContractRouter.java | 53 +-- .../contract/ContractRuntimeException.java | 5 +- .../contract/execution/ExecutionFactory.java | 7 +- .../execution/JSONTransactionSerializer.java | 236 ++++++----- .../impl/ContractExecutionService.java | 4 +- .../impl/ContractInvocationRequest.java | 37 +- .../contract/metadata/MetadataBuilder.java | 101 +++-- .../fabric/contract/metadata/TypeSchema.java | 245 ++++++----- .../routing/impl/ContractDefinitionImpl.java | 20 +- .../routing/impl/DataTypeDefinitionImpl.java | 4 +- .../routing/impl/RoutingRegistryImpl.java | 19 +- .../routing/impl/SerializerRegistryImpl.java | 41 +- .../contract/routing/impl/TxFunctionImpl.java | 70 ++-- .../routing/impl/TypeRegistryImpl.java | 13 +- .../systemcontract/SystemContract.java | 8 +- .../org/hyperledger/fabric/ledger/Ledger.java | 1 - .../fabric/ledger/impl/CollectionImpl.java | 28 -- .../fabric/ledger/impl/LedgerImpl.java | 15 +- .../hyperledger/fabric/metrics/Metrics.java | 12 +- .../fabric/metrics/MetricsProvider.java | 10 +- .../fabric/metrics/impl/DefaultProvider.java | 39 +- .../fabric/metrics/impl/NullProvider.java | 6 +- .../hyperledger/fabric/shim/Chaincode.java | 5 +- .../fabric/shim/ChaincodeBase.java | 102 +++-- .../fabric/shim/ChaincodeException.java | 3 + .../shim/ChaincodeServerProperties.java | 22 +- .../fabric/shim/ChaincodeStub.java | 1 + .../fabric/shim/ChatChaincodeWithPeer.java | 4 +- .../fabric/shim/NettyChaincodeServer.java | 2 + .../fabric/shim/NettyGrpcServer.java | 103 +++-- .../fabric/shim/ResponseUtils.java | 11 +- .../shim/ext/sbe/StateBasedEndorsement.java | 17 +- .../impl/StateBasedEndorsementFactory.java | 9 +- .../sbe/impl/StateBasedEndorsementImpl.java | 5 +- .../shim/impl/ChaincodeInvocationTask.java | 64 +-- .../shim/impl/ChaincodeMessageFactory.java | 35 +- .../shim/impl/ChaincodeSupportClient.java | 27 +- .../fabric/shim/impl/InvocationStubImpl.java | 157 ++++--- .../shim/impl/InvocationTaskExecutor.java | 4 +- .../shim/impl/InvocationTaskManager.java | 174 ++++---- .../fabric/shim/impl/KeyModificationImpl.java | 41 +- .../fabric/shim/impl/KeyValueImpl.java | 24 +- .../shim/impl/QueryResultsIteratorImpl.java | 9 +- .../QueryResultsIteratorWithMetadataImpl.java | 9 +- .../fabric/shim/ledger/CompositeKey.java | 11 +- .../org/hyperledger/fabric/traces/Traces.java | 12 +- .../fabric/traces/TracesProvider.java | 5 +- .../traces/impl/OpenTelemetryProperties.java | 68 +-- .../java/ChaincodeWithoutPackageTest.java | 6 +- .../src/test/java/contract/Greeting.java | 11 +- .../test/java/contract/SampleContract.java | 3 +- .../org/hyperledger/fabric/LoggerTest.java | 8 +- .../org/hyperledger/fabric/LoggingTest.java | 26 +- .../java/org/hyperledger/fabric/TestUtil.java | 3 +- .../fabric/contract/AllTypesAsset.java | 31 +- .../contract/ChaincodeStubNaiveImpl.java | 8 +- .../fabric/contract/ClientIdentityTest.java | 14 +- .../fabric/contract/ContextFactoryTest.java | 6 +- .../fabric/contract/ContextTest.java | 6 +- .../contract/ContractInterfaceTest.java | 13 +- .../fabric/contract/ContractRouterTest.java | 34 +- .../hyperledger/fabric/contract/MyType.java | 4 +- .../contract/TransactionExceptionTest.java | 20 +- .../ContractExecutionServiceTest.java | 12 +- .../JSONTransactionSerializerTest.java | 42 +- .../metadata/MetadataBuilderTest.java | 46 +-- .../contract/metadata/TypeSchemaTest.java | 27 +- .../routing/ContractDefinitionTest.java | 16 +- .../routing/DataTypeDefinitionTest.java | 39 +- .../routing/ParameterDefinitionTest.java | 4 +- .../routing/PropertyDefinitionTest.java | 4 +- .../contract/routing/TxFunctionTest.java | 9 +- .../contract/routing/TypeRegistryTest.java | 8 +- .../simplepath/ContractSimplePathTest.java | 14 +- .../hyperledger/fabric/ledger/LedgerTest.java | 10 +- .../fabric/metrics/MetricsTest.java | 14 +- .../metrics/impl/DefaultProviderTest.java | 16 +- .../fabric/shim/ChaincodeBaseTest.java | 44 +- .../fabric/shim/ChaincodeServerImplTest.java | 2 +- .../fabric/shim/ChaincodeStubTest.java | 13 +- .../fabric/shim/ChaincodeTest.java | 8 +- .../shim/ChatChaincodeWithPeerTest.java | 127 +++--- .../fabric/shim/NettyGrpcServerTest.java | 2 +- .../ext/sbe/StateBasedEndorsementTest.java | 4 +- .../StateBasedEndorsementFactoryTest.java | 6 +- .../impl/StateBasedEndorsementImplTest.java | 8 +- .../fabric/shim/fvt/ChaincodeFVTest.java | 40 +- .../impl/ChaincodeMessageFactoryTest.java | 2 +- .../shim/impl/ChaincodeSupportClientTest.java | 4 +- .../shim/impl/InnvocationTaskManagerTest.java | 2 +- .../shim/impl/InvocationStubImplTest.java | 14 +- .../shim/impl/InvocationTaskManagerTest.java | 16 +- .../shim/impl/KeyModificationImplTest.java | 57 ++- .../fabric/shim/impl/KeyValueImplTest.java | 42 +- ...ryResultsIteratorWithMetadataImplTest.java | 34 +- .../fabric/shim/ledger/CompositeKeyTest.java | 32 +- .../shim/mock/peer/ChaincodeMockPeer.java | 27 +- .../shim/mock/peer/GetHistoryForKeyStep.java | 2 +- .../shim/mock/peer/QueryResultStep.java | 2 +- .../hyperledger/fabric/traces/TracesTest.java | 16 +- .../traces/impl/DefaultProviderTest.java | 4 +- .../impl/OpenTelemetryPropertiesTest.java | 32 +- .../impl/OpenTelemetryTracesProviderTest.java | 10 +- .../traces/impl/TestSpanExporterProvider.java | 2 +- pmd-ruleset.xml | 54 +++ 129 files changed, 1941 insertions(+), 2024 deletions(-) delete mode 100644 ci/checkstyle/checkstyle.xml delete mode 100644 ci/checkstyle/java-copyright-header.txt delete mode 100644 fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java create mode 100644 pmd-ruleset.xml diff --git a/build.gradle b/build.gradle index ec45db35..2540fb8a 100644 --- a/build.gradle +++ b/build.gradle @@ -50,12 +50,13 @@ subprojects { version = rootProject.version java { - sourceCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } compileJava { if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { - options.release = 8 + options.release = 11 } } diff --git a/ci/checkstyle/checkstyle.xml b/ci/checkstyle/checkstyle.xml deleted file mode 100644 index 92b99a49..00000000 --- a/ci/checkstyle/checkstyle.xml +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ci/checkstyle/java-copyright-header.txt b/ci/checkstyle/java-copyright-header.txt deleted file mode 100644 index 5bc18a3d..00000000 --- a/ci/checkstyle/java-copyright-header.txt +++ /dev/null @@ -1,5 +0,0 @@ -^/\*$ -^ \* Copyright \d\d\d\d .*? All Rights Reserved\.$ -^ \*$ -^ \* SPDX-License-Identifier: Apache-2\.0$ -^ \*/$ \ No newline at end of file diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 144af895..25fbde49 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -40,8 +40,8 @@ RUN gradle \ fabric-chaincode-shim:publishToMavenLocal \ -x javadoc \ -x test \ - -x checkstyleMain \ - -x checkstyleTest + -x pmdMain \ + -x pmdTest WORKDIR /root/chaincode-java # Run the Gradle and Maven commands to generate the wrapper variants diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 4162e3ae..42a075f9 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -7,7 +7,12 @@ group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' java { - sourceCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileJava { + options.compilerArgs.addAll(['--release', '11']) } repositories { diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index fc475a98..9740748d 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -7,7 +7,7 @@ - 8 + 11 UTF-8 UTF-8 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 7d5ec564..a4d9619d 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -7,13 +7,12 @@ group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' java { - sourceCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } compileJava { - if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { - options.release = 8 - } + options.compilerArgs.addAll(['--release', '11']) } repositories { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index a57bef8b..79ef721a 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -7,13 +7,12 @@ group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' java { - sourceCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } compileJava { - if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { - options.release = 8 - } + options.compilerArgs.addAll(['--release', '11']) } repositories { diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.jar index bf82ff01c6cdae4a1bb754a6e062954d77ac5c11..7967f30dd1d25fe1b79a4a6e50e2aaa0e425c02c 100644 GIT binary patch delta 53252 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

    &vNik?M&>8{Oc%K{6*Sl5|ig;fC)?_5R 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⩔AYc#;6K^fq;$EQq-nkbqZE%wZDA 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 diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties index dc3affce..9548abd8 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties @@ -6,7 +6,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -14,5 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar +wrapperVersion=3.3.2 +distributionType=bin +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw index 41c0f0c2..5e9618ca 100755 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.3.2 # # Required ENV vars: # ------------------ @@ -27,284 +27,306 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 # MAVEN_SKIP_RC - flag to disable loading of mavenrc files # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then +if [ -z "$MAVEN_SKIP_RC" ]; then - if [ -f /etc/mavenrc ] ; then + if [ -f /usr/local/etc/mavenrc ]; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ]; then . /etc/mavenrc fi - if [ -f "$HOME/.mavenrc" ] ; then + if [ -f "$HOME/.mavenrc" ]; then . "$HOME/.mavenrc" fi fi # OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; +cygwin=false +darwin=false mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi +case "$(uname)" in +CYGWIN*) cygwin=true ;; +MINGW*) mingw=true ;; +Darwin*) + darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="$(/usr/libexec/java_home)" + export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home" + export JAVA_HOME fi - ;; + fi + ;; esac -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` +if [ -z "$JAVA_HOME" ]; then + if [ -r /etc/gentoo-release ]; then + JAVA_HOME=$(java-config --jre-home) fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +if $cygwin; then + [ -n "$JAVA_HOME" ] \ + && JAVA_HOME=$(cygpath --unix "$JAVA_HOME") + [ -n "$CLASSPATH" ] \ + && CLASSPATH=$(cygpath --path --unix "$CLASSPATH") fi # For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if $mingw; then + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \ + && JAVA_HOME="$( + cd "$JAVA_HOME" || ( + echo "cannot cd into $JAVA_HOME." >&2 + exit 1 + ) + pwd + )" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then + if $darwin; then + javaHome="$(dirname "$javaExecutable")" + javaExecutable="$(cd "$javaHome" && pwd -P)/javac" else - javaExecutable="`readlink -f \"$javaExecutable\"`" + javaExecutable="$(readlink -f "$javaExecutable")" fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` + javaHome="$(dirname "$javaExecutable")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') JAVA_HOME="$javaHome" export JAVA_HOME fi fi fi -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then +if [ -z "$JAVACMD" ]; then + if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="$( + \unset -f command 2>/dev/null + \command -v java + )" fi fi -if [ ! -x "$JAVACMD" ] ; then +if [ ! -x "$JAVACMD" ]; then echo "Error: JAVA_HOME is not defined correctly." >&2 echo " We cannot execute $JAVACMD" >&2 exit 1 fi -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +if [ -z "$JAVA_HOME" ]; then + echo "Warning: JAVA_HOME environment variable is not set." >&2 fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" + if [ -z "$1" ]; then + echo "Path not specified to find_maven_basedir" >&2 return 1 fi basedir="$1" wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then + while [ "$wdir" != '/' ]; do + if [ -d "$wdir"/.mvn ]; then basedir=$wdir break fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + wdir=$( + cd "$wdir/.." || exit 1 + pwd + ) fi # end of workaround done - echo "${basedir}" + printf '%s' "$( + cd "$basedir" || exit 1 + pwd + )" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' <"$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") if [ -z "$BASE_DIR" ]; then - exit 1; + exit 1 fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + log "Couldn't find $wrapperJarPath, downloading it ..." + + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + fi + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in wrapperUrl) + wrapperUrl="$safeValue" + break + ;; + esac + done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + + if $cygwin; then + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") + fi + + if command -v wget >/dev/null; then + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" + elif command -v curl >/dev/null; then + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + else + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" + fi fi + fi fi ########################################################################################## # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in wrapperSha256Sum) + wrapperSha256Sum=$value + break + ;; + esac +done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum >/dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi fi + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` + [ -n "$JAVA_HOME" ] \ + && JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") + [ -n "$CLASSPATH" ] \ + && CLASSPATH=$(cygpath --path --windows "$CLASSPATH") + [ -n "$MAVEN_PROJECTBASEDIR" ] \ + && MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd index 86115719..1204076a 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd @@ -1,182 +1,206 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. >&2 +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. >&2 +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. >&2 +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. >&2 +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index e70ceed1..f9e59238 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -7,7 +7,7 @@ - 8 + 11 UTF-8 UTF-8 diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java index b05dbf81..f63dc8b6 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/contractinstall/ContractInstallTest.java @@ -22,7 +22,7 @@ public static void setUp() throws Exception { } @Test - public void TestInstall() { + public void testInstall() { InvokeHelper helper = InvokeHelper.newHelper("baregradlecc", "sachannel"); String text = helper.invoke("org1", "whoami"); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java index ad856978..815ab88c 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/ledgertests/LedgerIntegrationTest.java @@ -23,7 +23,7 @@ public static void setUp() throws Exception { } @Test - public void TestLedgers() { + public void testLedgers() { InvokeHelper helper = InvokeHelper.newHelper("ledgercc", "sachannel"); String text = helper.invoke("org1", "accessLedgers"); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java index 94ebb378..93923ac6 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SACCIntegrationTest.java @@ -22,7 +22,7 @@ public static void setUp() throws Exception { } @Test - public void TestLedger() { + public void testLedger() { InvokeHelper helper = InvokeHelper.newHelper("shimcc", "sachannel"); String text = helper.invoke("org1", "putBulkStates"); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java index 32e8ec56..02ffb16c 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/shimtests/SBECCIntegrationTest.java @@ -22,7 +22,7 @@ public static void setUp() throws Exception { } @Test - public void RunSBE_pub_setget() { + public void runSBE_pub_setget() { final String mode = "pub"; final InvokeHelper helper = InvokeHelper.newHelper("shimcc", "sachannel"); @@ -85,7 +85,7 @@ public void RunSBE_pub_setget() { } @Test - public void RunSBE_priv() { + public void runSBE_priv() { final String mode = "priv"; final InvokeHelper helper = InvokeHelper.newHelper("shimcc", "sachannel"); diff --git a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java index 8483446e..f24f8b82 100644 --- a/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java +++ b/fabric-chaincode-integration-test/src/test/java/org/hyperleder/fabric/shim/integration/util/FabricState.java @@ -9,28 +9,18 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Semaphore; import org.hyperleder.fabric.shim.integration.util.Bash.BashBuilder; public final class FabricState { - private static FabricState state; + private static final FabricState state = new FabricState(); - private static final Map channelStarted = new HashMap<>(); - - // sempaphore to protect access - private static final Semaphore flag = new Semaphore(1); + private boolean started = false; public static FabricState getState() { - if (state == null) { - state = new FabricState(); - } - return state; } - private boolean started = false; - public synchronized void start() { if (!this.started) { diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index b4c50500..5a42b332 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -8,22 +8,18 @@ plugins { id 'maven-publish' id 'jacoco' id 'signing' - id 'checkstyle' + id 'pmd' } -checkstyle { - toolVersion '10.18.1' - configFile file("../ci/checkstyle/checkstyle.xml") - configProperties = [root_dir: file("..") ] -} -checkstyleMain { - source ='src/main/java' -} -checkstyleMain.exclude("**/ChaincodeServerProperties.**") -checkstyleTest { - source ='src/test/java' +pmd { + toolVersion = '7.7.0' + ruleSetFiles = files('../pmd-ruleset.xml') + ruleSets = [] // explicitly set to empty to avoid using the default configuration + ignoreFailures = false } +pmdTest.enabled = false + configurations { runtimeClasspath { resolutionStrategy.activateDependencyLocking() diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java index e1a55c90..35720635 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java @@ -18,7 +18,7 @@ protected Logger(final String name) { super(name, null); // ensure that the parent logger is set - this.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric")); + super.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric")); } /** @@ -45,9 +45,9 @@ public void debug(final String msg) { */ public static Logger getLogger(final Class class1) { // important to add the logger to the log manager - final Logger l = Logger.getLogger(class1.getName()); - LogManager.getLogManager().addLogger(l); - return l; + final Logger result = Logger.getLogger(class1.getName()); + LogManager.getLogManager().addLogger(result); + return result; } /** @param message */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java index 1d26eaf4..0901d75e 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logging.java @@ -7,8 +7,9 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.util.ArrayList; import java.util.Collections; +import java.util.List; +import java.util.Locale; import java.util.logging.Level; import java.util.logging.LogManager; @@ -50,7 +51,7 @@ public static String formatError(final Throwable throwable) { final Throwable cause = throwable.getCause(); if (cause != null) { buffer.append(".. caused by ..").append(System.lineSeparator()); - buffer.append(Logging.formatError(cause)); + buffer.append(formatError(cause)); } return buffer.toString(); @@ -67,11 +68,11 @@ public static void setLogLevel(final String newLevel) { final LogManager logManager = LogManager.getLogManager(); // slightly cumbersome approach - but the loggers don't have a 'get children' // so find those that have the correct stem. - final ArrayList allLoggers = Collections.list(logManager.getLoggerNames()); + final List allLoggers = Collections.list(logManager.getLoggerNames()); allLoggers.add("org.hyperledger"); allLoggers.stream() .filter(name -> name.startsWith("org.hyperledger")) - .map(name -> logManager.getLogger(name)) + .map(logManager::getLogger) .forEach(logger -> { if (logger != null) { logger.setLevel(l); @@ -81,7 +82,7 @@ public static void setLogLevel(final String newLevel) { private static Level mapLevel(final String level) { if (level != null) { - switch (level.toUpperCase().trim()) { + switch (level.toUpperCase(Locale.getDefault()).trim()) { case "ERROR": case "CRITICAL": return Level.SEVERE; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java index 4c10f704..2ce5cbbc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ClientIdentity.java @@ -30,11 +30,11 @@ * and attributes. Such information is useful in enforcing access control by the chaincode. */ public final class ClientIdentity { - private static Logger logger = Logger.getLogger(ContractRouter.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ContractRouter.class.getName()); private final String mspId; private final X509Certificate cert; - private Map attrs; + private final Map attrs; private final String id; // special OID used by Fabric to save attributes in x.509 certificates private static final String FABRIC_CERT_ATTR_OID = "1.2.3.4.5.6.7.8.1"; @@ -47,7 +47,7 @@ public final class ClientIdentity { * @throws JSONException * @throws IOException */ - public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSONException, IOException { + public ClientIdentity(final ChaincodeStub stub) throws CertificateException, IOException { final byte[] signingId = stub.getCreator(); // Create a Serialized Identity protobuf @@ -60,11 +60,12 @@ public ClientIdentity(final ChaincodeStub stub) throws CertificateException, JSO CertificateFactory.getInstance("X509").generateCertificate(new ByteArrayInputStream(idBytes)); this.cert = cert; - this.attrs = new HashMap(); // Get the extension where the identity attributes are stored final byte[] extensionValue = cert.getExtensionValue(FABRIC_CERT_ATTR_OID); if (extensionValue != null) { this.attrs = parseAttributes(extensionValue); + } else { + this.attrs = new HashMap<>(); } // Populate identity @@ -100,7 +101,7 @@ public String getMSPID() { */ private Map parseAttributes(final byte[] extensionValue) throws IOException { - final Map attrMap = new HashMap(); + final Map attrMap = new HashMap<>(); // Create ASN1InputStream from extensionValue try (ByteArrayInputStream inStream = new ByteArrayInputStream(extensionValue); @@ -126,7 +127,7 @@ private Map parseAttributes(final byte[] extensionValue) throws } catch (final JSONException error) { // creating a JSON object failed // decoded extensionValue is not a string containing JSON - logger.error(() -> logger.formatError(error)); + LOGGER.error(() -> LOGGER.formatError(error)); // return empty map } return attrMap; @@ -142,11 +143,7 @@ private Map parseAttributes(final byte[] extensionValue) throws * @return {String | null} Value of the attribute or null if the invoking identity does not possess the attribute. */ public String getAttributeValue(final String attrName) { - if (this.attrs.containsKey(attrName)) { - return this.attrs.get(attrName); - } else { - return null; - } + return this.attrs.getOrDefault(attrName, null); } /** @@ -160,11 +157,7 @@ public String getAttributeValue(final String attrName) { * expected value. Otherwise, returns false. */ public boolean assertAttributeValue(final String attrName, final String attrValue) { - if (!this.attrs.containsKey(attrName)) { - return false; - } else { - return attrValue.equals(this.attrs.get(attrName)); - } + return this.attrs.containsKey(attrName) && attrValue.equals(this.attrs.get(attrName)); } /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java index 64e12a1b..68514adb 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContextFactory.java @@ -10,14 +10,11 @@ /** Factory to create {@link Context} from {@link ChaincodeStub} by wrapping stub with dynamic proxy. */ public final class ContextFactory { - private static ContextFactory cf; + private static final ContextFactory INSTANCE = new ContextFactory(); /** @return ContextFactory */ - public static synchronized ContextFactory getInstance() { - if (cf == null) { - cf = new ContextFactory(); - } - return cf; + public static ContextFactory getInstance() { + return INSTANCE; } /** @@ -25,7 +22,6 @@ public static synchronized ContextFactory getInstance() { * @return Context */ public Context createContext(final ChaincodeStub stub) { - final Context newContext = new Context(stub); - return newContext; + return new Context(stub); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java index c9bea5fc..e1db9de4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractInterface.java @@ -75,7 +75,9 @@ default void unknownTransaction(final Context ctx) { * * @param ctx the context as created by {@link #createContext(ChaincodeStub)}. */ - default void beforeTransaction(final Context ctx) {} + default void beforeTransaction(final Context ctx) { + // Nothing by default + } /** * Invoked once after each transaction. @@ -86,5 +88,7 @@ default void beforeTransaction(final Context ctx) {} * @param result The object returned from the transaction function if any. As this is a Java object and therefore * pass-by-reference it is possible to modify this object. */ - default void afterTransaction(final Context ctx, final Object result) {} + default void afterTransaction(final Context ctx, final Object result) { + // Nothing by default + } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java index 0219f71d..d7b6f9e5 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java @@ -35,7 +35,7 @@ * @see ContractInterface */ public final class ContractRouter extends ChaincodeBase { - private static Logger logger = Logger.getLogger(ContractRouter.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ContractRouter.class.getName()); private final RoutingRegistry registry; private final TypeRegistry typeRegistry; @@ -53,6 +53,7 @@ public final class ContractRouter extends ChaincodeBase { * @param args */ public ContractRouter(final String[] args) { + super(); super.initializeLogging(); super.processEnvironmentOptions(); super.processCommandLineOptions(args); @@ -62,7 +63,7 @@ public ContractRouter(final String[] args) { Metrics.initialize(props); Traces.initialize(props); - logger.fine("ContractRouter"); + LOGGER.fine("ContractRouter"); registry = new RoutingRegistryImpl(); typeRegistry = TypeRegistry.getRegistry(); @@ -72,15 +73,15 @@ public ContractRouter(final String[] args) { serializers.findAndSetContents(); } catch (InstantiationException | IllegalAccessException e) { final ContractRuntimeException cre = new ContractRuntimeException("Unable to locate Serializers", e); - logger.severe(() -> Logging.formatError(cre)); - throw new RuntimeException(cre); + LOGGER.severe(() -> Logging.formatError(cre)); + throw cre; } executor = ExecutionFactory.getInstance().createExecutionService(serializers); } /** Locate all the contracts that are available on the classpath. */ - protected void findAllContracts() { + void findAllContracts() { registry.findAndSetContracts(this.typeRegistry); } @@ -91,28 +92,29 @@ protected void findAllContracts() { * * @throws Exception */ + @SuppressWarnings("PMD.AvoidCatchingGenericException") void startRouting() { try { super.connectToPeer(); } catch (final Exception e) { - logger.severe(() -> Logging.formatError(e)); - final ContractRuntimeException cre = new ContractRuntimeException("Unable to start routing", e); - throw cre; + LOGGER.severe(() -> Logging.formatError(e)); + throw new ContractRuntimeException("Unable to start routing", e); } } + @SuppressWarnings("PMD.AvoidCatchingThrowable") private Response processRequest(final ChaincodeStub stub) { - logger.info(() -> "Got invoke routing request"); + LOGGER.info(() -> "Got invoke routing request"); try { - if (stub.getStringArgs().size() > 0) { - logger.info(() -> "Got the invoke request for:" + stub.getFunction() + " " + stub.getParameters()); - final InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub); - final TxFunction txFn = getRouting(request); - logger.info(() -> "Got routing:" + txFn.getRouting()); - return executor.executeRequest(txFn, request, stub); - } else { + if (stub.getStringArgs().isEmpty()) { return ResponseUtils.newSuccessResponse(); } + + LOGGER.info(() -> "Got the invoke request for:" + stub.getFunction() + " " + stub.getParameters()); + final InvocationRequest request = ExecutionFactory.getInstance().createRequest(stub); + final TxFunction txFn = getRouting(request); + LOGGER.info(() -> "Got routing:" + txFn.getRouting()); + return executor.executeRequest(txFn, request, stub); } catch (final Throwable throwable) { return ResponseUtils.newErrorResponse(throwable); } @@ -139,7 +141,7 @@ TxFunction getRouting(final InvocationRequest request) { if (registry.containsRoute(request)) { return registry.getTxFn(request); } else { - logger.fine(() -> "Namespace is " + request); + LOGGER.fine(() -> "Namespace is " + request); final ContractDefinition contract = registry.getContract(request.getNamespace()); return contract.getUnknownRoute(); } @@ -150,34 +152,35 @@ TxFunction getRouting(final InvocationRequest request) { * * @param args */ + @SuppressWarnings("PMD.SignatureDeclareThrowsException") public static void main(final String[] args) throws Exception { final ContractRouter cfc = new ContractRouter(args); cfc.findAllContracts(); - logger.fine(cfc.getRoutingRegistry().toString()); + LOGGER.fine(() -> cfc.getRoutingRegistry().toString()); // Create the Metadata ahead of time rather than have to produce every // time MetadataBuilder.initialize(cfc.getRoutingRegistry(), cfc.getTypeRegistry()); - logger.info(() -> "Metadata follows:" + MetadataBuilder.debugString()); + LOGGER.info(() -> "Metadata follows:" + MetadataBuilder.debugString()); // check if this should be running in client or server mode if (cfc.isServer()) { - logger.info("Starting chaincode as server"); + LOGGER.info("Starting chaincode as server"); ChaincodeServer chaincodeServer = new NettyChaincodeServer(cfc, cfc.getChaincodeServerConfig()); chaincodeServer.start(); } else { - logger.info("Starting chaincode as client"); + LOGGER.info("Starting chaincode as client"); cfc.startRouting(); } } - protected TypeRegistry getTypeRegistry() { + TypeRegistry getTypeRegistry() { return this.typeRegistry; } - protected RoutingRegistry getRoutingRegistry() { + RoutingRegistry getRoutingRegistry() { return this.registry; } @@ -189,10 +192,10 @@ protected RoutingRegistry getRoutingRegistry() { public void startRouterWithChaincodeServer(final ChaincodeServer chaincodeServer) throws IOException, InterruptedException { findAllContracts(); - logger.fine(getRoutingRegistry().toString()); + LOGGER.fine(() -> getRoutingRegistry().toString()); MetadataBuilder.initialize(getRoutingRegistry(), getTypeRegistry()); - logger.info(() -> "Metadata follows:" + MetadataBuilder.debugString()); + LOGGER.info(() -> "Metadata follows:" + MetadataBuilder.debugString()); chaincodeServer.start(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java index b51c218f..78d559a2 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRuntimeException.java @@ -14,6 +14,8 @@ *

    FUTURE At some future point we wish to add more diagnostic information into this, for example current tx id */ public class ContractRuntimeException extends ChaincodeException { + /** Generated serial version id. */ + private static final long serialVersionUID = -884373036398750450L; /** @param string */ public ContractRuntimeException(final String string) { @@ -32,7 +34,4 @@ public ContractRuntimeException(final String string, final Throwable cause) { public ContractRuntimeException(final Throwable cause) { super(cause); } - - /** Generated serial version id. */ - private static final long serialVersionUID = -884373036398750450L; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java index fee47eb1..3cd7a5fc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionFactory.java @@ -12,14 +12,11 @@ import org.hyperledger.fabric.shim.ChaincodeStub; public class ExecutionFactory { - private static ExecutionFactory rf; + private static final ExecutionFactory INSTANCE = new ExecutionFactory(); /** @return ExecutionFactory */ public static ExecutionFactory getInstance() { - if (rf == null) { - rf = new ExecutionFactory(); - } - return rf; + return INSTANCE; } /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java index c1c99591..ac2e33b9 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java @@ -11,8 +11,6 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.nio.charset.StandardCharsets; -import java.util.Iterator; import java.util.Map; import java.util.Set; import org.hyperledger.fabric.Logger; @@ -26,15 +24,13 @@ import org.json.JSONException; import org.json.JSONObject; -/** Used as a the default serialisation for transmission from SDK to Contract. */ +/** Used as the default serialisation for transmission from SDK to Contract. */ @Serializer() +@SuppressWarnings({"PMD.GodClass", "PMD.AvoidLiteralsInIfCondition", "PMD.AvoidDuplicateLiterals"}) public class JSONTransactionSerializer implements SerializerInterface { - private static Logger logger = Logger.getLogger(JSONTransactionSerializer.class.getName()); + private static final Logger LOGGER = Logger.getLogger(JSONTransactionSerializer.class.getName()); private final TypeRegistry typeRegistry = TypeRegistry.getRegistry(); - /** Create a new serialiser. */ - public JSONTransactionSerializer() {} - /** * Convert the value supplied to a byte array, according to the TypeSchema. * @@ -44,7 +40,7 @@ public JSONTransactionSerializer() {} */ @Override public byte[] toBuffer(final Object value, final TypeSchema ts) { - logger.debug(() -> "Schema to convert is " + ts); + LOGGER.debug(() -> "Schema to convert is " + ts); byte[] buffer = null; if (value != null) { final String type = ts.getType(); @@ -56,7 +52,7 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { break; case "string": final String format = ts.getFormat(); - if (format != null && format.contentEquals("uint16")) { + if ("utin16".equals(format)) { buffer = Character.valueOf((char) value).toString().getBytes(UTF_8); } else { buffer = ((String) value).getBytes(UTF_8); @@ -66,7 +62,7 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { case "integer": case "boolean": default: - buffer = (value).toString().getBytes(UTF_8); + buffer = value.toString().getBytes(UTF_8); } } else { // at this point we can assert that the value is @@ -76,7 +72,7 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { // it should have final DataTypeDefinition dtd = this.typeRegistry.getDataType(ts); final Set keySet = dtd.getProperties().keySet(); - final String[] propNames = keySet.toArray(new String[keySet.size()]); + final String[] propNames = keySet.toArray(new String[0]); // Note: whilst the current JSON library does pretty much // everything is required, this part is hard. @@ -105,6 +101,7 @@ public byte[] toBuffer(final Object value, final TypeSchema ts) { * @param ts Schema to normalise to * @return JSONArray */ + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) { JSONArray normalizedArray; @@ -112,22 +109,12 @@ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) final TypeSchema items = ts.getItems(); final String type = items.getType(); - if (type != null && type != "array") { - // primitive - can return this directly - normalizedArray = jsonArray; - } else if (type != null && type == "array") { - // nested arrays, get the type of what it makes up - // Need to loop over all elements and normalize each one - normalizedArray = new JSONArray(); - for (int i = 0; i < jsonArray.length(); i++) { - normalizedArray.put(i, normalizeArray(jsonArray.getJSONArray(i), items)); - } - } else { + if (null == type) { // get the permitted propeties in the type, // then loop over the array and ensure they are correct final DataTypeDefinition dtd = this.typeRegistry.getDataType(items); final Set keySet = dtd.getProperties().keySet(); - final String[] propNames = keySet.toArray(new String[keySet.size()]); + final String[] propNames = keySet.toArray(new String[0]); normalizedArray = new JSONArray(); // array of objects @@ -136,7 +123,18 @@ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) final JSONObject obj = new JSONObject(jsonArray.getJSONObject(i), propNames); normalizedArray.put(i, obj); } + } else if ("array".equals(type)) { + // nested arrays, get the type of what it makes up + // Need to loop over all elements and normalize each one + normalizedArray = new JSONArray(); + for (int i = 0; i < jsonArray.length(); i++) { + normalizedArray.put(i, normalizeArray(jsonArray.getJSONArray(i), items)); + } + } else { + // primitive - can return this directly + normalizedArray = jsonArray; } + return normalizedArray; } @@ -150,15 +148,10 @@ private JSONArray normalizeArray(final JSONArray jsonArray, final TypeSchema ts) @Override public Object fromBuffer(final byte[] buffer, final TypeSchema ts) { try { - final String stringData = new String(buffer, StandardCharsets.UTF_8); - Object value = null; - - value = convert(stringData, ts); - - return value; + final String stringData = new String(buffer, UTF_8); + return convert(stringData, ts); } catch (InstantiationException | IllegalAccessException e) { - final ContractRuntimeException cre = new ContractRuntimeException(e); - throw cre; + throw new ContractRuntimeException(e); } } @@ -172,102 +165,136 @@ public Object fromBuffer(final byte[] buffer, final TypeSchema ts) { * @return Class for the Object variant */ private Class mapPrimitive(final Class primitive) { - String primitiveType; - final boolean isArray = primitive.isArray(); - if (isArray) { - primitiveType = primitive.getComponentType().getName(); - } else { - primitiveType = primitive.getName(); + if (primitive.isArray()) { + return mapArrayPrimitive(primitive); } - switch (primitiveType) { + return mapBasicPrimitive(primitive); + } + + private Class mapArrayPrimitive(final Class primitive) { + switch (primitive.getComponentType().getName()) { case "int": - return isArray ? Integer[].class : Integer.class; + return Integer[].class; case "long": - return isArray ? Long[].class : Long.class; + return Long[].class; case "float": - return isArray ? Float[].class : Float.class; + return Float[].class; case "double": - return isArray ? Double[].class : Double.class; + return Double[].class; case "short": - return isArray ? Short[].class : Short.class; + return Short[].class; case "byte": - return isArray ? Byte[].class : Byte.class; + return Byte[].class; case "char": - return isArray ? Character[].class : Character.class; + return Character[].class; case "boolean": - return isArray ? Boolean[].class : Boolean.class; + return Boolean[].class; default: return primitive; } } - /* - * Internal method to do the conversion - */ + private Class mapBasicPrimitive(final Class primitive) { + switch (primitive.getName()) { + case "int": + return Integer.class; + case "long": + return Long.class; + case "float": + return Float.class; + case "double": + return Double.class; + case "short": + return Short.class; + case "byte": + return Byte.class; + case "char": + return Character.class; + case "boolean": + return Boolean.class; + default: + return primitive; + } + } + + /** Internal method to do the conversion */ private Object convert(final String stringData, final TypeSchema ts) - throws IllegalArgumentException, IllegalAccessException, InstantiationException { - logger.debug(() -> "Schema to convert is " + ts); + throws IllegalAccessException, InstantiationException { + LOGGER.debug(() -> "Schema to convert is " + ts); + String type = ts.getType(); + String format = null; - Object value = null; if (type == null) { type = "object"; final String ref = ts.getRef(); - format = ref.substring(ref.lastIndexOf("/") + 1); + format = ref.substring(ref.lastIndexOf('/') + 1); } - if (type.contentEquals("string")) { - final String strformat = ts.getFormat(); - if (strformat != null && strformat.contentEquals("uint16")) { - value = stringData.charAt(0); - } else { - value = stringData; - } - } else if (type.contentEquals("integer")) { - final String intFormat = ts.getFormat(); - switch (intFormat) { - case "int32": - value = Integer.parseInt(stringData); - break; - case "int8": - value = Byte.parseByte(stringData); - break; - case "int16": - value = Short.parseShort(stringData); - break; - case "int64": - value = Long.parseLong(stringData); - break; - default: - throw new RuntimeException("Unknown format for integer " + intFormat); - } + switch (type) { + case "string": + return convertString(stringData, ts); + case "integer": + return convertInteger(stringData, ts); + case "number": + return convertNumber(stringData, ts); + case "boolean": + return Boolean.parseBoolean(stringData); + case "object": + return createComponentInstance(format, stringData, ts); + case "array": + return convertArray(stringData, ts); + default: + return null; + } + } - } else if (type.contentEquals("number")) { - final String numFormat = ts.getFormat(); - if (numFormat.contentEquals("float")) { - value = Float.parseFloat(stringData); - } else { - value = Double.parseDouble(stringData); - } - } else if (type.contentEquals("boolean")) { - value = Boolean.parseBoolean(stringData); - } else if (type.contentEquals("object")) { - value = createComponentInstance(format, stringData, ts); - } else if (type.contentEquals("array")) { - final JSONArray jsonArray = new JSONArray(stringData); - final TypeSchema itemSchema = ts.getItems(); - - // note here that the type has to be converted in the case of primitives - final Object[] data = (Object[]) - Array.newInstance(mapPrimitive(itemSchema.getTypeClass(this.typeRegistry)), jsonArray.length()); - for (int i = 0; i < jsonArray.length(); i++) { - final Object convertedData = convert(jsonArray.get(i).toString(), itemSchema); - data[i] = convertedData; - } - value = data; + private Object convertArray(final String stringData, final TypeSchema ts) + throws IllegalAccessException, InstantiationException { + final JSONArray jsonArray = new JSONArray(stringData); + final TypeSchema itemSchema = ts.getItems(); + + // note here that the type has to be converted in the case of primitives + final Object[] data = (Object[]) + Array.newInstance(mapPrimitive(itemSchema.getTypeClass(this.typeRegistry)), jsonArray.length()); + for (int i = 0; i < jsonArray.length(); i++) { + final Object convertedData = convert(jsonArray.get(i).toString(), itemSchema); + data[i] = convertedData; + } + + return data; + } + + private Object convertNumber(final String stringData, final TypeSchema ts) { + if ("float".equals(ts.getFormat())) { + return Float.parseFloat(stringData); + } + + return Double.parseDouble(stringData); + } + + private Object convertInteger(final String stringData, final TypeSchema ts) { + switch (ts.getFormat()) { + case "int32": + return Integer.parseInt(stringData); + case "int8": + return Byte.parseByte(stringData); + case "int16": + return Short.parseShort(stringData); + case "int64": + return Long.parseLong(stringData); + default: + throw new IllegalArgumentException("Unknown format for integer " + ts.getFormat()); + } + } + + private Object convertString(final String stringData, final TypeSchema ts) { + if ("uint16".equals(ts.getFormat())) { + return stringData.charAt(0); } - return value; + + return stringData; } /** @@ -278,6 +305,7 @@ private Object convert(final String stringData, final TypeSchema ts) * @param ts TypeSchema * @return new object */ + @SuppressWarnings("PMD.AvoidAccessibilityAlteration") Object createComponentInstance(final String format, final String jsonString, final TypeSchema ts) { final DataTypeDefinition dtd = this.typeRegistry.getDataType(format); @@ -296,9 +324,7 @@ Object createComponentInstance(final String format, final String jsonString, fin ts.validate(json); try { final Map fields = dtd.getProperties(); - for (final Iterator iterator = fields.values().iterator(); iterator.hasNext(); ) { - final PropertyDefinition prop = iterator.next(); - + for (final PropertyDefinition prop : fields.values()) { final Field f = prop.getField(); f.setAccessible(true); final Object newValue = convert(json.get(prop.getName()).toString(), prop.getSchema()); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java index b8803269..509f60d9 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractExecutionService.java @@ -28,7 +28,7 @@ public class ContractExecutionService implements ExecutionService { - private static Logger logger = Logger.getLogger(ContractExecutionService.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ContractExecutionService.class.getName()); private final SerializerRegistryImpl serializers; @@ -41,7 +41,7 @@ public ContractExecutionService(final SerializerRegistryImpl serializers) { @Override public Chaincode.Response executeRequest( final TxFunction txFn, final InvocationRequest req, final ChaincodeStub stub) { - logger.fine(() -> "Routing Request" + txFn); + LOGGER.fine(() -> "Routing Request" + txFn); final TxFunction.Routing rd = txFn.getRouting(); Chaincode.Response response; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java index a63d2ffc..7a3e0ff3 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java @@ -6,27 +6,36 @@ package org.hyperledger.fabric.contract.execution.impl; -import java.util.Collections; +import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.stream.Collectors; +import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperledger.fabric.contract.execution.InvocationRequest; import org.hyperledger.fabric.shim.ChaincodeStub; -public class ContractInvocationRequest implements InvocationRequest { - private String namespace; - private String method; - private List args = Collections.emptyList(); +public final class ContractInvocationRequest implements InvocationRequest { + @SuppressWarnings("PMD.ProperLogger") // PMD 7.7.0 gives a false positive here + private static final Log LOGGER = LogFactory.getLog(ContractInvocationRequest.class); - private static Log logger = LogFactory.getLog(ContractInvocationRequest.class); + private static final Pattern NS_REGEX = Pattern.compile(":"); + + private final String namespace; + private final String method; + private final List args; /** @param context */ + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") public ContractInvocationRequest(final ChaincodeStub context) { - final String func = - context.getStringArgs().size() > 0 ? context.getStringArgs().get(0) : null; - final String[] funcParts = func.split(":"); - logger.debug(func); + List funcAndArgs = context.getArgs(); + if (funcAndArgs.isEmpty()) { + throw new IllegalArgumentException("Missing function name"); + } + + final String func = new String(funcAndArgs.get(0), StandardCharsets.UTF_8); + LOGGER.debug(func); + + final String[] funcParts = NS_REGEX.split(func); if (funcParts.length == 2) { namespace = funcParts[0]; method = funcParts[1]; @@ -35,8 +44,10 @@ public ContractInvocationRequest(final ChaincodeStub context) { method = funcParts[0]; } - args = context.getArgs().stream().skip(1).collect(Collectors.toList()); - logger.debug(namespace + " " + method + " " + args); + args = funcAndArgs.subList(1, funcAndArgs.size()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(namespace + " " + method + " " + args); + } } /** */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java index c7b5d0c0..e444efa7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/MetadataBuilder.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.io.UncheckedIOException; import java.net.URI; import java.util.ArrayList; import java.util.Collection; @@ -40,16 +41,26 @@ *

    This class is used to build up the JSON structure to be returned as the metadata It is not a store of information, * rather a set of functional data to process to and from metadata json to the internal data structure */ +@SuppressWarnings("PMD.AvoidDuplicateLiterals") public final class MetadataBuilder { - private static Logger logger = Logger.getLogger(MetadataBuilder.class); + private static final Logger LOGGER = Logger.getLogger(MetadataBuilder.class); - private MetadataBuilder() {} + private static final int PADDING = 3; - @SuppressWarnings("serial") - static class MetadataMap extends HashMap { + // Metadata is composed of three primary sections + // each of which is stored in a map + private static Map> contractMap = new HashMap<>(); + private static Map overallInfoMap = new HashMap<>(); + private static Map componentMap = new HashMap<>(); + + // The schema client used to load any other referenced schemas + private static SchemaClient schemaClient = new DefaultSchemaClient(); + + static final class MetadataMap extends HashMap { + private static final long serialVersionUID = 1L; V putIfNotNull(final K key, final V value) { - logger.info(key + " " + value); + LOGGER.info(() -> key + " " + value); if (value != null && !value.toString().isEmpty()) { return put(key, value); } else { @@ -58,14 +69,7 @@ V putIfNotNull(final K key, final V value) { } } - // Metadata is composed of three primary sections - // each of which is stored in a map - private static Map> contractMap = new HashMap<>(); - private static Map overallInfoMap = new HashMap(); - private static Map componentMap = new HashMap(); - - // The schema client used to load any other referenced schemas - private static SchemaClient schemaClient = new DefaultSchemaClient(); + private MetadataBuilder() {} /** * Validation method. @@ -73,7 +77,7 @@ V putIfNotNull(final K key, final V value) { * @throws ValidationException if the metadata is not valid */ public static void validate() { - logger.info("Running schema test validation"); + LOGGER.info("Running schema test validation"); final ClassLoader cl = MetadataBuilder.class.getClassLoader(); try (InputStream contractSchemaInputStream = cl.getResourceAsStream("contract-schema.json"); InputStream jsonSchemaInputStream = cl.getResourceAsStream("json-schema-draft-04-schema.json")) { @@ -88,13 +92,13 @@ public static void validate() { schema.validate(metadata()); } catch (final IOException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } catch (final ValidationException e) { - logger.error(e.getMessage()); + LOGGER.error(e::getMessage); e.getCausingExceptions().stream() .map(ValidationException::getMessage) - .forEach(logger::info); - logger.error(debugString()); + .forEach(LOGGER::info); + LOGGER.error(MetadataBuilder::debugString); throw e; } } @@ -115,8 +119,8 @@ public static void initialize(final RoutingRegistry registry, final TypeRegistry // need to validate that the metadata that has been created is really valid // it should be as it's been created by code, but this is a valuable double // check - logger.info("Validating schema created"); - MetadataBuilder.validate(); + LOGGER.info("Validating schema created"); + validate(); } /** @@ -133,7 +137,7 @@ public static void addComponent(final DataTypeDefinition datatype) { component.put("additionalProperties", false); final Map propertiesMap = datatype.getProperties().entrySet().stream() - .collect(Collectors.toMap(Entry::getKey, e -> (e.getValue().getSchema()))); + .collect(Collectors.toMap(Entry::getKey, e -> e.getValue().getSchema())); component.put("properties", propertiesMap); componentMap.put(datatype.getSimpleName(), component); @@ -145,7 +149,7 @@ public static void addComponent(final DataTypeDefinition datatype) { * @param contractDefinition Class of the object to use as a contract * @return the key that the contract class is referred to in the metadata */ - @SuppressWarnings("serial") + @SuppressWarnings("PMD.LooseCoupling") public static String addContract(final ContractDefinition contractDefinition) { final String key = contractDefinition.getName(); @@ -153,40 +157,34 @@ public static String addContract(final ContractDefinition contractDefinition) { final Contract annotation = contractDefinition.getAnnotation(); final Info info = annotation.info(); - final HashMap infoMap = new HashMap(); + final HashMap infoMap = new HashMap<>(); infoMap.put("title", info.title()); infoMap.put("description", info.description()); infoMap.put("termsOfService", info.termsOfService()); - infoMap.put("contact", new MetadataMap() { - { - putIfNotNull("email", info.contact().email()); - putIfNotNull("name", info.contact().name()); - putIfNotNull("url", info.contact().url()); - } - }); - infoMap.put("license", new MetadataMap() { - { - put("name", info.license().name()); - putIfNotNull("url", info.license().url()); - } - }); + + MetadataMap contact = new MetadataMap<>(); + contact.putIfNotNull("email", info.contact().email()); + contact.putIfNotNull("name", info.contact().name()); + contact.putIfNotNull("url", info.contact().url()); + infoMap.put("contact", contact); + + MetadataMap license = new MetadataMap<>(); + license.put("name", info.license().name()); + license.putIfNotNull("url", info.license().url()); + infoMap.put("license", license); + infoMap.put("version", info.version()); - final HashMap contract = new HashMap(); + final HashMap contract = new HashMap<>(); contract.put("name", key); - contract.put("transactions", new ArrayList()); + contract.put("transactions", new ArrayList<>()); contract.put("info", infoMap); contractMap.put(key, contract); - final boolean defaultContract = true; - if (defaultContract) { - overallInfoMap.putAll(infoMap); - } + overallInfoMap.putAll(infoMap); final Collection fns = contractDefinition.getTxFunctions(); - fns.forEach(txFn -> { - MetadataBuilder.addTransaction(txFn, key); - }); + fns.forEach(txFn -> addTransaction(txFn, key)); return key; } @@ -204,7 +202,7 @@ public static void addTransaction(final TxFunction txFunction, final String cont transaction.put("returns", returnSchema); } - final ArrayList tags = new ArrayList(); + final List tags = new ArrayList<>(); tags.add(txFunction.getType()); if (txFunction.getType() == TransactionType.SUBMIT) { // add deprecated tags tags.add(TransactionType.INVOKE); @@ -216,7 +214,7 @@ public static void addTransaction(final TxFunction txFunction, final String cont @SuppressWarnings("unchecked") final List txs = (ArrayList) contract.get("transactions"); - final ArrayList paramsList = new ArrayList(); + final List paramsList = new ArrayList<>(); txFunction.getParamsList().forEach(pd -> { final TypeSchema paramMap = pd.getSchema(); paramMap.put("name", pd.getName()); @@ -225,7 +223,7 @@ public static void addTransaction(final TxFunction txFunction, final String cont transaction.put("parameters", paramsList); - if (tags.size() != 0) { + if (!tags.isEmpty()) { transaction.put("tags", tags.toArray()); transaction.put("name", txFunction.getName()); txs.add(transaction); @@ -241,8 +239,6 @@ public static String getMetadata() { return metadata().toString(); } - private static final int PADDING = 3; - /** * Returns the metadata as a JSON string (spaced out for humans). * @@ -258,15 +254,14 @@ public static String debugString() { * @return JSONObject of the metadata */ private static JSONObject metadata() { - final HashMap metadata = new HashMap(); + final Map metadata = new HashMap<>(); metadata.put("$schema", "https://fabric-shim.github.io/release-1.4/contract-schema.json"); metadata.put("info", overallInfoMap); metadata.put("contracts", contractMap); metadata.put("components", Collections.singletonMap("schemas", componentMap)); - final JSONObject joMetadata = new JSONObject(metadata); - return joMetadata; + return new JSONObject(metadata); } /** @return All the components indexed by name */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java index 79453428..8b11eccd 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java @@ -9,6 +9,7 @@ import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.everit.json.schema.Schema; import org.everit.json.schema.ValidationException; import org.everit.json.schema.loader.SchemaLoader; @@ -24,12 +25,16 @@ * *

    Does not include the "schema" top level map */ -@SuppressWarnings("serial") +@SuppressWarnings({"PMD.LooseCoupling", "PMD.GodClass"}) public final class TypeSchema extends HashMap { - private static Logger logger = Logger.getLogger(TypeSchema.class.getName()); + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(TypeSchema.class.getName()); - /** */ - public TypeSchema() {} + private static final String SCHEMA_PROP = "schema"; + private static final String TYPE_PROP = "type"; + private static final String ITEMS_PROP = "items"; + private static final String FORMAT_PROP = "format"; + private static final String INTEGER_TYPE = "integer"; private Object putInternal(final String key, final Object value) { if (value != null && !value.toString().isEmpty()) { @@ -57,26 +62,26 @@ TypeSchema[] putIfNotNull(final String key, final TypeSchema[] value) { /** @return Return Type String */ public String getType() { - if (this.containsKey("schema")) { - final Map intermediateMap = (Map) this.get("schema"); - return (String) intermediateMap.get("type"); + if (this.containsKey(SCHEMA_PROP)) { + final Map intermediateMap = (Map) this.get(SCHEMA_PROP); + return (String) intermediateMap.get(TYPE_PROP); } - return (String) this.get("type"); + return (String) this.get(TYPE_PROP); } /** @return TypeSchema items */ public TypeSchema getItems() { - if (this.containsKey("schema")) { - final Map intermediateMap = (Map) this.get("schema"); - return (TypeSchema) intermediateMap.get("items"); + if (this.containsKey(SCHEMA_PROP)) { + final Map intermediateMap = (Map) this.get(SCHEMA_PROP); + return (TypeSchema) intermediateMap.get(ITEMS_PROP); } - return (TypeSchema) this.get("items"); + return (TypeSchema) this.get(ITEMS_PROP); } /** @return Reference */ public String getRef() { - if (this.containsKey("schema")) { - final Map intermediateMap = (Map) this.get("schema"); + if (this.containsKey(SCHEMA_PROP)) { + final Map intermediateMap = (Map) this.get(SCHEMA_PROP); return (String) intermediateMap.get("$ref"); } return (String) this.get("$ref"); @@ -84,11 +89,11 @@ public String getRef() { /** @return Format */ public String getFormat() { - if (this.containsKey("schema")) { - final Map intermediateMap = (Map) this.get("schema"); - return (String) intermediateMap.get("format"); + if (this.containsKey(SCHEMA_PROP)) { + final Map intermediateMap = (Map) this.get(SCHEMA_PROP); + return (String) intermediateMap.get(FORMAT_PROP); } - return (String) this.get("format"); + return (String) this.get(FORMAT_PROP); } /** @@ -96,65 +101,71 @@ public String getFormat() { * @return Class object */ public Class getTypeClass(final TypeRegistry typeRegistry) { - Class clz = null; - String type = getType(); - if (type == null) { - type = "object"; + String type = Optional.ofNullable(getType()).orElse("object"); + + switch (type) { + case "object": + return getObjectClass(typeRegistry); + case "string": + return getStringClass(); + case INTEGER_TYPE: + return getIntegerClass(); + case "number": + return getNumberClass(); + case "boolean": + return boolean.class; + case "array": + return getArrayClass(typeRegistry); + default: + return null; } + } - if (type.contentEquals("string")) { - final String format = getFormat(); - if (format != null && format.contentEquals("uint16")) { - clz = char.class; - } else { - clz = String.class; - } + private Class getArrayClass(final TypeRegistry typeRegistry) { + final TypeSchema typdef = this.getItems(); + final Class arrayType = typdef.getTypeClass(typeRegistry); + return Array.newInstance(arrayType, 0).getClass(); + } - } else if (type.contentEquals("integer")) { - // need to check the format - final String format = getFormat(); - switch (format) { - case "int8": - clz = byte.class; - break; - case "int16": - clz = short.class; - break; - case "int32": - clz = int.class; - break; - case "int64": - clz = long.class; - break; - default: - throw new RuntimeException("Unknown format for integer of " + format); - } - } else if (type.contentEquals("number")) { - // need to check the format - final String format = getFormat(); - switch (format) { - case "double": - clz = double.class; - break; - case "float": - clz = float.class; - break; - default: - throw new RuntimeException("Unknown format for number of " + format); - } - } else if (type.contentEquals("boolean")) { - clz = boolean.class; - } else if (type.contentEquals("object")) { - final String ref = this.getRef(); - final String format = ref.substring(ref.lastIndexOf("/") + 1); - clz = typeRegistry.getDataType(format).getTypeClass(); - } else if (type.contentEquals("array")) { - final TypeSchema typdef = this.getItems(); - final Class arrayType = typdef.getTypeClass(typeRegistry); - clz = Array.newInstance(arrayType, 0).getClass(); + private Class getNumberClass() { + switch (getFormat()) { + case "double": + return double.class; + case "float": + return float.class; + default: + throw new IllegalArgumentException("Unknown format for number of " + getFormat()); + } + } + + private Class getIntegerClass() { + // need to check the format + switch (getFormat()) { + case "int8": + return byte.class; + case "int16": + return short.class; + case "int32": + return int.class; + case "int64": + return long.class; + default: + throw new IllegalArgumentException("Unknown format for integer of " + getFormat()); } + } + + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") + private Class getStringClass() { + if ("uint16".equals(getFormat())) { + return char.class; + } + return String.class; + } - return clz; + private Class getObjectClass(final TypeRegistry typeRegistry) { + final String ref = this.getRef(); + final String format = ref.substring(ref.lastIndexOf('/') + 1); + return typeRegistry.getDataType(format).getTypeClass(); } /** @@ -163,81 +174,86 @@ public Class getTypeClass(final TypeRegistry typeRegistry) { * @param clz * @return TypeSchema */ + @SuppressWarnings({"PMD.ReturnEmptyCollectionRatherThanNull", "PMD.AvoidLiteralsInIfCondition"}) public static TypeSchema typeConvert(final Class clz) { - final TypeSchema returnschema = new TypeSchema(); String className = clz.getTypeName(); - if (className == "void") { + + if ("void".equals(className)) { return null; } - TypeSchema schema; + final TypeSchema result = new TypeSchema(); + TypeSchema schema = result; if (clz.isArray()) { - returnschema.put("type", "array"); + result.put(TYPE_PROP, "array"); + schema = new TypeSchema(); + final Class componentClass = clz.getComponentType(); + className = componentClass.getTypeName(); // double check the componentType - final Class componentClass = clz.getComponentType(); if (componentClass.isArray()) { // nested arrays - returnschema.put("items", TypeSchema.typeConvert(componentClass)); + result.put(ITEMS_PROP, typeConvert(componentClass)); } else { - returnschema.put("items", schema); + result.put(ITEMS_PROP, schema); } - - className = componentClass.getTypeName(); - } else { - schema = returnschema; } + updateSchemaForClass(schema, className); + + return result; + } + + @SuppressWarnings("PMD.CyclomaticComplexity") + private static void updateSchemaForClass(final TypeSchema schema, final String className) { switch (className) { case "java.lang.String": - schema.put("type", "string"); - break; + schema.put(TYPE_PROP, "string"); + return; case "char": case "java.lang.Character": - schema.put("type", "string"); - schema.put("format", "uint16"); - break; + schema.put(TYPE_PROP, "string"); + schema.put(FORMAT_PROP, "uint16"); + return; case "byte": case "java.lang.Byte": - schema.put("type", "integer"); - schema.put("format", "int8"); - break; + schema.put(TYPE_PROP, INTEGER_TYPE); + schema.put(FORMAT_PROP, "int8"); + return; case "short": case "java.lang.Short": - schema.put("type", "integer"); - schema.put("format", "int16"); - break; + schema.put(TYPE_PROP, INTEGER_TYPE); + schema.put(FORMAT_PROP, "int16"); + return; case "int": case "java.lang.Integer": - schema.put("type", "integer"); - schema.put("format", "int32"); - break; + schema.put(TYPE_PROP, INTEGER_TYPE); + schema.put(FORMAT_PROP, "int32"); + return; case "long": case "java.lang.Long": - schema.put("type", "integer"); - schema.put("format", "int64"); - break; + schema.put(TYPE_PROP, INTEGER_TYPE); + schema.put(FORMAT_PROP, "int64"); + return; case "double": case "java.lang.Double": - schema.put("type", "number"); - schema.put("format", "double"); - break; + schema.put(TYPE_PROP, "number"); + schema.put(FORMAT_PROP, "double"); + return; case "float": case "java.lang.Float": - schema.put("type", "number"); - schema.put("format", "float"); - break; + schema.put(TYPE_PROP, "number"); + schema.put(FORMAT_PROP, "float"); + return; case "boolean": case "java.lang.Boolean": - schema.put("type", "boolean"); - break; + schema.put(TYPE_PROP, "boolean"); + return; default: schema.put("$ref", "#/components/schemas/" + className.substring(className.lastIndexOf('.') + 1)); } - - return returnschema; } /** @@ -252,8 +268,8 @@ public void validate(final JSONObject obj) { toValidate.put("prop", obj); JSONObject schemaJSON; - if (this.containsKey("schema")) { - schemaJSON = new JSONObject((Map) this.get("schema")); + if (this.containsKey(SCHEMA_PROP)) { + schemaJSON = new JSONObject((Map) this.get(SCHEMA_PROP)); } else { schemaJSON = new JSONObject(this); } @@ -269,8 +285,9 @@ public void validate(final JSONObject obj) { e.getCausingExceptions().stream() .map(ValidationException::getMessage) .forEach(sb::append); - logger.info(sb.toString()); - throw new ContractRuntimeException(sb.toString(), e); + String message = sb.toString(); + LOGGER.info(message); + throw new ContractRuntimeException(message, e); } } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java index 056b3abc..8df5f3ab 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/ContractDefinitionImpl.java @@ -24,20 +24,20 @@ *

    Contains information about the contract, including transaction functions and unknown transaction routing */ public final class ContractDefinitionImpl implements ContractDefinition { - private static Logger logger = Logger.getLogger(ContractDefinitionImpl.class); + private static final Logger LOGGER = Logger.getLogger(ContractDefinitionImpl.class); private final Map txFunctions = new HashMap<>(); - private String name; + private final String name; private final boolean isDefault; private final Class contractClz; private final Contract contractAnnotation; - private TxFunction unknownTx; + private final TxFunction unknownTx; /** @param cl */ public ContractDefinitionImpl(final Class cl) { final Contract annotation = cl.getAnnotation(Contract.class); - logger.debug(() -> "Class Contract Annotation: " + annotation); + LOGGER.debug(() -> "Class Contract Annotation: " + annotation); final String annotationName = annotation.name(); @@ -52,18 +52,18 @@ public ContractDefinitionImpl(final Class cl) { contractClz = cl; try { - final Method m = cl.getMethod("unknownTransaction", new Class[] {Context.class}); + final Method m = cl.getMethod("unknownTransaction", Context.class); unknownTx = new TxFunctionImpl(m, this); unknownTx.setUnknownTx(true); } catch (NoSuchMethodException | SecurityException e) { final ContractRuntimeException cre = new ContractRuntimeException("Failure to find unknownTransaction method", e); - logger.severe(() -> logger.formatError(cre)); + LOGGER.severe(() -> LOGGER.formatError(cre)); throw cre; } - logger.info(() -> "Found class: " + cl.getCanonicalName()); - logger.debug(() -> "Namespace: " + this.name); + LOGGER.info(() -> "Found class: " + cl.getCanonicalName()); + LOGGER.debug(() -> "Namespace: " + this.name); } @Override @@ -83,13 +83,13 @@ public Class getContractImpl() { @Override public TxFunction addTxFunction(final Method m) { - logger.debug(() -> "Adding method " + m.getName()); + LOGGER.debug(() -> "Adding method " + m.getName()); final TxFunction txFn = new TxFunctionImpl(m, this); final TxFunction previousTxnFn = txFunctions.put(txFn.getName(), txFn); if (previousTxnFn != null) { final String message = String.format("Duplicate transaction method %s", previousTxnFn.getName()); final ContractRuntimeException cre = new ContractRuntimeException(message); - logger.severe(() -> logger.formatError(cre)); + LOGGER.severe(() -> LOGGER.formatError(cre)); throw cre; } return txFn; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java index 5165bfbf..8d1ed867 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/DataTypeDefinitionImpl.java @@ -7,6 +7,7 @@ import java.lang.reflect.Field; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.stream.Stream; import org.hyperledger.fabric.contract.annotation.Property; @@ -22,6 +23,7 @@ public final class DataTypeDefinitionImpl implements DataTypeDefinition { private final Class clazz; /** @param componentClass */ + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public DataTypeDefinitionImpl(final Class componentClass) { this.clazz = componentClass; this.name = componentClass.getName(); @@ -39,7 +41,7 @@ public DataTypeDefinitionImpl(final Class componentClass) { for (int i = 0; i < userSupplied.length; i += 2) { final String userKey = userSupplied[i]; Object userValue; - switch (userKey.toLowerCase()) { + switch (userKey.toLowerCase(Locale.getDefault())) { case "title": case "pattern": userValue = userSupplied[i + 1]; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java index 5996137c..49180d38 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/RoutingRegistryImpl.java @@ -96,8 +96,7 @@ public TxFunction.Routing getRoute(final InvocationRequest request) { @Override public TxFunction getTxFn(final InvocationRequest request) { - final TxFunction txFunction = contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); - return txFunction; + return contracts.get(request.getNamespace()).getTxFunction(request.getMethod()); } /* @@ -145,7 +144,7 @@ public void findAndSetContracts(final TypeRegistry typeRegistry) { final List> dataTypeClasses = new ArrayList<>(); try (ScanResult scanResult = classGraph.scan()) { for (final ClassInfo classInfo : scanResult.getClassesWithAnnotation(Contract.class.getCanonicalName())) { - logger.debug("Found class with contract annotation: " + classInfo.getName()); + logger.debug(() -> "Found class with contract annotation: " + classInfo.getName()); try { final Class contractClass = classInfo.loadClass(); logger.debug("Loaded class"); @@ -155,18 +154,18 @@ public void findAndSetContracts(final TypeRegistry typeRegistry) { // compatible, // and not some random class with the same name. logger.debug("Class does not have compatible contract annotation"); - } else if (!ContractInterface.class.isAssignableFrom(contractClass)) { - logger.debug("Class is not assignable from ContractInterface"); - } else { + } else if (ContractInterface.class.isAssignableFrom(contractClass)) { logger.debug("Class is assignable from ContractInterface"); contractClasses.add((Class) contractClass); + } else { + logger.debug("Class is not assignable from ContractInterface"); } } catch (final IllegalArgumentException e) { - logger.debug("Failed to load class: " + e); + logger.debug(() -> "Failed to load class: " + e); } } for (final ClassInfo classInfo : scanResult.getClassesWithAnnotation(DataType.class.getCanonicalName())) { - logger.debug("Found class with data type annotation: " + classInfo.getName()); + logger.debug(() -> "Found class with data type annotation: " + classInfo.getName()); try { final Class dataTypeClass = classInfo.loadClass(); logger.debug("Loaded class"); @@ -181,7 +180,7 @@ public void findAndSetContracts(final TypeRegistry typeRegistry) { dataTypeClasses.add(dataTypeClass); } } catch (final IllegalArgumentException e) { - logger.debug("Failed to load class: " + e); + logger.debug(() -> "Failed to load class: " + e); } } } @@ -206,7 +205,7 @@ private void addContracts(final List> contractClasses) logger.debug("Searching annotated methods"); for (final Method m : contractClass.getMethods()) { if (m.getAnnotation(Transaction.class) != null) { - logger.debug("Found annotated method " + m.getName()); + logger.debug(() -> "Found annotated method " + m.getName()); contract.addTxFunction(m); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java index 3e7c1f74..728966f0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java @@ -22,13 +22,10 @@ *

    It holds the serializers that have been defined. JSONTransactionSerializer is the default. */ public class SerializerRegistryImpl { - private static Logger logger = Logger.getLogger(SerializerRegistryImpl.class); + private static final Logger LOGGER = Logger.getLogger(SerializerRegistryImpl.class); private final Class annotationClass = Serializer.class; - /** */ - public SerializerRegistryImpl() {} - // Could index these by name and or type. private final Map contents = new HashMap<>(); @@ -45,17 +42,14 @@ public SerializerInterface getSerializer(final String name, final Serializer.TAR } private SerializerInterface add( - final String name, final Serializer.TARGET target, final Class clazz) { - logger.debug(() -> "Adding new Class " + clazz.getCanonicalName() + " for " + target); - try { - final String key = name + ":" + target; - final SerializerInterface newObj = clazz.newInstance(); - this.contents.put(key, newObj); + final String name, final Serializer.TARGET target, final Class clazz) + throws InstantiationException, IllegalAccessException { + LOGGER.debug(() -> "Adding new Class " + clazz.getCanonicalName() + " for " + target); + final String key = name + ":" + target; + final SerializerInterface newObj = clazz.newInstance(); + this.contents.put(key, newObj); - return newObj; - } catch (InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); - } + return newObj; } /** @@ -75,19 +69,14 @@ public void findAndSetContents() throws InstantiationException, IllegalAccessExc try (ScanResult scanResult = classGraph.scan()) { for (final ClassInfo classInfo : scanResult.getClassesWithAnnotation(this.annotationClass.getCanonicalName())) { - logger.debug("Found class with contract annotation: " + classInfo.getName()); - try { - final Class cls = (Class) classInfo.loadClass(); - logger.debug("Loaded class"); - - final String className = cls.getCanonicalName(); - if (!seenClass.contains(className)) { - seenClass.add(className); - this.add(className, Serializer.TARGET.TRANSACTION, cls); - } + LOGGER.debug(() -> "Found class with contract annotation: " + classInfo.getName()); + final Class cls = (Class) classInfo.loadClass(); + LOGGER.debug("Loaded class"); - } catch (final IllegalArgumentException e) { - logger.debug("Failed to load class: " + e); + final String className = cls.getCanonicalName(); + if (!seenClass.contains(className)) { + seenClass.add(className); + this.add(className, Serializer.TARGET.TRANSACTION, cls); } } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java index 3f61350a..26f336f5 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TxFunctionImpl.java @@ -7,9 +7,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; +import java.lang.reflect.Parameter; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.hyperledger.fabric.Logger; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; @@ -23,18 +24,17 @@ import org.hyperledger.fabric.contract.routing.TxFunction; public final class TxFunctionImpl implements TxFunction { - private static Logger logger = Logger.getLogger(TxFunctionImpl.class); + private static final Logger LOGGER = Logger.getLogger(TxFunctionImpl.class); private final Method method; private String name; private TransactionType type; - private TransactionType typeDeprecated; private final Routing routing; private TypeSchema returnSchema; - private List paramsList = new ArrayList<>(); + private List paramsList; private boolean isUnknownTx; - public final class RoutingImpl implements Routing { + public static final class RoutingImpl implements Routing { private final Method method; private final Class clazz; @@ -88,7 +88,7 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { this.method = m; if (m.getAnnotation(Transaction.class) != null) { - logger.debug("Found Transaction method: " + m.getName()); + LOGGER.debug(() -> "Found Transaction method: " + m.getName()); if (m.getAnnotation(Transaction.class).intent() == Transaction.TYPE.SUBMIT) { this.type = TransactionType.SUBMIT; } else { @@ -113,18 +113,18 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { this.returnSchema = TypeSchema.typeConvert(m.getReturnType()); // parameter processing - final List params = - new ArrayList(Arrays.asList(method.getParameters())); + this.paramsList = buildParameters(m); + } + private List buildParameters(final Method m) { + Parameter[] params = m.getParameters(); // validate the first one is a context object - if (params.size() == 0) { + if (params.length == 0) { throw new ContractRuntimeException("First argument should be of type Context"); - } else if (!Context.class.isAssignableFrom(params.get(0).getType())) { - throw new ContractRuntimeException("First argument should be of type Context " + method.getName() + " " - + params.get(0).getType()); - } else { - - params.remove(0); + } + if (!Context.class.isAssignableFrom(params[0].getType())) { + throw new ContractRuntimeException( + "First argument should be of type Context " + m.getName() + " " + params[0].getType()); } // FUTURE: if ever the method of creating the instance where to change, @@ -132,25 +132,27 @@ public TxFunctionImpl(final Method m, final ContractDefinition contract) { // here encapsulating the change. eg use an annotation to define where the // context goes - for (final java.lang.reflect.Parameter parameter : params) { - final TypeSchema paramMap = new TypeSchema(); - final TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); - - final Property annotation = - parameter.getAnnotation(org.hyperledger.fabric.contract.annotation.Property.class); - if (annotation != null) { - final String[] userSupplied = annotation.schema(); - for (int i = 0; i < userSupplied.length; i += 2) { - schema.put(userSupplied[i], userSupplied[i + 1]); - } - } + return Arrays.stream(params) + .skip(1) + .map(TxFunctionImpl::newParameterDefinition) + .collect(Collectors.toList()); + } + + private static ParameterDefinitionImpl newParameterDefinition(final Parameter parameter) { + final TypeSchema paramMap = new TypeSchema(); + final TypeSchema schema = TypeSchema.typeConvert(parameter.getType()); - paramMap.put("name", parameter.getName()); - paramMap.put("schema", schema); - final ParameterDefinition pd = - new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), paramMap, parameter); - paramsList.add(pd); + final Property annotation = parameter.getAnnotation(Property.class); + if (annotation != null) { + final String[] userSupplied = annotation.schema(); + for (int i = 0; i < userSupplied.length; i += 2) { + schema.put(userSupplied[i], userSupplied[i + 1]); + } } + + paramMap.put("name", parameter.getName()); + paramMap.put("schema", schema); + return new ParameterDefinitionImpl(parameter.getName(), parameter.getClass(), paramMap, parameter); } @Override @@ -169,7 +171,7 @@ public Class getReturnType() { } @Override - public java.lang.reflect.Parameter[] getParameters() { + public Parameter[] getParameters() { return method.getParameters(); } @@ -194,7 +196,7 @@ public List getParamsList() { } /** @param paramsList */ - public void setParamsList(final ArrayList paramsList) { + public void setParamsList(final List paramsList) { this.paramsList = paramsList; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java index 07377c77..54d2e995 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/TypeRegistryImpl.java @@ -14,8 +14,9 @@ /** Registry to hold the complex data types as defined in the contract. */ public final class TypeRegistryImpl implements TypeRegistry { + private static final TypeRegistryImpl INSTANCE = new TypeRegistryImpl(); - private static TypeRegistryImpl singletonInstance; + private final Map components = new HashMap<>(); /** * Get the TypeRegistry singleton instance. @@ -23,15 +24,9 @@ public final class TypeRegistryImpl implements TypeRegistry { * @return TypeRegistry */ public static TypeRegistry getInstance() { - if (singletonInstance == null) { - singletonInstance = new TypeRegistryImpl(); - } - - return singletonInstance; + return INSTANCE; } - private final Map components = new HashMap<>(); - /* * (non-Javadoc) * @@ -68,7 +63,7 @@ public DataTypeDefinition getDataType(final String name) { @Override public DataTypeDefinition getDataType(final TypeSchema schema) { final String ref = schema.getRef(); - final String format = ref.substring(ref.lastIndexOf("/") + 1); + final String format = ref.substring(ref.lastIndexOf('/') + 1); return getDataType(format); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java index 74fd07ab..762efe66 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/systemcontract/SystemContract.java @@ -21,16 +21,12 @@ description = "Provides information about the contracts within this container")) public final class SystemContract implements ContractInterface { - /** */ - public SystemContract() {} - /** * @param ctx * @return Metadata */ - @Transaction(submit = false, name = "GetMetadata") + @Transaction(intent = Transaction.TYPE.EVALUATE, name = "GetMetadata") public String getMetadata(final Context ctx) { - final String jsonmetadata = MetadataBuilder.getMetadata(); - return jsonmetadata; + return MetadataBuilder.getMetadata(); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java index 3f9c11cc..1d97ec71 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Ledger.java @@ -33,7 +33,6 @@ public interface Ledger { static Ledger getLedger(final Context ctx) { return new LedgerImpl(ctx); } - ; /** * Return the a collection based on the supplied name. diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java deleted file mode 100644 index c313ef77..00000000 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/CollectionImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2020 IBM All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.ledger.impl; - -import org.hyperledger.fabric.ledger.Collection; - -/** Placeholder. */ -public class CollectionImpl implements Collection { - - private final String name; - - /** - * @param name - * @param ledgerImpl - */ - public CollectionImpl(final String name, final LedgerImpl ledgerImpl) { - this.name = name; - } - - @Override - public void placeholder() { - // TODO Auto-generated method stub - - } -} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java index 9f8ed761..5d204ba2 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java @@ -8,26 +8,27 @@ import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.ledger.Collection; import org.hyperledger.fabric.ledger.Ledger; -import org.hyperledger.fabric.shim.ChaincodeStub; public final class LedgerImpl implements Ledger { - // The Chaincode Stub or SPI to provide access to the underlying Fabric - // APIs - private final ChaincodeStub stub; - /** * New Ledger Implementation. * * @param ctx Context transactional context to use */ + @SuppressWarnings("PMD.UnusedFormalParameter") public LedgerImpl(final Context ctx) { - this.stub = ctx.getStub(); + // Empty stub } @Override public Collection getCollection(final String name) { - return new CollectionImpl(name, this); + return new Collection() { + @Override + public void placeholder() { + // Empty stub + } + }; } @Override diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java index 74cd6247..b13e3708 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/Metrics.java @@ -5,7 +5,6 @@ */ package org.hyperledger.fabric.metrics; -import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.logging.Logger; import org.hyperledger.fabric.metrics.impl.DefaultProvider; @@ -32,6 +31,7 @@ private Metrics() {} * @param props * @return The metrics provide */ + @SuppressWarnings("PMD.AvoidCatchingGenericException") public static MetricsProvider initialize(final Properties props) { if (Boolean.parseBoolean((String) props.get(CHAINCODE_METRICS_ENABLED))) { try { @@ -46,14 +46,8 @@ public static MetricsProvider initialize(final Properties props) { logger.info("Using default metrics provider (logs to org.hyperledger.Performance)"); provider = new DefaultProvider(); } - } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | IllegalArgumentException - | InvocationTargetException - | NoSuchMethodException - | SecurityException e) { - throw new RuntimeException("Unable to start metrics", e); + } catch (Exception e) { + throw new IllegalStateException("Unable to start metrics", e); } } else { // return a 'null' provider diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java index 9609ea87..aa726b96 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/MetricsProvider.java @@ -28,8 +28,9 @@ public interface MetricsProvider { * * @param props */ - default void initialize(final Properties props) {} - ; + default void initialize(final Properties props) { + // Do nothing by default + } /** * Pass a reference to this task service for information gathering. This is related specifically to the handling of @@ -37,6 +38,7 @@ default void initialize(final Properties props) {} * * @param taskService */ - default void setTaskMetricsCollector(final TaskMetricsCollector taskService) {} - ; + default void setTaskMetricsCollector(final TaskMetricsCollector taskService) { + // Do nothing by default + } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java index 841e4164..3f34028d 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/DefaultProvider.java @@ -15,13 +15,14 @@ /** Simple default provider that logs to the org.hyperledger.Performance logger the basic metrics. */ public final class DefaultProvider implements MetricsProvider { - private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); + private static final Logger PERFLOGGER = Logger.getLogger(Logging.PERFLOGGER); + private static final int TIME_INTERVAL = 5000; private TaskMetricsCollector taskService; /** */ public DefaultProvider() { - perflogger.info("Default Metrics Provider started"); + PERFLOGGER.info("Default Metrics Provider started"); } @Override @@ -29,8 +30,6 @@ public void setTaskMetricsCollector(final TaskMetricsCollector taskService) { this.taskService = taskService; } - private static final int TIME_INTERVAL = 5000; - @Override public void initialize(final Properties props) { final Timer metricTimer = new Timer(true); @@ -45,26 +44,22 @@ public void run() { TIME_INTERVAL); } - protected void logMetrics() { - - perflogger.info(() -> { - if (DefaultProvider.this.taskService == null) { + void logMetrics() { + PERFLOGGER.info(() -> { + if (taskService == null) { return "No Metrics Provider service yet"; } - final StringBuilder sb = new StringBuilder(); - sb.append('{'); - sb.append(String.format(" \"active_count\":%d ", DefaultProvider.this.taskService.getActiveCount())) - .append(','); - sb.append(String.format(" \"pool_size\":%d ", DefaultProvider.this.taskService.getPoolSize())) - .append(','); - sb.append(String.format(" \"core_pool_size\":%d ", DefaultProvider.this.taskService.getCorePoolSize())) - .append(','); - sb.append(String.format( - " \"current_task_count\":%d ", DefaultProvider.this.taskService.getCurrentTaskCount())) - .append(','); - sb.append(String.format( - " \"current_queue_depth\":%d ", DefaultProvider.this.taskService.getCurrentQueueCount())); - return sb.append('}').toString(); + return '{' + + String.format(" \"active_count\":%d ", taskService.getActiveCount()) + + ',' + + String.format(" \"pool_size\":%d ", taskService.getPoolSize()) + + ',' + + String.format(" \"core_pool_size\":%d ", taskService.getCorePoolSize()) + + ',' + + String.format(" \"current_task_count\":%d ", taskService.getCurrentTaskCount()) + + ',' + + String.format(" \"current_queue_depth\":%d ", taskService.getCurrentQueueCount()) + + '}'; }); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java index 19639009..35be1fa6 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/metrics/impl/NullProvider.java @@ -8,8 +8,4 @@ import org.hyperledger.fabric.metrics.MetricsProvider; /** Very simple provider that does absolutely nothing. Used when metrics are disabled. */ -public class NullProvider implements MetricsProvider { - - /** */ - public NullProvider() {} -} +public class NullProvider implements MetricsProvider {} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java index b8882487..ca576534 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/Chaincode.java @@ -46,6 +46,7 @@ class Response { * @param message a response message. * @param payload a response payload. */ + @SuppressWarnings("PMD.ArrayIsStoredDirectly") public Response(final Status status, final String message, final byte[] payload) { this.statusCode = status.getCode(); this.message = message; @@ -59,6 +60,7 @@ public Response(final Status status, final String message, final byte[] payload) * @param message a response message. * @param payload a response payload. */ + @SuppressWarnings("PMD.ArrayIsStoredDirectly") public Response(final int statusCode, final String message, final byte[] payload) { this.statusCode = statusCode; this.message = message; @@ -101,6 +103,7 @@ public String getMessage() { * * @return payload bytes. */ + @SuppressWarnings("PMD.MethodReturnsInternalArray") public byte[] getPayload() { return payload; } @@ -164,7 +167,7 @@ public static boolean hasStatusForCode(final int code) { } static { - for (final Status status : Status.values()) { + for (final Status status : values()) { CODETOSTATUS.put(status.code, status); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java index 0ce76bc4..a90e6bda 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java @@ -6,7 +6,6 @@ package org.hyperledger.fabric.shim; -import static java.lang.String.format; import static java.util.logging.Level.ALL; import com.google.protobuf.InvalidProtocolBufferException; @@ -29,6 +28,7 @@ import java.nio.file.Paths; import java.security.Security; import java.util.Base64; +import java.util.Locale; import java.util.Properties; import java.util.logging.Level; import java.util.logging.LogRecord; @@ -56,6 +56,7 @@ * * @see org.hyperledger.fabric.contract */ +@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.GodClass"}) public abstract class ChaincodeBase implements Chaincode { /** */ @@ -64,15 +65,10 @@ public abstract class ChaincodeBase implements Chaincode { /** */ public static final String CORE_CHAINCODE_LOGGING_LEVEL = "CORE_CHAINCODE_LOGGING_LEVEL"; - @Override - public abstract Response init(ChaincodeStub stub); - - @Override - public abstract Response invoke(ChaincodeStub stub); - private static final Logger LOGGER = Logger.getLogger(ChaincodeBase.class.getName()); /** */ + @SuppressWarnings("PMD.AvoidUsingHardCodedIP") public static final String DEFAULT_HOST = "127.0.0.1"; /** */ @@ -83,7 +79,7 @@ public abstract class ChaincodeBase implements Chaincode { private String host = DEFAULT_HOST; private int port = DEFAULT_PORT; - private boolean tlsEnabled = false; + private boolean tlsEnabled; private String tlsClientKeyPath; private String tlsClientCertPath; private String tlsClientKeyFile; @@ -107,11 +103,18 @@ public abstract class ChaincodeBase implements Chaincode { private static final String MAX_INBOUND_MESSAGE_SIZE = "MAX_INBOUND_MESSAGE_SIZE"; private Properties props; private Level logLevel; + private CCState state = CCState.CREATED; static { Security.addProvider(new BouncyCastleProvider()); } + @Override + public abstract Response init(ChaincodeStub stub); + + @Override + public abstract Response invoke(ChaincodeStub stub); + private int getMaxInboundMessageSize() { if (this.props == null) { throw new IllegalStateException("Chaincode config not available"); @@ -129,6 +132,7 @@ private int getMaxInboundMessageSize() { * * @param args command line arguments */ + @SuppressWarnings("PMD.AvoidCatchingGenericException") public void start(final String[] args) { try { initializeLogging(); @@ -188,7 +192,7 @@ protected final void connectToPeer() throws IOException { // has stopped in the peer or the network comms, so also shutdown final StreamObserver requestObserver = chaincodeSupportClient .getStub() - .register(new StreamObserver() { + .register(new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage chaincodeMessage) { // message off to the ITM... @@ -245,7 +249,7 @@ protected StreamObserver connectToPeer(final StreamObserver() { + return new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage chaincodeMessage) { itm.onChaincodeMessage(chaincodeMessage); @@ -273,15 +277,16 @@ protected final void initializeLogging() { "java.util.logging.SimpleFormatter.format", "%1$tH:%1$tM:%1$tS:%1$tL %4$-7.7s %2$-80.80s %5$s%6$s%n"); final Logger rootLogger = Logger.getLogger(""); + var formatter = new SimpleFormatter() { + @Override + public String format(final LogRecord record) { + return Thread.currentThread() + " " + super.format(record); + } + }; + for (final java.util.logging.Handler handler : rootLogger.getHandlers()) { handler.setLevel(ALL); - handler.setFormatter(new SimpleFormatter() { - - @Override - public synchronized String format(final LogRecord record) { - return Thread.currentThread() + " " + super.format(record); - } - }); + handler.setFormatter(formatter); } rootLogger.info("Updated all handlers the format"); @@ -307,7 +312,7 @@ public synchronized String format(final LogRecord record) { private Level mapLevel(final String level) { if (level != null) { - switch (level.toUpperCase().trim()) { + switch (level.toUpperCase(Locale.getDefault()).trim()) { case "CRITICAL": case "ERROR": return Level.SEVERE; @@ -334,7 +339,7 @@ private SocketAddress parseHostPort(final String hostAddrStr) throws URISyntaxEx String host = uri.getHost(); int port = uri.getPort(); - if (uri.getHost() == null || uri.getPort() == -1) { + if (host == null || port == -1) { throw new URISyntaxException(uri.toString(), "URI must have host and port parts"); } @@ -352,28 +357,34 @@ public boolean isServer() { } /** Validate init parameters from env chaincode base. */ + @SuppressWarnings("PMD.CyclomaticComplexity") public void validateOptions() { if (this.id == null || this.id.isEmpty()) { - throw new IllegalArgumentException(format( + throw new IllegalArgumentException(String.format( "The chaincode id must be specified using either the -i or --i command line options or the %s environment variable.", CORE_CHAINCODE_ID_NAME)); } if (this.tlsEnabled) { if (tlsClientCertPath == null) { - throw new IllegalArgumentException( - format("Client key certificate chain (%s) was not specified.", ENV_TLS_CLIENT_CERT_PATH)); + throw new IllegalArgumentException(String.format( + "Client key certificate chain (%s) was not specified.", ENV_TLS_CLIENT_CERT_PATH)); } if (tlsClientKeyPath == null) { throw new IllegalArgumentException( - format("Client key (%s) was not specified.", ENV_TLS_CLIENT_KEY_PATH)); + String.format("Client key (%s) was not specified.", ENV_TLS_CLIENT_KEY_PATH)); } if (tlsClientRootCertPath == null) { - throw new IllegalArgumentException( - format("Peer certificate trust store (%s) was not specified.", CORE_PEER_TLS_ROOTCERT_FILE)); + throw new IllegalArgumentException(String.format( + "Peer certificate trust store (%s) was not specified.", CORE_PEER_TLS_ROOTCERT_FILE)); } } } + @SuppressWarnings({ + "PMD.AvoidLiteralsInIfCondition", + "PMD.AvoidCatchingGenericException", + "PMD.ExceptionAsFlowControl" + }) protected final void processCommandLineOptions(final String[] args) { final Options options = new Options(); options.addOption("a", "peer.address", true, "Address of peer to connect to"); @@ -391,7 +402,7 @@ protected final void processCommandLineOptions(final String[] args) { } final String[] hostArr = hostAddrStr.split(":"); if (hostArr.length == 2) { - port = Integer.valueOf(hostArr[1].trim()); + port = Integer.parseInt(hostArr[1].trim()); host = hostArr[0].trim(); } else { final String msg = String.format( @@ -407,12 +418,13 @@ protected final void processCommandLineOptions(final String[] args) { LOGGER.warning(() -> "cli parsing failed with exception" + Logging.formatError(e)); } - LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>"); - LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id); - LOGGER.info("CORE_PEER_ADDRESS: " + this.host + ":" + this.port); + LOGGER.info(() -> "<<<<<<<<<<<<>>>>>>>>>>>" + "\nCORE_CHAINCODE_ID_NAME: " + + this.id + "\nCORE_PEER_ADDRESS: " + + this.host + ":" + this.port); } /** set fields from env. */ + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") public final void processEnvironmentOptions() { if (System.getenv().containsKey(CORE_CHAINCODE_ID_NAME)) { @@ -421,7 +433,7 @@ public final void processEnvironmentOptions() { if (System.getenv().containsKey(CORE_PEER_ADDRESS)) { final String[] hostArr = System.getenv(CORE_PEER_ADDRESS).split(":"); if (hostArr.length == 2) { - this.port = Integer.valueOf(hostArr[1].trim()); + this.port = Integer.parseInt(hostArr[1].trim()); this.host = hostArr[0].trim(); } else { final String msg = String.format( @@ -449,18 +461,20 @@ public final void processEnvironmentOptions() { this.tlsClientCertFile = System.getenv(ENV_TLS_CLIENT_CERT_FILE); } - LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>"); - LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id); - LOGGER.info("CORE_PEER_ADDRESS: " + this.host); - LOGGER.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled); - LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath); - LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath); - LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath); - LOGGER.info("CORE_TLS_CLIENT_KEY_FILE: " + this.tlsClientKeyFile); - LOGGER.info("CORE_TLS_CLIENT_CERT_FILE: " + this.tlsClientCertFile); - LOGGER.info("CORE_PEER_LOCALMSPID: " + this.localMspId); - LOGGER.info("CHAINCODE_SERVER_ADDRESS: " + this.chaincodeServerAddress); - LOGGER.info("LOGLEVEL: " + this.logLevel); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>"); + LOGGER.info("CORE_CHAINCODE_ID_NAME: " + this.id); + LOGGER.info("CORE_PEER_ADDRESS: " + this.host); + LOGGER.info("CORE_PEER_TLS_ENABLED: " + this.tlsEnabled); + LOGGER.info("CORE_PEER_TLS_ROOTCERT_FILE: " + this.tlsClientRootCertPath); + LOGGER.info("CORE_TLS_CLIENT_KEY_PATH: " + this.tlsClientKeyPath); + LOGGER.info("CORE_TLS_CLIENT_CERT_PATH: " + this.tlsClientCertPath); + LOGGER.info("CORE_TLS_CLIENT_KEY_FILE: " + this.tlsClientKeyFile); + LOGGER.info("CORE_TLS_CLIENT_CERT_FILE: " + this.tlsClientCertFile); + LOGGER.info("CORE_PEER_LOCALMSPID: " + this.localMspId); + LOGGER.info("CHAINCODE_SERVER_ADDRESS: " + this.chaincodeServerAddress); + LOGGER.info("LOGLEVEL: " + this.logLevel); + } } /** @@ -490,7 +504,7 @@ public Properties getChaincodeConfig() { props.setProperty(CORE_PEER_ADDRESS, this.host); LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>"); - LOGGER.info(() -> this.props.toString()); + LOGGER.info(this.props::toString); } return this.props; @@ -646,8 +660,6 @@ public enum CCState { READY } - private CCState state = CCState.CREATED; - /** @return State */ public final CCState getState() { return this.state; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java index 7a4b5312..36ec21cf 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeException.java @@ -62,6 +62,7 @@ public ChaincodeException(final String message, final Throwable cause) { * @param message the detail message. * @param payload the response payload. */ + @SuppressWarnings("PMD.ArrayIsStoredDirectly") public ChaincodeException(final String message, final byte[] payload) { super(message); @@ -75,6 +76,7 @@ public ChaincodeException(final String message, final byte[] payload) { * @param payload the response payload. * @param cause the cause. */ + @SuppressWarnings("PMD.ArrayIsStoredDirectly") public ChaincodeException(final String message, final byte[] payload, final Throwable cause) { super(message, cause); @@ -115,6 +117,7 @@ public ChaincodeException(final String message, final String payload, final Thro * * @return the response payload or {@code null} if there is no response. */ + @SuppressWarnings("PMD.MethodReturnsInternalArray") public byte[] getPayload() { return payload; } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java index af81bfb7..4352fe14 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java @@ -9,21 +9,23 @@ public final class ChaincodeServerProperties { private SocketAddress serverAddress; - private int maxInboundMetadataSize = 100 * 1024 * 1024; // checkstyle:ignore-line:MagicNumber - private int maxInboundMessageSize = 100 * 1024 * 1024; // checkstyle:ignore-line:MagicNumber - private int maxConnectionAgeSeconds = 5; // checkstyle:ignore-line:MagicNumber - private int keepAliveTimeoutSeconds = 20; // checkstyle:ignore-line:MagicNumber - private int permitKeepAliveTimeMinutes = 1; // checkstyle:ignore-line:MagicNumber - private int keepAliveTimeMinutes = 1; // checkstyle:ignore-line:MagicNumber + private int maxInboundMetadataSize = 100 * 1024 * 1024; + private int maxInboundMessageSize = 100 * 1024 * 1024; + private int maxConnectionAgeSeconds = 5; + private int keepAliveTimeoutSeconds = 20; + private int permitKeepAliveTimeMinutes = 1; + private int keepAliveTimeMinutes = 1; private boolean permitKeepAliveWithoutCalls = true; private String keyPassword; private String keyCertChainFile; private String keyFile; private String trustCertCollectionFile; - private boolean tlsEnabled = false; + private boolean tlsEnabled; /** Constructor using default configuration. */ - public ChaincodeServerProperties() {} + public ChaincodeServerProperties() { + // Nothing to do + } /** * Constructor. @@ -39,7 +41,7 @@ public ChaincodeServerProperties() {} * @param permitKeepAliveWithoutCalls whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are * no outstanding RPCs on the connection. */ - // checkstyle:ignore-next-line:ParameterNumber + @SuppressWarnings({"PMD.UnusedFormalParameter", "PMD.NullAssignment"}) public ChaincodeServerProperties( final int portChaincodeServer, final int maxInboundMetadataSize, @@ -174,6 +176,7 @@ public void setKeepAliveTimeMinutes(final int keepAliveTimeMinutes) { * * @return true if clients are allowed to send keep-alive requests without calls; otherwise false. */ + @SuppressWarnings("PMD.BooleanGetMethodName") public boolean getPermitKeepAliveWithoutCalls() { return permitKeepAliveWithoutCalls; } @@ -311,6 +314,7 @@ public void setTlsEnabled(final boolean tlsEnabled) { * * @throws IllegalArgumentException if any properties are not valid. */ + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void validate() { if (this.getServerAddress() == null) { throw new IllegalArgumentException("chaincodeServerProperties.getServerAddress() must be set"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java index 8c223fc4..63a5fab4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeStub.java @@ -26,6 +26,7 @@ * An object which manages the transaction context, provides access to state variables, and supports calls to other * chaincode implementations. */ +@SuppressWarnings("PMD.ExcessivePublicCount") public interface ChaincodeStub { /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java index f53d0ad1..c6df3d0f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeer.java @@ -15,9 +15,10 @@ public class ChatChaincodeWithPeer extends ChaincodeGrpc.ChaincodeImplBase { private static Logger logger = Logger.getLogger(ChatChaincodeWithPeer.class.getName()); - private ChaincodeBase chaincodeBase; + private final ChaincodeBase chaincodeBase; ChatChaincodeWithPeer(final ChaincodeBase chaincodeBase) throws IOException { + super(); if (chaincodeBase == null) { throw new IOException("chaincodeBase can't be null"); } @@ -34,6 +35,7 @@ public class ChatChaincodeWithPeer extends ChaincodeGrpc.ChaincodeImplBase { * @return */ @Override + @SuppressWarnings("PMD.AvoidCatchingGenericException") public StreamObserver connect(final StreamObserver responseObserver) { if (responseObserver == null) { return null; diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java index df594ed2..14679384 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyChaincodeServer.java @@ -33,12 +33,14 @@ public NettyChaincodeServer( * @throws IOException problem while start grpc server * @throws InterruptedException thrown when block and awaiting shutdown gprc server */ + @Override public void start() throws IOException, InterruptedException { grpcServer.start(); grpcServer.blockUntilShutdown(); } /** shutdown now grpc server. */ + @Override public void stop() { grpcServer.stop(); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java index bb142337..00e7c2ac 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/NettyGrpcServer.java @@ -16,7 +16,9 @@ import java.io.IOException; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; +import java.util.logging.Level; import java.util.logging.Logger; +import javax.net.ssl.SSLException; /** implementation grpc server with NettyGrpcServer. */ public final class NettyGrpcServer implements GrpcServer { @@ -54,67 +56,76 @@ public NettyGrpcServer(final ChaincodeBase chaincodeBase, final ChaincodeServerP .maxInboundMessageSize(chaincodeServerProperties.getMaxInboundMessageSize()); if (chaincodeServerProperties.isTlsEnabled()) { - final File keyCertChainFile = - Paths.get(chaincodeServerProperties.getKeyCertChainFile()).toFile(); - final File keyFile = - Paths.get(chaincodeServerProperties.getKeyFile()).toFile(); - - SslContextBuilder sslContextBuilder; - if (chaincodeServerProperties.getKeyPassword() == null - || chaincodeServerProperties.getKeyPassword().isEmpty()) { - sslContextBuilder = SslContextBuilder.forServer(keyCertChainFile, keyFile); - } else { - sslContextBuilder = SslContextBuilder.forServer( - keyCertChainFile, keyFile, chaincodeServerProperties.getKeyPassword()); - } - - ApplicationProtocolConfig apn = new ApplicationProtocolConfig( - ApplicationProtocolConfig.Protocol.ALPN, - ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, - ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, - ApplicationProtocolNames.HTTP_2); - sslContextBuilder.applicationProtocolConfig(apn); - - if (chaincodeServerProperties.getTrustCertCollectionFile() != null) { - final File trustCertCollectionFile = Paths.get(chaincodeServerProperties.getTrustCertCollectionFile()) - .toFile(); - sslContextBuilder.clientAuth(ClientAuth.REQUIRE); - sslContextBuilder.trustManager(trustCertCollectionFile); - } - - serverBuilder.sslContext(sslContextBuilder.build()); + configureTls(serverBuilder, chaincodeServerProperties); } - LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>:\n"); - LOGGER.info( - "ServerAddress:" + chaincodeServerProperties.getServerAddress().toString()); - LOGGER.info("MaxInboundMetadataSize:" + chaincodeServerProperties.getMaxInboundMetadataSize()); - LOGGER.info("MaxInboundMessageSize:" + chaincodeServerProperties.getMaxInboundMessageSize()); - LOGGER.info("MaxConnectionAgeSeconds:" + chaincodeServerProperties.getMaxConnectionAgeSeconds()); - LOGGER.info("KeepAliveTimeoutSeconds:" + chaincodeServerProperties.getKeepAliveTimeoutSeconds()); - LOGGER.info("PermitKeepAliveTimeMinutes:" + chaincodeServerProperties.getPermitKeepAliveTimeMinutes()); - LOGGER.info("KeepAliveTimeMinutes:" + chaincodeServerProperties.getKeepAliveTimeMinutes()); - LOGGER.info("PermitKeepAliveWithoutCalls:" + chaincodeServerProperties.getPermitKeepAliveWithoutCalls()); - LOGGER.info("KeyPassword:" + chaincodeServerProperties.getKeyPassword()); - LOGGER.info("KeyCertChainFile:" + chaincodeServerProperties.getKeyCertChainFile()); - LOGGER.info("KeyFile:" + chaincodeServerProperties.getKeyFile()); - LOGGER.info("isTlsEnabled:" + chaincodeServerProperties.isTlsEnabled()); - LOGGER.info("\n"); + if (LOGGER.isLoggable(Level.INFO)) { + LOGGER.info("<<<<<<<<<<<<>>>>>>>>>>>:\n"); + LOGGER.info("ServerAddress:" + + chaincodeServerProperties.getServerAddress().toString()); + LOGGER.info("MaxInboundMetadataSize:" + chaincodeServerProperties.getMaxInboundMetadataSize()); + LOGGER.info("MaxInboundMessageSize:" + chaincodeServerProperties.getMaxInboundMessageSize()); + LOGGER.info("MaxConnectionAgeSeconds:" + chaincodeServerProperties.getMaxConnectionAgeSeconds()); + LOGGER.info("KeepAliveTimeoutSeconds:" + chaincodeServerProperties.getKeepAliveTimeoutSeconds()); + LOGGER.info("PermitKeepAliveTimeMinutes:" + chaincodeServerProperties.getPermitKeepAliveTimeMinutes()); + LOGGER.info("KeepAliveTimeMinutes:" + chaincodeServerProperties.getKeepAliveTimeMinutes()); + LOGGER.info("PermitKeepAliveWithoutCalls:" + chaincodeServerProperties.getPermitKeepAliveWithoutCalls()); + LOGGER.info("KeyPassword:" + chaincodeServerProperties.getKeyPassword()); + LOGGER.info("KeyCertChainFile:" + chaincodeServerProperties.getKeyCertChainFile()); + LOGGER.info("KeyFile:" + chaincodeServerProperties.getKeyFile()); + LOGGER.info("isTlsEnabled:" + chaincodeServerProperties.isTlsEnabled()); + LOGGER.info("\n"); + } this.server = serverBuilder.build(); } + private static void configureTls( + final NettyServerBuilder serverBuilder, final ChaincodeServerProperties chaincodeServerProperties) + throws SSLException { + final File keyCertChainFile = + Paths.get(chaincodeServerProperties.getKeyCertChainFile()).toFile(); + final File keyFile = Paths.get(chaincodeServerProperties.getKeyFile()).toFile(); + + final SslContextBuilder sslContextBuilder; + if (chaincodeServerProperties.getKeyPassword() == null + || chaincodeServerProperties.getKeyPassword().isEmpty()) { + sslContextBuilder = SslContextBuilder.forServer(keyCertChainFile, keyFile); + } else { + sslContextBuilder = + SslContextBuilder.forServer(keyCertChainFile, keyFile, chaincodeServerProperties.getKeyPassword()); + } + + ApplicationProtocolConfig apn = new ApplicationProtocolConfig( + ApplicationProtocolConfig.Protocol.ALPN, + ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE, + ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT, + ApplicationProtocolNames.HTTP_2); + sslContextBuilder.applicationProtocolConfig(apn); + + if (chaincodeServerProperties.getTrustCertCollectionFile() != null) { + final File trustCertCollectionFile = Paths.get(chaincodeServerProperties.getTrustCertCollectionFile()) + .toFile(); + sslContextBuilder.clientAuth(ClientAuth.REQUIRE); + sslContextBuilder.trustManager(trustCertCollectionFile); + } + + serverBuilder.sslContext(sslContextBuilder.build()); + } + /** * start grpc server. * * @throws IOException */ + @SuppressWarnings("PMD.SystemPrintln") + @Override public void start() throws IOException { LOGGER.info("start grpc server"); Runtime.getRuntime().addShutdownHook(new Thread(() -> { // Use stderr here since the logger may have been reset by its JVM shutdown hook. System.err.println("*** shutting down gRPC server since JVM is shutting down"); - NettyGrpcServer.this.stop(); + stop(); System.err.println("*** server shut down"); })); server.start(); @@ -125,12 +136,14 @@ public void start() throws IOException { * * @throws InterruptedException */ + @Override public void blockUntilShutdown() throws InterruptedException { LOGGER.info("Waits for the server to become terminated."); server.awaitTermination(); } /** shutdown now grpc server. */ + @Override public void stop() { LOGGER.info("shutdown now grpc server."); server.shutdownNow(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java index bd6ee06e..ab7419fa 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ResponseUtils.java @@ -85,15 +85,12 @@ public static Chaincode.Response newErrorResponse(final Throwable throwable) { // logged logger.error(() -> logger.formatError(throwable)); - String message = null; - byte[] payload = null; if (throwable instanceof ChaincodeException) { - message = throwable.getMessage(); - payload = ((ChaincodeException) throwable).getPayload(); + String message = throwable.getMessage(); + byte[] payload = ((ChaincodeException) throwable).getPayload(); return new Chaincode.Response(INTERNAL_SERVER_ERROR, message, payload); - } else { - message = "Unexpected error"; - return ResponseUtils.newErrorResponse(message, payload); } + + return newErrorResponse("Unexpected error", null); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java index c390ef90..df22a7b9 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsement.java @@ -48,12 +48,21 @@ public interface StateBasedEndorsement { List listOrgs(); /** RoleType of an endorsement policy's identity. */ + @SuppressWarnings("PMD.FieldNamingConventions") enum RoleType { /** RoleTypeMember identifies an org's member identity. */ RoleTypeMember("MEMBER"), /** RoleTypePeer identifies an org's peer identity. */ RoleTypePeer("PEER"); + private static final Map reverseLookup = new HashMap<>(); + + static { + for (final RoleType item : values()) { + reverseLookup.put(item.getVal(), item); + } + } + private final String val; RoleType(final String val) { @@ -65,14 +74,6 @@ public String getVal() { return val; } - private static Map reverseLookup = new HashMap<>(); - - static { - for (final RoleType item : RoleType.values()) { - reverseLookup.put(item.getVal(), item); - } - } - /** * @param val * @return RoleType diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java index f93fc6ce..9a040a59 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactory.java @@ -9,14 +9,11 @@ /** Factory for {@link StateBasedEndorsement} objects. */ public class StateBasedEndorsementFactory { - private static StateBasedEndorsementFactory instance; + private static final StateBasedEndorsementFactory INSTANCE = new StateBasedEndorsementFactory(); /** @return Endorsement Factory */ - public static synchronized StateBasedEndorsementFactory getInstance() { - if (instance == null) { - instance = new StateBasedEndorsementFactory(); - } - return instance; + public static StateBasedEndorsementFactory getInstance() { + return INSTANCE; } /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java index 68a67369..1226a3cb 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java @@ -23,7 +23,8 @@ /** Implements {@link StateBasedEndorsement}. */ public final class StateBasedEndorsementImpl implements StateBasedEndorsement { - private static Log logger = LogFactory.getLog(StateBasedEndorsementImpl.class); + @SuppressWarnings("PMD.ProperLogger") // PMD 7.7.0 reports a false positive + private static final Log LOGGER = LogFactory.getLog(StateBasedEndorsementImpl.class); private final Map orgs = new HashMap<>(); @@ -86,7 +87,7 @@ private void addOrg(final MSPPrincipal identity) { final MSPRole mspRole = MSPRole.parseFrom(identity.getPrincipal()); orgs.put(mspRole.getMspIdentifier(), mspRole.getRole()); } catch (final InvalidProtocolBufferException e) { - logger.warn("error unmarshalling msp principal"); + LOGGER.warn("error unmarshalling msp principal"); throw new IllegalArgumentException("error unmarshalling msp principal", e); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java index b2c3c916..1f502b36 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java @@ -13,11 +13,14 @@ import com.google.protobuf.InvalidProtocolBufferException; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; +import java.security.NoSuchAlgorithmException; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.logging.Logger; import org.hyperledger.fabric.Logging; +import org.hyperledger.fabric.contract.ContractRuntimeException; import org.hyperledger.fabric.protos.peer.ChaincodeMessage; import org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type; import org.hyperledger.fabric.shim.Chaincode; @@ -25,10 +28,11 @@ import org.hyperledger.fabric.traces.Traces; /** A 'Callable' implementation the has the job of invoking the chaincode, and matching the response and requests. */ +@SuppressWarnings("PMD.MoreThanOneLogger") public class ChaincodeInvocationTask implements Callable { - private static Logger logger = Logger.getLogger(ChaincodeInvocationTask.class.getName()); - private static Logger perfLogger = Logger.getLogger(Logging.PERFLOGGER); + private static final Logger LOGGER = Logger.getLogger(ChaincodeInvocationTask.class.getName()); + private static final Logger PERFLOGGER = Logger.getLogger(Logging.PERFLOGGER); private final String key; private final Type type; @@ -40,7 +44,7 @@ public class ChaincodeInvocationTask implements Callable { // up if there's no body waiting. // // Usual case should be the main thread is waiting for something to come back - private final ArrayBlockingQueue postbox = new ArrayBlockingQueue<>(2, true); + private final BlockingQueue postbox = new ArrayBlockingQueue<>(2, true); private final ChaincodeMessage message; private final Chaincode chaincode; @@ -67,13 +71,14 @@ public ChaincodeInvocationTask( /** Main method to power the invocation of the chaincode. */ @Override + @SuppressWarnings("PMD.AvoidCatchingGenericException") public ChaincodeMessage call() { ChaincodeMessage finalResponseMessage; Span span = null; try { try { - perfLogger.fine(() -> "> task:start TX::" + this.txId); + PERFLOGGER.fine(() -> "> task:start TX::" + this.txId); // A key interface for the chaincode's invoke() method implementation // is the 'ChaincodeStub' interface. An instance of this is created @@ -87,7 +92,7 @@ public ChaincodeMessage call() { // result is what will be sent to the peer as a response to this invocation final Chaincode.Response result; - perfLogger.fine(() -> "> task:invoke TX::" + this.txId); + PERFLOGGER.fine(() -> "> task:invoke TX::" + this.txId); // Call chaincode's invoke // Note in Fabric v2, there won't be any INIT @@ -97,11 +102,11 @@ public ChaincodeMessage call() { result = chaincode.invoke(stub); } - perfLogger.fine(() -> "< task:invoke TX::" + this.txId); + PERFLOGGER.fine(() -> "< task:invoke TX::" + this.txId); if (result.getStatus().getCode() >= Chaincode.Response.Status.INTERNAL_SERVER_ERROR.getCode()) { // Send ERROR with entire result.Message as payload - logger.severe(() -> String.format( + LOGGER.severe(() -> String.format( "[%-8.8s] Invoke failed with error code %d. Sending %s", message.getTxid(), result.getStatus().getCode(), ERROR)); finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage( @@ -111,14 +116,14 @@ public ChaincodeMessage call() { } } else { // Send COMPLETED with entire result as payload - logger.fine( + LOGGER.fine( () -> String.format("[%-8.8s] Invoke succeeded. Sending %s", message.getTxid(), COMPLETED)); finalResponseMessage = ChaincodeMessageFactory.newCompletedEventMessage( message.getChannelId(), message.getTxid(), result, stub.getEvent()); } - } catch (InvalidProtocolBufferException | RuntimeException e) { - logger.severe( + } catch (InvalidProtocolBufferException | NoSuchAlgorithmException | RuntimeException e) { + LOGGER.severe( () -> String.format("[%-8.8s] Invoke failed. Sending %s: %s", message.getTxid(), ERROR, e)); finalResponseMessage = ChaincodeMessageFactory.newErrorEventMessage(message.getChannelId(), message.getTxid(), e); @@ -129,7 +134,7 @@ public ChaincodeMessage call() { // send the final response message to the peer outgoingMessageConsumer.accept(finalResponseMessage); - perfLogger.fine(() -> "< task:end TX::" + this.txId); + PERFLOGGER.fine(() -> "< task:end TX::" + this.txId); } finally { if (span != null) { span.end(); @@ -151,11 +156,22 @@ public String getTxKey() { /** * Use the Key as to determine equality. * - * @param task + * @param other * @return equality */ - public boolean equals(final ChaincodeInvocationTask task) { - return key.equals(task.getTxKey()); + @Override + public boolean equals(final Object other) { + if (!(other instanceof ChaincodeInvocationTask)) { + return false; + } + + ChaincodeInvocationTask that = (ChaincodeInvocationTask) other; + return this.key.equals(that.getTxKey()); + } + + @Override + public int hashCode() { + return key.hashCode(); } /** @@ -190,33 +206,33 @@ public void postMessage(final ChaincodeMessage msg) throws InterruptedException protected ByteString invoke(final ChaincodeMessage message) { // send the message - logger.fine(() -> "Task Sending message to the peer " + message.getTxid()); + LOGGER.fine(() -> "Task Sending message to the peer " + message.getTxid()); outgoingMessageConsumer.accept(message); // wait for response ChaincodeMessage response; try { - perfLogger.fine(() -> "> task:answer TX::" + message.getTxid()); + PERFLOGGER.fine(() -> "> task:answer TX::" + message.getTxid()); response = postbox.take(); - perfLogger.fine(() -> "< task:answer TX::" + message.getTxid()); + PERFLOGGER.fine(() -> "< task:answer TX::" + message.getTxid()); } catch (final InterruptedException e) { - logger.severe(() -> "Interrupted exchanging messages "); - throw new RuntimeException(String.format("[%-8.8s]InterruptedException received.", txId), e); + LOGGER.severe(() -> "Interrupted exchanging messages "); + throw new ContractRuntimeException(String.format("[%-8.8s]InterruptedException received.", txId), e); } // handle response switch (response.getType()) { case RESPONSE: - logger.fine(() -> String.format("[%-8.8s] Successful response received.", txId)); + LOGGER.fine(() -> String.format("[%-8.8s] Successful response received.", txId)); return response.getPayload(); case ERROR: - logger.severe(() -> String.format("[%-8.8s] Unsuccessful response received.", txId)); - throw new RuntimeException(String.format("[%-8.8s]Unsuccessful response received.", txId)); + LOGGER.severe(() -> String.format("[%-8.8s] Unsuccessful response received.", txId)); + throw new ContractRuntimeException(String.format("[%-8.8s]Unsuccessful response received.", txId)); default: - logger.severe(() -> String.format( + LOGGER.severe(() -> String.format( "[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, response.getType(), RESPONSE, ERROR)); - throw new RuntimeException(String.format( + throw new IllegalStateException(String.format( "[%-8.8s] Unexpected %s response received. Expected %s or %s.", txId, response.getType(), RESPONSE, ERROR)); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java index 651bc81a..199a1b75 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactory.java @@ -37,7 +37,7 @@ public final class ChaincodeMessageFactory { private ChaincodeMessageFactory() {} - protected static ChaincodeMessage newGetPrivateDataHashEventMessage( + static ChaincodeMessage newGetPrivateDataHashEventMessage( final String channelId, final String txId, final String collection, final String key) { return newEventMessage( GET_PRIVATE_DATA_HASH, @@ -50,7 +50,7 @@ protected static ChaincodeMessage newGetPrivateDataHashEventMessage( .toByteString()); } - protected static ChaincodeMessage newGetStateEventMessage( + static ChaincodeMessage newGetStateEventMessage( final String channelId, final String txId, final String collection, final String key) { return newEventMessage( GET_STATE, @@ -63,7 +63,7 @@ protected static ChaincodeMessage newGetStateEventMessage( .toByteString()); } - protected static ChaincodeMessage newGetStateMetadataEventMessage( + static ChaincodeMessage newGetStateMetadataEventMessage( final String channelId, final String txId, final String collection, final String key) { return newEventMessage( GET_STATE_METADATA, @@ -76,7 +76,7 @@ protected static ChaincodeMessage newGetStateMetadataEventMessage( .toByteString()); } - protected static ChaincodeMessage newPutStateEventMessage( + static ChaincodeMessage newPutStateEventMessage( final String channelId, final String txId, final String collection, @@ -94,7 +94,7 @@ protected static ChaincodeMessage newPutStateEventMessage( .toByteString()); } - protected static ChaincodeMessage newPutStateMetadataEventMessage( + static ChaincodeMessage newPutStateMetadataEventMessage( final String channelId, final String txId, final String collection, @@ -116,7 +116,7 @@ protected static ChaincodeMessage newPutStateMetadataEventMessage( .toByteString()); } - protected static ChaincodeMessage newDeleteStateEventMessage( + static ChaincodeMessage newDeleteStateEventMessage( final String channelId, final String txId, final String collection, final String key) { return newEventMessage( DEL_STATE, @@ -129,7 +129,7 @@ protected static ChaincodeMessage newDeleteStateEventMessage( .toByteString()); } - protected static ChaincodeMessage newPurgeStateEventMessage( + static ChaincodeMessage newPurgeStateEventMessage( final String channelId, final String txId, final String collection, final String key) { return newEventMessage( Type.PURGE_PRIVATE_DATA, @@ -142,46 +142,43 @@ protected static ChaincodeMessage newPurgeStateEventMessage( .toByteString()); } - protected static ChaincodeMessage newErrorEventMessage( - final String channelId, final String txId, final Throwable throwable) { + static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final Throwable throwable) { return newErrorEventMessage(channelId, txId, printStackTrace(throwable)); } - protected static ChaincodeMessage newErrorEventMessage( - final String channelId, final String txId, final String message) { + static ChaincodeMessage newErrorEventMessage(final String channelId, final String txId, final String message) { return newErrorEventMessage(channelId, txId, message, null); } - protected static ChaincodeMessage newErrorEventMessage( + static ChaincodeMessage newErrorEventMessage( final String channelId, final String txId, final String message, final ChaincodeEvent event) { return newEventMessage(ERROR, channelId, txId, ByteString.copyFromUtf8(message), event); } - protected static ChaincodeMessage newCompletedEventMessage( + static ChaincodeMessage newCompletedEventMessage( final String channelId, final String txId, final Chaincode.Response response, final ChaincodeEvent event) { - final ChaincodeMessage message = newEventMessage( + return newEventMessage( COMPLETED, channelId, txId, toProtoResponse(response).toByteString(), event); - return message; } - protected static ChaincodeMessage newInvokeChaincodeMessage( + static ChaincodeMessage newInvokeChaincodeMessage( final String channelId, final String txId, final ByteString payload) { return newEventMessage(INVOKE_CHAINCODE, channelId, txId, payload, null); } - protected static ChaincodeMessage newRegisterChaincodeMessage(final ChaincodeID chaincodeId) { + static ChaincodeMessage newRegisterChaincodeMessage(final ChaincodeID chaincodeId) { return ChaincodeMessage.newBuilder() .setType(REGISTER) .setPayload(chaincodeId.toByteString()) .build(); } - protected static ChaincodeMessage newEventMessage( + static ChaincodeMessage newEventMessage( final Type type, final String channelId, final String txId, final ByteString payload) { return newEventMessage(type, channelId, txId, payload, null); } - protected static ChaincodeMessage newEventMessage( + static ChaincodeMessage newEventMessage( final Type type, final String channelId, final String txId, diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java index d3a6190d..b55a64f4 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClient.java @@ -22,8 +22,7 @@ public class ChaincodeSupportClient { private static final int DEFAULT_TIMEOUT = 5; - private static final Logger LOGGER = Logger.getLogger(ChaincodeSupportClient.class.getName()); - private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); + private static final Logger PERFLOGGER = Logger.getLogger(Logging.PERFLOGGER); private final ManagedChannel channel; private final ChaincodeSupportStub stub; @@ -77,19 +76,14 @@ public void start(final InvocationTaskManager itm, final StreamObserver consumer = new Consumer() { - - // create a lock, with fair property - private final ReentrantLock lock = new ReentrantLock(true); - - @Override - public void accept(final ChaincodeMessage t) { - lock.lock(); - perflogger.fine(() -> "> sendToPeer TX::" + t.getTxid()); - requestObserver.onNext(t); - perflogger.fine(() -> "< sendToPeer TX::" + t.getTxid()); - lock.unlock(); - } + // create a lock, with fair property + final ReentrantLock lock = new ReentrantLock(true); + final Consumer consumer = t -> { + lock.lock(); + PERFLOGGER.fine(() -> "> sendToPeer TX::" + t.getTxid()); + requestObserver.onNext(t); + PERFLOGGER.fine(() -> "< sendToPeer TX::" + t.getTxid()); + lock.unlock(); }; // Pass a Consumer interface back to the the task manager. This is for tasks to @@ -97,7 +91,8 @@ public void accept(final ChaincodeMessage t) { // // NOTE the register() - very important - as this triggers the ITM to send the // first message to the peer; otherwise the both sides will sit there waiting - itm.setResponseConsumer(consumer).register(); + itm.setResponseConsumer(consumer); + itm.register(); } /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java index 809b36a5..ec0b1ffc 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationStubImpl.java @@ -16,6 +16,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Timestamp; +import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.MessageDigest; @@ -25,6 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -57,6 +59,7 @@ import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; +@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.GodClass"}) class InvocationStubImpl implements ChaincodeStub { private static final String UNSPECIFIED_START_KEY = new String(Character.toChars(0x000001)); @@ -65,6 +68,24 @@ class InvocationStubImpl implements ChaincodeStub { public static final String MAX_UNICODE_RUNE = "\udbff\udfff"; private static final String CORE_PEER_LOCALMSPID = "CORE_PEER_LOCALMSPID"; + + private static final Function + QUERY_RESULT_BYTES_TO_KEY_MODIFICATION = queryResultBytes -> { + try { + return org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.parseFrom( + queryResultBytes.getResultBytes()); + } catch (final InvalidProtocolBufferException e) { + throw new UncheckedIOException(e); + } + }; + private static final Function QUERY_RESULT_BYTES_TO_KV = queryResultBytes -> { + try { + return KV.parseFrom(queryResultBytes.getResultBytes()); + } catch (final InvalidProtocolBufferException e) { + throw new UncheckedIOException(e); + } + }; + private final String channelId; private final String txId; private final ChaincodeInvocationTask handler; @@ -82,7 +103,7 @@ class InvocationStubImpl implements ChaincodeStub { * @throws InvalidProtocolBufferException */ InvocationStubImpl(final ChaincodeMessage message, final ChaincodeInvocationTask handler) - throws InvalidProtocolBufferException { + throws InvalidProtocolBufferException, NoSuchAlgorithmException { this.channelId = message.getChannelId(); this.txId = message.getTxid(); this.handler = handler; @@ -90,31 +111,35 @@ class InvocationStubImpl implements ChaincodeStub { this.args = Collections.unmodifiableList(input.getArgsList()); this.signedProposal = message.getProposal(); - if (this.signedProposal == null - || this.signedProposal.getProposalBytes().isEmpty()) { + if (this.signedProposal.getProposalBytes().isEmpty()) { this.creator = null; this.txTimestamp = null; this.transientMap = Collections.emptyMap(); this.binding = null; } else { - try { - final Proposal proposal = Proposal.parseFrom(signedProposal.getProposalBytes()); - final Header header = Header.parseFrom(proposal.getHeader()); - final ChannelHeader channelHeader = ChannelHeader.parseFrom(header.getChannelHeader()); - validateProposalType(channelHeader); - final SignatureHeader signatureHeader = SignatureHeader.parseFrom(header.getSignatureHeader()); - final ChaincodeProposalPayload chaincodeProposalPayload = - ChaincodeProposalPayload.parseFrom(proposal.getPayload()); - final Timestamp timestamp = channelHeader.getTimestamp(); - - this.txTimestamp = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); - this.creator = signatureHeader.getCreator(); - this.transientMap = chaincodeProposalPayload.getTransientMapMap(); - this.binding = computeBinding(channelHeader, signatureHeader); - } catch (InvalidProtocolBufferException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); + final Proposal proposal = Proposal.parseFrom(signedProposal.getProposalBytes()); + final Header header = Header.parseFrom(proposal.getHeader()); + final ChannelHeader channelHeader = ChannelHeader.parseFrom(header.getChannelHeader()); + validateProposalType(channelHeader); + final SignatureHeader signatureHeader = SignatureHeader.parseFrom(header.getSignatureHeader()); + final ChaincodeProposalPayload chaincodeProposalPayload = + ChaincodeProposalPayload.parseFrom(proposal.getPayload()); + final Timestamp timestamp = channelHeader.getTimestamp(); + + this.txTimestamp = Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()); + this.creator = signatureHeader.getCreator(); + this.transientMap = chaincodeProposalPayload.getTransientMapMap(); + this.binding = computeBinding(channelHeader, signatureHeader); + } + } + + private static boolean isEmptyString(final String str) { + for (int i = 0; i < str.length(); i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return false; } } + return true; } private byte[] computeBinding(final ChannelHeader channelHeader, final SignatureHeader signatureHeader) @@ -135,24 +160,24 @@ private void validateProposalType(final ChannelHeader channelHeader) { case CONFIG: return; default: - throw new RuntimeException(String.format( + throw new IllegalArgumentException(String.format( "Unexpected transaction type: %s", HeaderType.forNumber(channelHeader.getType()))); } } @Override public List getArgs() { - return args.stream().map(x -> x.toByteArray()).collect(Collectors.toList()); + return args.stream().map(ByteString::toByteArray).collect(toList()); } @Override public List getStringArgs() { - return args.stream().map(x -> x.toStringUtf8()).collect(Collectors.toList()); + return args.stream().map(ByteString::toStringUtf8).collect(toList()); } @Override public String getFunction() { - return getStringArgs().size() > 0 ? getStringArgs().get(0) : null; + return getStringArgs().isEmpty() ? null : getStringArgs().get(0); } @Override @@ -162,7 +187,7 @@ public List getParameters() { @Override public void setEvent(final String name, final byte[] payload) { - if (name == null || name.trim().isEmpty()) { + if (null == name || isEmptyString(name)) { throw new IllegalArgumentException("event name can not be nil string"); } if (payload != null) { @@ -198,6 +223,7 @@ public byte[] getState(final String key) { } @Override + @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") public byte[] getStateValidationParameter(final String key) { final ByteString payload = @@ -215,8 +241,8 @@ public byte[] getStateValidationParameter(final String key) { .toByteArray(); } } catch (final InvalidProtocolBufferException e) { - LOGGER.severe(String.format("[%-8.8s] unmarshalling error", txId)); - throw new RuntimeException("Error unmarshalling StateMetadataResult.", e); + LOGGER.severe(() -> String.format("[%-8.8s] unmarshalling error", txId)); + throw new UncheckedIOException("Error unmarshalling StateMetadataResult.", e); } return null; @@ -273,21 +299,10 @@ private QueryResultsIterator executeGetStateByRange( ChaincodeMessageFactory.newEventMessage(GET_STATE_BY_RANGE, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl( - this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorImpl<>( + this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new)); } - private final Function queryResultBytesToKv = new Function() { - @Override - public KV apply(final QueryResultBytes queryResultBytes) { - try { - return KV.parseFrom(queryResultBytes.getResultBytes()); - } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } - } - }; - @Override public QueryResultsIteratorWithMetadata getStateByRangeWithPagination( final String startKey, final String endKey, final int pageSize, final String bookmark) { @@ -329,7 +344,7 @@ private QueryResultsIteratorWithMetadataImpl executeGetStateByRangeWit final ByteString response = this.handler.invoke(requestMessage); return new QueryResultsIteratorWithMetadataImpl<>( - this.handler, getChannelId(), getTxId(), response, queryResultBytesToKv.andThen(KeyValueImpl::new)); + this.handler, getChannelId(), getTxId(), response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new)); } @Override @@ -409,8 +424,8 @@ public QueryResultsIterator getQueryResult(final String query) { ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl( - this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorImpl<>( + this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new)); } @Override @@ -432,8 +447,8 @@ public QueryResultsIteratorWithMetadata getQueryResultWithPagination( ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorWithMetadataImpl( - this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorWithMetadataImpl<>( + this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new)); } @Override @@ -448,29 +463,14 @@ public QueryResultsIterator getHistoryForKey(final String key) ChaincodeMessageFactory.newEventMessage(GET_HISTORY_FOR_KEY, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl( + return new QueryResultsIteratorImpl<>( this.handler, channelId, txId, response, - queryResultBytesToKeyModification.andThen(KeyModificationImpl::new)); + QUERY_RESULT_BYTES_TO_KEY_MODIFICATION.andThen(KeyModificationImpl::new)); } - private final Function - queryResultBytesToKeyModification = - new Function() { - @Override - public org.hyperledger.fabric.protos.ledger.queryresult.KeyModification apply( - final QueryResultBytes queryResultBytes) { - try { - return org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.parseFrom( - queryResultBytes.getResultBytes()); - } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); - } - } - }; - @Override public byte[] getPrivateData(final String collection, final String key) { validateCollection(collection); @@ -496,6 +496,7 @@ public byte[] getPrivateDataHash(final String collection, final String key) { } @Override + @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") public byte[] getPrivateDataValidationParameter(final String collection, final String key) { validateCollection(collection); @@ -514,8 +515,8 @@ public byte[] getPrivateDataValidationParameter(final String collection, final S .toByteArray(); } } catch (final InvalidProtocolBufferException e) { - LOGGER.severe(String.format("[%-8.8s] unmarshalling error", txId)); - throw new RuntimeException("Error unmarshalling StateMetadataResult.", e); + LOGGER.severe(() -> String.format("[%-8.8s] unmarshalling error", txId)); + throw new UncheckedIOException("Error unmarshalling StateMetadataResult.", e); } return null; @@ -625,8 +626,8 @@ public QueryResultsIterator getPrivateDataQueryResult(final String col ChaincodeMessageFactory.newEventMessage(GET_QUERY_RESULT, channelId, txId, requestPayload); final ByteString response = handler.invoke(requestMessage); - return new QueryResultsIteratorImpl( - this.handler, channelId, txId, response, queryResultBytesToKv.andThen(KeyValueImpl::new)); + return new QueryResultsIteratorImpl<>( + this.handler, channelId, txId, response, QUERY_RESULT_BYTES_TO_KV.andThen(KeyValueImpl::new)); } @Override @@ -634,7 +635,7 @@ public Chaincode.Response invokeChaincode( final String chaincodeName, final List args, final String channel) { // internally we handle chaincode name as a composite name final String compositeName; - if (channel != null && !channel.trim().isEmpty()) { + if (channel != null && !isEmptyString(channel)) { compositeName = chaincodeName + "/" + channel; } else { compositeName = chaincodeName; @@ -644,7 +645,7 @@ public Chaincode.Response invokeChaincode( final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder() .setChaincodeId(ChaincodeID.newBuilder().setName(compositeName).build()) .setInput(ChaincodeInput.newBuilder() - .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())) + .addAllArgs(args.stream().map(ByteString::copyFrom).collect(toList())) .build()) .build() .toByteString(); @@ -659,7 +660,7 @@ public Chaincode.Response invokeChaincode( final ChaincodeMessage responseMessage = ChaincodeMessage.parseFrom(response); // the actual response message must be of type COMPLETED - LOGGER.fine(String.format( + LOGGER.fine(() -> String.format( "[%-8.8s] %s response received from other chaincode.", txId, responseMessage.getType())); if (responseMessage.getType() == COMPLETED) { @@ -668,14 +669,14 @@ public Chaincode.Response invokeChaincode( return new Chaincode.Response( Chaincode.Response.Status.forCode(r.getStatus()), r.getMessage(), - r.getPayload() == null ? null : r.getPayload().toByteArray()); + r.getPayload().toByteArray()); } else { // error final String message = responseMessage.getPayload().toStringUtf8(); return new Chaincode.Response(Chaincode.Response.Status.INTERNAL_SERVER_ERROR, message, null); } } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } @@ -690,6 +691,7 @@ public Instant getTxTimestamp() { } @Override + @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") public byte[] getCreator() { if (creator == null) { return null; @@ -700,27 +702,24 @@ public byte[] getCreator() { @Override public Map getTransient() { return transientMap.entrySet().stream() - .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue().toByteArray())); + .collect(Collectors.toMap(Map.Entry::getKey, x -> x.getValue().toByteArray())); } @Override + @SuppressWarnings("PMD.MethodReturnsInternalArray") public byte[] getBinding() { return this.binding; } private void validateKey(final String key) { - if (key == null) { - throw new NullPointerException("key cannot be null"); - } - if (key.length() == 0) { + Objects.requireNonNull(key, "key cannot be null"); + if (key.isEmpty()) { throw new IllegalArgumentException("key cannot not be an empty string"); } } private void validateCollection(final String collection) { - if (collection == null) { - throw new NullPointerException("collection cannot be null"); - } + Objects.requireNonNull(collection, "collection cannot be null"); if (collection.isEmpty()) { throw new IllegalArgumentException("collection must not be an empty string"); } @@ -731,6 +730,6 @@ public String getMspId() { if (System.getenv().containsKey(CORE_PEER_LOCALMSPID)) { return System.getenv(CORE_PEER_LOCALMSPID); } - throw new RuntimeException("CORE_PEER_LOCALMSPID is unset in chaincode process"); + throw new IllegalStateException("CORE_PEER_LOCALMSPID is unset in chaincode process"); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java index c2402e48..1267ac4f 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskExecutor.java @@ -18,6 +18,8 @@ public final class InvocationTaskExecutor extends ThreadPoolExecutor implements TaskMetricsCollector { private static Logger logger = Logger.getLogger(InvocationTaskExecutor.class.getName()); + private final AtomicInteger count = new AtomicInteger(); + /** * @param corePoolSize * @param maximumPoolSize @@ -40,8 +42,6 @@ public InvocationTaskExecutor( logger.info("Thread pool created"); } - private final AtomicInteger count = new AtomicInteger(); - @Override protected void beforeExecute(final Thread thread, final Runnable task) { super.beforeExecute(thread, task); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java index 2de85597..aecc8e64 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java @@ -8,6 +8,7 @@ import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.READY; import static org.hyperledger.fabric.protos.peer.ChaincodeMessage.Type.REGISTERED; +import java.util.Map; import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; @@ -35,27 +36,19 @@ *

    In the current 1.4 Fabric Protocol this is in practice a singleton - because the peer will ignore multiple * 'register' calls. And an instance of this will be created per register call for a given chaincodeID. */ +@SuppressWarnings("PMD.MoreThanOneLogger") public final class InvocationTaskManager { - private static Logger logger = Logger.getLogger(InvocationTaskManager.class.getName()); - private static Logger perflogger = Logger.getLogger(Logging.PERFLOGGER); - - /** - * Get an instance of the Invocation Task Manager. - * - * @param chaincode Chaincode Instance - * @param chaincodeId ID of the chaincode - * @return InvocationTaskManager - */ - public static InvocationTaskManager getManager(final ChaincodeBase chaincode, final ChaincodeID chaincodeId) { - return new InvocationTaskManager(chaincode, chaincodeId); - } + private static final Logger LOGGER = Logger.getLogger(InvocationTaskManager.class.getName()); + private static final Logger PERFLOGGER = Logger.getLogger(Logging.PERFLOGGER); + private static final String CANNOT_HANDLE_FORMAT = "[%-8.8s] Received %s: cannot handle"; + private static final int SHUTDOWN_TIMEOUT = 60; // Keeping a map here of the tasks that are currently ongoing, and the key // // Key = txid + channleid // One task = one transaction invocation - private final ConcurrentHashMap innvocationTasks = new ConcurrentHashMap<>(); + private final Map innvocationTasks = new ConcurrentHashMap<>(); // Way to send back the events and data that make up the requests private Consumer outgoingMessage; @@ -69,13 +62,14 @@ public static InvocationTaskManager getManager(final ChaincodeBase chaincode, fi private final int maximumPoolSize; private final int corePoolSize; private final long keepAliveTime; - private final TimeUnit unit = TimeUnit.MILLISECONDS; + private static final TimeUnit UNIT = TimeUnit.MILLISECONDS; private final BlockingQueue workQueue; // Minor customization of the ThreadFactory to give a more recognizable name to the threads private final ThreadFactory threadFactory = new ThreadFactory() { - private AtomicInteger next = new AtomicInteger(0); + private final AtomicInteger next = new AtomicInteger(0); + @Override public Thread newThread(final Runnable r) { Thread thread = Executors.defaultThreadFactory().newThread(r); thread.setName("fabric-txinvoke:" + next.incrementAndGet()); @@ -94,6 +88,17 @@ public Thread newThread(final Runnable r) { private final InvocationTaskExecutor taskService; + /** + * Get an instance of the Invocation Task Manager. + * + * @param chaincode Chaincode Instance + * @param chaincodeId ID of the chaincode + * @return InvocationTaskManager + */ + public static InvocationTaskManager getManager(final ChaincodeBase chaincode, final ChaincodeID chaincodeId) { + return new InvocationTaskManager(chaincode, chaincodeId); + } + /** * New InvocationTaskManager. * @@ -117,14 +122,14 @@ public InvocationTaskManager(final ChaincodeBase chaincode, final ChaincodeID ch corePoolSize = Integer.parseInt((String) props.getOrDefault("TP_CORE_POOL_SIZE", "5")); keepAliveTime = Long.parseLong((String) props.getOrDefault("TP_KEEP_ALIVE_MS", "5000")); - logger.info(() -> "Max Pool Size [TP_MAX_POOL_SIZE]" + maximumPoolSize); - logger.info(() -> "Queue Size [TP_CORE_POOL_SIZE]" + queueSize); - logger.info(() -> "Core Pool Size [TP_QUEUE_SIZE]" + corePoolSize); - logger.info(() -> "Keep Alive Time [TP_KEEP_ALIVE_MS]" + keepAliveTime); + LOGGER.info(() -> "Max Pool Size [TP_MAX_POOL_SIZE]" + maximumPoolSize); + LOGGER.info(() -> "Queue Size [TP_CORE_POOL_SIZE]" + queueSize); + LOGGER.info(() -> "Core Pool Size [TP_QUEUE_SIZE]" + corePoolSize); + LOGGER.info(() -> "Keep Alive Time [TP_KEEP_ALIVE_MS]" + keepAliveTime); - workQueue = new LinkedBlockingQueue(queueSize); + workQueue = new LinkedBlockingQueue<>(queueSize); taskService = new InvocationTaskExecutor( - corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); + corePoolSize, maximumPoolSize, keepAliveTime, UNIT, workQueue, threadFactory, handler); Metrics.getProvider().setTaskMetricsCollector(taskService); } @@ -135,45 +140,15 @@ public InvocationTaskManager(final ChaincodeBase chaincode, final ChaincodeID ch * @throws IllegalArgumentException validation fields and arguments * @param chaincodeMessage ChaincodeMessage */ - public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) throws IllegalArgumentException { - if (chaincodeMessage == null) { + @SuppressWarnings("PMD.AvoidCatchingGenericException") + public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) { + if (null == chaincodeMessage) { throw new IllegalArgumentException("chaincodeMessage is null"); } - logger.fine(() -> + LOGGER.fine(() -> String.format("[%-8.8s] %s", chaincodeMessage.getTxid(), ChaincodeBase.toJsonString(chaincodeMessage))); try { - final Type msgType = chaincodeMessage.getType(); - switch (chaincode.getState()) { - case CREATED: - if (msgType == REGISTERED) { - chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.ESTABLISHED); - logger.fine(() -> String.format( - "[%-8.8s] Received REGISTERED: moving to established state", - chaincodeMessage.getTxid())); - } else { - logger.warning(() -> String.format( - "[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); - } - break; - case ESTABLISHED: - if (msgType == READY) { - chaincode.setState(org.hyperledger.fabric.shim.ChaincodeBase.CCState.READY); - logger.fine(() -> String.format( - "[%-8.8s] Received READY: ready for invocations", chaincodeMessage.getTxid())); - } else { - logger.warning(() -> String.format( - "[%-8.8s] Received %s: cannot handle", chaincodeMessage.getTxid(), msgType)); - } - break; - case READY: - handleMsg(chaincodeMessage, msgType); - break; - default: - logger.warning(() -> String.format( - "[%-8.8s] Received %s: cannot handle", - chaincodeMessage.getTxid(), chaincodeMessage.getType())); - break; - } + processChaincodeMessage(chaincodeMessage); } catch (final RuntimeException e) { // catch any issues with say the comms dropping or something else completely // unknown @@ -183,6 +158,37 @@ public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) throws I } } + private void processChaincodeMessage(final ChaincodeMessage chaincodeMessage) { + final Type msgType = chaincodeMessage.getType(); + + switch (chaincode.getState()) { + case CREATED: + if (msgType == REGISTERED) { + chaincode.setState(ChaincodeBase.CCState.ESTABLISHED); + LOGGER.fine(() -> String.format( + "[%-8.8s] Received REGISTERED: moving to established state", chaincodeMessage.getTxid())); + } else { + LOGGER.warning(() -> String.format(CANNOT_HANDLE_FORMAT, chaincodeMessage.getTxid(), msgType)); + } + break; + case ESTABLISHED: + if (msgType == READY) { + chaincode.setState(ChaincodeBase.CCState.READY); + LOGGER.fine(() -> String.format( + "[%-8.8s] Received READY: ready for invocations", chaincodeMessage.getTxid())); + } else { + LOGGER.warning(() -> String.format(CANNOT_HANDLE_FORMAT, chaincodeMessage.getTxid(), msgType)); + } + break; + case READY: + handleMsg(chaincodeMessage, msgType); + break; + default: + LOGGER.warning(() -> String.format(CANNOT_HANDLE_FORMAT, chaincodeMessage.getTxid(), msgType)); + break; + } + } + /** * Key method to take the message, determine if it is a new transaction or an answer (good or bad) to a stub api. * @@ -190,7 +196,7 @@ public void onChaincodeMessage(final ChaincodeMessage chaincodeMessage) throws I * @param msgType */ private void handleMsg(final ChaincodeMessage message, final Type msgType) { - logger.fine(() -> String.format("[%-8.8s] Received %s", message.getTxid(), msgType.toString())); + LOGGER.fine(() -> String.format("[%-8.8s] Received %s", message.getTxid(), msgType.toString())); switch (msgType) { case RESPONSE: case ERROR: @@ -201,8 +207,7 @@ private void handleMsg(final ChaincodeMessage message, final Type msgType) { newTask(message, msgType); break; default: - logger.warning(() -> - String.format("[%-8.8s] Received %s: cannot handle", message.getTxid(), message.getType())); + LOGGER.warning(() -> String.format(CANNOT_HANDLE_FORMAT, message.getTxid(), message.getType())); break; } } @@ -214,26 +219,29 @@ private void handleMsg(final ChaincodeMessage message, final Type msgType) { */ private void sendToTask(final ChaincodeMessage message) { try { - perflogger.fine(() -> "> sendToTask TX::" + message.getTxid()); + PERFLOGGER.fine(() -> "> sendToTask TX::" + message.getTxid()); final String key = message.getChannelId() + message.getTxid(); final ChaincodeInvocationTask task = this.innvocationTasks.get(key); if (task == null) { - throw new InterruptedException("Task hasmap missing entry"); + sendFailure(message, new InterruptedException("Task map missing entry: " + key)); + } else { + task.postMessage(message); + PERFLOGGER.fine(() -> "< sendToTask TX::" + message.getTxid()); } - task.postMessage(message); - - perflogger.fine(() -> "< sendToTask TX::" + message.getTxid()); } catch (final InterruptedException e) { - logger.severe( - () -> "Failed to send response to the task task " + message.getTxid() + Logging.formatError(e)); - - final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage( - message.getChannelId(), message.getTxid(), "Failed to send response to task"); - this.outgoingMessage.accept(m); + sendFailure(message, e); } } + private void sendFailure(final ChaincodeMessage message, final InterruptedException e) { + LOGGER.severe(() -> "Failed to send response to the task task " + message.getTxid() + Logging.formatError(e)); + + final ChaincodeMessage m = ChaincodeMessageFactory.newErrorEventMessage( + message.getChannelId(), message.getTxid(), "Failed to send response to task"); + this.outgoingMessage.accept(m); + } + /** * Create a new task to handle this transaction function. * @@ -246,11 +254,11 @@ private void newTask(final ChaincodeMessage message, final Type type) { final ChaincodeInvocationTask task = new ChaincodeInvocationTask(message, type, this.outgoingMessage, this.chaincode); - perflogger.fine(() -> "> newTask:created TX::" + txid); + PERFLOGGER.fine(() -> "> newTask:created TX::" + txid); this.innvocationTasks.put(task.getTxKey(), task); try { - perflogger.fine(() -> "> newTask:submitting TX::" + txid); + PERFLOGGER.fine(() -> "> newTask:submitting TX::" + txid); // submit the task to run, with the taskService providing the // threading support. @@ -266,13 +274,13 @@ private void newTask(final ChaincodeMessage message, final Type type) { // list response.thenRun(() -> { innvocationTasks.remove(task.getTxKey()); - perflogger.fine(() -> "< newTask:completed TX::" + txid); + PERFLOGGER.fine(() -> "< newTask:completed TX::" + txid); }); - perflogger.fine(() -> "< newTask:submitted TX::" + txid); + PERFLOGGER.fine(() -> "< newTask:submitted TX::" + txid); } catch (final RejectedExecutionException e) { - logger.warning(() -> "Failed to submit task " + txid + Logging.formatError(e)); + LOGGER.warning(() -> "Failed to submit task " + txid + Logging.formatError(e)); // this means that there is no way that this can be handed off to another // thread for processing, and there's no space left in the queue to hold // it pending @@ -289,33 +297,27 @@ private void newTask(final ChaincodeMessage message, final Type type) { * @param outgoingMessage * @return InvocationTaskManager */ - public InvocationTaskManager setResponseConsumer(final Consumer outgoingMessage) { + public void setResponseConsumer(final Consumer outgoingMessage) { this.outgoingMessage = outgoingMessage; - - return this; } /** * Send the initial protocol message for the 'register' phase. * * @throws IllegalArgumentException validation fields and arguments - * @return InvocationTaskManager */ - public InvocationTaskManager register() throws IllegalArgumentException { + public void register() { if (outgoingMessage == null) { throw new IllegalArgumentException("outgoingMessage is null"); } - logger.info(() -> "Registering new chaincode " + this.chaincodeId); + LOGGER.info(() -> "Registering new chaincode " + this.chaincodeId); chaincode.setState(ChaincodeBase.CCState.CREATED); this.outgoingMessage.accept(ChaincodeMessageFactory.newRegisterChaincodeMessage(this.chaincodeId)); - - return this; } - private static final int SHUTDOWN_TIMEOUT = 60; - /** */ + @SuppressWarnings("PMD.SystemPrintln") public void shutdown() { // Recommended shutdown process from // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java index 2cecbf97..2bbcca43 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyModificationImpl.java @@ -13,7 +13,7 @@ public final class KeyModificationImpl implements KeyModification { private final String txId; private final ByteString value; - private final java.time.Instant timestamp; + private final Instant timestamp; private final boolean deleted; KeyModificationImpl(final org.hyperledger.fabric.protos.ledger.queryresult.KeyModification km) { @@ -40,7 +40,7 @@ public String getStringValue() { } @Override - public java.time.Instant getTimestamp() { + public Instant getTimestamp() { return timestamp; } @@ -52,38 +52,29 @@ public boolean isDeleted() { @Override public int hashCode() { final int prime = 31; - int result = 1; - result = prime * result + (deleted ? 1231 : 1237); - result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode()); - result = prime * result + ((txId == null) ? 0 : txId.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); + int result = Boolean.hashCode(deleted); + result = prime * result + timestamp.hashCode(); + result = prime * result + txId.hashCode(); + result = prime * result + value.hashCode(); return result; } @Override - public boolean equals(final Object obj) { - if (this == obj) { + public boolean equals(final Object other) { + if (this == other) { return true; } - if (obj == null) { + if (other == null) { return false; } - if (getClass() != obj.getClass()) { + if (getClass() != other.getClass()) { return false; } - final KeyModificationImpl other = (KeyModificationImpl) obj; - if (deleted != other.deleted) { - return false; - } - if (!timestamp.equals(other.timestamp)) { - return false; - } - if (!txId.equals(other.txId)) { - return false; - } - if (!value.equals(other.value)) { - return false; - } - return true; + + final KeyModificationImpl that = (KeyModificationImpl) other; + return this.deleted == that.deleted + && this.timestamp.equals(that.timestamp) + && this.txId.equals(that.txId) + && this.value.equals(that.value); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java index dbf1089f..e158fc96 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/KeyValueImpl.java @@ -37,30 +37,24 @@ public String getStringValue() { @Override public int hashCode() { final int prime = 31; - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); + int result = key.hashCode(); + result = prime * result + value.hashCode(); return result; } @Override - public boolean equals(final Object obj) { - if (this == obj) { + public boolean equals(final Object other) { + if (this == other) { return true; } - if (obj == null) { + if (other == null) { return false; } - if (getClass() != obj.getClass()) { + if (getClass() != other.getClass()) { return false; } - final KeyValueImpl other = (KeyValueImpl) obj; - if (!key.equals(other.key)) { - return false; - } - if (!value.equals(other.value)) { - return false; - } - return true; + + final KeyValueImpl that = (KeyValueImpl) other; + return this.key.equals(that.key) && this.value.equals(that.value); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java index 874ae4f7..89350204 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java @@ -11,6 +11,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.io.UncheckedIOException; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; @@ -39,7 +40,7 @@ class QueryResultsIteratorImpl implements QueryResultsIterator { private final String txId; private Iterator currentIterator; private QueryResponse currentQueryResponse; - private Function mapper; + private final Function mapper; QueryResultsIteratorImpl( final ChaincodeInvocationTask handler, @@ -56,13 +57,13 @@ class QueryResultsIteratorImpl implements QueryResultsIterator { this.currentIterator = currentQueryResponse.getResultsList().iterator(); this.mapper = mapper; } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } @Override public Iterator iterator() { - return new Iterator() { + return new Iterator<>() { @Override public boolean hasNext() { @@ -95,7 +96,7 @@ public T next() { try { currentQueryResponse = QueryResponse.parseFrom(responseMessage); } catch (final InvalidProtocolBufferException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } currentIterator = currentQueryResponse.getResultsList().iterator(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java index 26d24f55..25043547 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImpl.java @@ -8,6 +8,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.io.UncheckedIOException; import java.util.function.Function; import java.util.logging.Logger; import org.hyperledger.fabric.protos.peer.QueryResponse; @@ -25,9 +26,9 @@ */ public final class QueryResultsIteratorWithMetadataImpl extends QueryResultsIteratorImpl implements QueryResultsIteratorWithMetadata { - private static Logger logger = Logger.getLogger(QueryResultsIteratorWithMetadataImpl.class.getName()); + private static final Logger LOGGER = Logger.getLogger(QueryResultsIteratorWithMetadataImpl.class.getName()); - private QueryResponseMetadata metadata; + private final QueryResponseMetadata metadata; /** * @param handler @@ -47,8 +48,8 @@ public QueryResultsIteratorWithMetadataImpl( final QueryResponse queryResponse = QueryResponse.parseFrom(responseBuffer); metadata = QueryResponseMetadata.parseFrom(queryResponse.getMetadata()); } catch (final InvalidProtocolBufferException e) { - logger.warning("can't parse response metadata"); - throw new RuntimeException(e); + LOGGER.warning("can't parse response metadata"); + throw new UncheckedIOException(e); } } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java index 32335315..4c88c237 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/CompositeKey.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,7 +27,7 @@ public class CompositeKey { private final String objectType; private final List attributes; - private final String compositeKey; + private final String key; /** * @param objectType @@ -41,12 +42,10 @@ public CompositeKey(final String objectType, final String... attributes) { * @param attributes */ public CompositeKey(final String objectType, final List attributes) { - if (objectType == null) { - throw new NullPointerException("objectType cannot be null"); - } + Objects.requireNonNull(objectType, "objectType cannot be null"); this.objectType = objectType; this.attributes = attributes; - this.compositeKey = generateCompositeKeyString(objectType, attributes); + this.key = generateCompositeKeyString(objectType, attributes); } /** @return object type */ @@ -62,7 +61,7 @@ public List getAttributes() { /** */ @Override public String toString() { - return compositeKey; + return key; } /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java index 28ba7b28..60f3407a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/Traces.java @@ -5,7 +5,6 @@ */ package org.hyperledger.fabric.traces; -import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.logging.Logger; import org.hyperledger.fabric.traces.impl.DefaultTracesProvider; @@ -33,6 +32,7 @@ private Traces() {} * @param props the configuration of the chaincode * @return The traces provider */ + @SuppressWarnings("PMD.AvoidCatchingGenericException") public static TracesProvider initialize(final Properties props) { if (Boolean.parseBoolean((String) props.get(CHAINCODE_TRACES_ENABLED))) { try { @@ -47,14 +47,8 @@ public static TracesProvider initialize(final Properties props) { logger.info("Using default traces provider"); provider = new DefaultTracesProvider(); } - } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | IllegalArgumentException - | InvocationTargetException - | NoSuchMethodException - | SecurityException e) { - throw new RuntimeException("Unable to start traces", e); + } catch (Exception e) { + throw new IllegalStateException("Unable to start traces", e); } } else { // return a 'null' provider diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java index 2083b4e9..40c49086 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/TracesProvider.java @@ -31,8 +31,9 @@ public interface TracesProvider { * * @param props */ - default void initialize(final Properties props) {} - ; + default void initialize(final Properties props) { + // Do nothing by default + } /** * Creates a span with metadata of the current chaincode execution, possibly linked to the execution arguments. diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java index 7afa5c48..da954aee 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryProperties.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -23,11 +24,12 @@ final class OpenTelemetryProperties implements ConfigProperties { private final Map config; - OpenTelemetryProperties(final Map... arrayOfProperties) { + @SafeVarargs + OpenTelemetryProperties(final Map... arrayOfProperties) { Map config = new HashMap<>(); - for (Map props : arrayOfProperties) { - props.forEach((key, value) -> - config.put(((String) key).toLowerCase(Locale.ROOT).replace('-', '.'), (String) value)); + for (Map props : arrayOfProperties) { + props.forEach( + (key, value) -> config.put(key.toLowerCase(Locale.ROOT).replace('-', '.'), value)); } this.config = config; } @@ -43,54 +45,50 @@ final class OpenTelemetryProperties implements ConfigProperties { if (value == null || value.isEmpty()) { return null; } - return Boolean.parseBoolean(value); + return Boolean.valueOf(value); } @Override - @Nullable @SuppressWarnings("UnusedException") - public Integer getInt(final String name) { + @Nullable public Integer getInt(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { return null; } try { - return Integer.parseInt(value); + return Integer.valueOf(value); } catch (NumberFormatException ex) { - throw newInvalidPropertyException(name, value, "integer"); + throw newInvalidPropertyException(name, value, "integer", ex); } } @Override - @Nullable @SuppressWarnings("UnusedException") - public Long getLong(final String name) { + @Nullable public Long getLong(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { return null; } try { - return Long.parseLong(value); + return Long.valueOf(value); } catch (NumberFormatException ex) { - throw newInvalidPropertyException(name, value, "long"); + throw newInvalidPropertyException(name, value, "long", ex); } } @Override - @Nullable @SuppressWarnings("UnusedException") - public Double getDouble(final String name) { + @Nullable public Double getDouble(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { return null; } try { - return Double.parseDouble(value); + return Double.valueOf(value); } catch (NumberFormatException ex) { - throw newInvalidPropertyException(name, value, "double"); + throw newInvalidPropertyException(name, value, "double", ex); } } @Override - @Nullable @SuppressWarnings("UnusedException") - public Duration getDuration(final String name) { + @Nullable public Duration getDuration(final String name) { String value = config.get(name); if (value == null || value.isEmpty()) { return null; @@ -99,14 +97,15 @@ public Duration getDuration(final String name) { String numberString = value.substring(0, value.length() - unitString.length()); try { long rawNumber = Long.parseLong(numberString.trim()); - TimeUnit unit = getDurationUnit(unitString.trim()); + TimeUnit unit = getDurationUnit(unitString.trim()) + .orElseThrow(() -> new ConfigurationException( + "Invalid duration property " + name + "=" + value + ". Invalid duration unit.")); return Duration.ofMillis(TimeUnit.MILLISECONDS.convert(rawNumber, unit)); } catch (NumberFormatException ex) { - throw new ConfigurationException( + var e = new ConfigurationException( "Invalid duration property " + name + "=" + value + ". Expected number, found: " + numberString); - } catch (ConfigurationException ex) { - throw new ConfigurationException( - "Invalid duration property " + name + "=" + value + ". " + ex.getMessage()); + e.addSuppressed(ex); + throw e; } } @@ -120,6 +119,7 @@ public List getList(final String name) { } @Override + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") public Map getMap(final String name) { return getList(name).stream() .map(keyValuePair -> filterBlanksAndNulls(keyValuePair.split("=", 2))) @@ -136,9 +136,11 @@ public Map getMap(final String name) { } private static ConfigurationException newInvalidPropertyException( - final String name, final String value, final String type) { - throw new ConfigurationException( + final String name, final String value, final String type, final Exception cause) { + var e = new ConfigurationException( "Invalid value for property " + name + "=" + value + ". Must be a " + type + "."); + e.addSuppressed(cause); + throw e; } private static List filterBlanksAndNulls(final String[] values) { @@ -151,21 +153,21 @@ private static List filterBlanksAndNulls(final String[] values) { * @param unitString the time unit as a string * @return the parsed TimeUnit */ - private static TimeUnit getDurationUnit(final String unitString) { + private static Optional getDurationUnit(final String unitString) { switch (unitString) { case "": // Fallthrough expected case "ms": - return TimeUnit.MILLISECONDS; + return Optional.of(TimeUnit.MILLISECONDS); case "s": - return TimeUnit.SECONDS; + return Optional.of(TimeUnit.SECONDS); case "m": - return TimeUnit.MINUTES; + return Optional.of(TimeUnit.MINUTES); case "h": - return TimeUnit.HOURS; + return Optional.of(TimeUnit.HOURS); case "d": - return TimeUnit.DAYS; + return Optional.of(TimeUnit.DAYS); default: - throw new ConfigurationException("Invalid duration string, found: " + unitString); + return Optional.empty(); } } diff --git a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java index a97b3071..60d7c5ff 100644 --- a/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java +++ b/fabric-chaincode-shim/src/test/java/ChaincodeWithoutPackageTest.java @@ -18,11 +18,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -public final class ChaincodeWithoutPackageTest { +final class ChaincodeWithoutPackageTest { private ChaincodeMockPeer server; @AfterEach - public void afterTest() throws Exception { + void afterTest() throws Exception { if (server != null) { server.stop(); server = null; @@ -30,7 +30,7 @@ public void afterTest() throws Exception { } @Test - public void testRegisterChaincodeWithoutPackage() throws Exception { + void testRegisterChaincodeWithoutPackage() throws Exception { final ChaincodeBase cb = new EmptyChaincodeWithoutPackage(); final List scenario = new ArrayList<>(); diff --git a/fabric-chaincode-shim/src/test/java/contract/Greeting.java b/fabric-chaincode-shim/src/test/java/contract/Greeting.java index 7f2a16f5..ac49bf4f 100644 --- a/fabric-chaincode-shim/src/test/java/contract/Greeting.java +++ b/fabric-chaincode-shim/src/test/java/contract/Greeting.java @@ -5,6 +5,8 @@ */ package contract; +import static org.assertj.core.api.Assertions.assertThat; + import org.hyperledger.fabric.contract.annotation.DataType; import org.hyperledger.fabric.contract.annotation.Property; import org.json.JSONObject; @@ -53,13 +55,8 @@ public Greeting(final String text) { public static void validate(final Greeting greeting) { final String text = greeting.text; - if (text.length() != greeting.textLength) { - throw new Error("Length incorrectly set"); - } - - if (text.split(" ").length != greeting.wordCount) { - throw new Error("Word count incorrectly set"); - } + assertThat(text).as("greeting length").hasSize(greeting.textLength); + assertThat(text.split(" ")).as("word count").hasSize(greeting.wordCount); } public String toJSONString() { diff --git a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java index a28a2924..426aab7c 100644 --- a/fabric-chaincode-shim/src/test/java/contract/SampleContract.java +++ b/fabric-chaincode-shim/src/test/java/contract/SampleContract.java @@ -24,6 +24,7 @@ license = @License(name = "fred", url = "http://fred.me"), version = "0.0.1", title = "samplecontract")) +@SuppressWarnings("PMD.SystemPrintln") @Default() public class SampleContract implements ContractInterface { public static int getBeforeInvoked() { @@ -109,7 +110,7 @@ public String t3(final Context ctx, final String exception, final String message throw new ChaincodeException(message, "T3ERR1"); } } else { - throw new RuntimeException(message); + throw new IllegalArgumentException(message); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java index 62751cef..90c327d6 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggerTest.java @@ -9,15 +9,15 @@ import org.hyperledger.fabric.contract.ContractRuntimeException; import org.junit.jupiter.api.Test; -public class LoggerTest { +class LoggerTest { @Test - public void logger() { + void logger() { Logger.getLogger(LoggerTest.class); Logger.getLogger(LoggerTest.class.getName()); } @Test - public void testContractException() { + void testContractException() { final Logger logger = Logger.getLogger(LoggerTest.class); final ContractRuntimeException cre1 = new ContractRuntimeException(""); @@ -32,7 +32,7 @@ public void testContractException() { } @Test - public void testDebug() { + void testDebug() { Logger.getLogger(LoggerTest.class).debug("debug message"); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java index c4b22d47..98c5dde8 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/LoggingTest.java @@ -15,9 +15,9 @@ import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; -public final class LoggingTest { +final class LoggingTest { @Test - public void testMapLevel() { + void testMapLevel() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { assertEquals(Level.SEVERE, proxyMapLevel("ERROR"), "Error maps"); assertEquals(Level.SEVERE, proxyMapLevel("critical"), "Critical maps"); @@ -30,23 +30,15 @@ public void testMapLevel() { assertEquals(Level.INFO, proxyMapLevel(new Object[] {null}), "Info maps"); } - public Object proxyMapLevel(final Object... args) { - - try { - final Method m = Logging.class.getDeclaredMethod("mapLevel", String.class); - m.setAccessible(true); - return m.invoke(null, args); - } catch (NoSuchMethodException - | SecurityException - | IllegalAccessException - | IllegalArgumentException - | InvocationTargetException e) { - throw new RuntimeException(e); - } + private Object proxyMapLevel(final Object... args) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + final Method m = Logging.class.getDeclaredMethod("mapLevel", String.class); + m.setAccessible(true); + return m.invoke(null, args); } @Test - public void testFormatError() { + void testFormatError() { final Exception e1 = new Exception("Computer says no"); assertThat(Logging.formatError(e1), containsString("Computer says no")); @@ -61,7 +53,7 @@ public void testFormatError() { } @Test - public void testSetLogLevel() { + void testSetLogLevel() { final java.util.logging.Logger l = java.util.logging.Logger.getLogger("org.hyperledger.fabric.test"); final java.util.logging.Logger another = java.util.logging.Logger.getLogger("acme.wibble"); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java index 8c48b8b5..2aa32cfe 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/TestUtil.java @@ -108,7 +108,6 @@ public static String createCertWithIdentityAttributes(final String attributeValu final X509CertificateHolder builtCert = certBuilder.build(contentSigner); final X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X509") .generateCertificate(new ByteArrayInputStream(builtCert.getEncoded())); - final String encodedCert = Base64.getEncoder().encodeToString(certificate.getEncoded()); - return encodedCert; + return Base64.getEncoder().encodeToString(certificate.getEncoded()); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java index 86cee5cf..4b4ed224 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/AllTypesAsset.java @@ -122,7 +122,13 @@ public void setTheCustomObject(final MyType customObject) { this.theCustomObject = customObject; } - public boolean equals(final AllTypesAsset obj) { + @Override + public boolean equals(final Object other) { + if (!(other instanceof AllTypesAsset)) { + return false; + } + + AllTypesAsset obj = (AllTypesAsset) other; return theByte == obj.getTheByte() && theShort == obj.getTheShort() && theInt == obj.getTheInt() @@ -135,18 +141,15 @@ public boolean equals(final AllTypesAsset obj) { @Override public String toString() { - final StringBuilder builder = new StringBuilder(System.lineSeparator()); - builder.append("byte=" + theByte).append(System.lineSeparator()); - builder.append("short=" + theShort).append(System.lineSeparator()); - builder.append("int=" + theInt).append(System.lineSeparator()); - builder.append("long=" + theLong).append(System.lineSeparator()); - builder.append("float=" + theFloat).append(System.lineSeparator()); - builder.append("double=" + theDouble).append(System.lineSeparator()); - builder.append("boolean=" + theBoolean).append(System.lineSeparator()); - builder.append("char=" + theChar).append(System.lineSeparator()); - builder.append("String=" + theString).append(System.lineSeparator()); - builder.append("Mytype=" + theCustomObject).append(System.lineSeparator()); - - return builder.toString(); + return System.lineSeparator() + "byte=" + theByte + System.lineSeparator() + "short=" + + theShort + System.lineSeparator() + "int=" + + theInt + System.lineSeparator() + "long=" + + theLong + System.lineSeparator() + "float=" + + theFloat + System.lineSeparator() + "double=" + + theDouble + System.lineSeparator() + "boolean=" + + theBoolean + System.lineSeparator() + "char=" + + theChar + System.lineSeparator() + "String=" + + theString + System.lineSeparator() + "Mytype=" + + theCustomObject + System.lineSeparator(); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java index 0054c1d6..ad475730 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ChaincodeStubNaiveImpl.java @@ -60,7 +60,9 @@ public ChaincodeStubNaiveImpl() { @Override public List getArgs() { if (argsAsByte == null) { - argsAsByte = args.stream().map(i -> i.getBytes()).collect(Collectors.toList()); + argsAsByte = args.stream() + .map(arg -> arg.getBytes(StandardCharsets.UTF_8)) + .collect(Collectors.toList()); } return argsAsByte; } @@ -259,7 +261,7 @@ public byte[] getCreator() { @Override public Map getTransient() { - return null; + return new HashMap<>(); } @Override @@ -269,7 +271,7 @@ public byte[] getBinding() { void setStringArgs(final List args) { this.args = args; - this.argsAsByte = args.stream().map(i -> i.getBytes()).collect(Collectors.toList()); + this.argsAsByte = args.stream().map(String::getBytes).collect(Collectors.toList()); } public byte[] buildSerializedIdentity() { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java index 9f85095d..f1da45ed 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ClientIdentityTest.java @@ -16,10 +16,10 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.jupiter.api.Test; -public class ClientIdentityTest { +final class ClientIdentityTest { /** Test client identity can be created using certificate without attributes */ @Test - public void clientIdentityWithoutAttributes() throws Exception { + void clientIdentityWithoutAttributes() throws Exception { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); final ClientIdentity identity = new ClientIdentity(stub); assertEquals(identity.getMSPID(), "testMSPID"); @@ -39,7 +39,7 @@ public void clientIdentityWithoutAttributes() throws Exception { /** Test client identity can be created using certificate with attributes */ @Test - public void clientIdentityWithAttributes() throws Exception { + void clientIdentityWithAttributes() throws Exception { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.CERT_WITH_ATTRS); final ClientIdentity identity = new ClientIdentity(stub); @@ -58,7 +58,7 @@ public void clientIdentityWithAttributes() throws Exception { /** Test client identity can be created using certificate with multiple attributes */ @Test - public void clientIdentityWithMultipleAttributes() throws Exception { + void clientIdentityWithMultipleAttributes() throws Exception { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.CERT_MULTIPLE_ATTRIBUTES); final ClientIdentity identity = new ClientIdentity(stub); @@ -81,7 +81,7 @@ public void clientIdentityWithMultipleAttributes() throws Exception { /** Test client identity can be created using certificate with long distinguished name */ @Test - public void clientIdentityWithLongDNs() throws Exception { + void clientIdentityWithLongDNs() throws Exception { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); ((ChaincodeStubNaiveImpl) stub).setCertificate(TestUtil.CERT_WITH_DNS); final ClientIdentity identity = new ClientIdentity(stub); @@ -100,7 +100,7 @@ public void clientIdentityWithLongDNs() throws Exception { /** Test client identity throws a ContractRuntimeException when creating a serialized identity fails */ @Test - public void catchInvalidProtocolBufferException() { + void catchInvalidProtocolBufferException() { final ChaincodeStub stub = mock(ChaincodeStub.class); when(stub.getCreator()).thenReturn("somethingInvalid".getBytes()); @@ -111,7 +111,7 @@ public void catchInvalidProtocolBufferException() { /** Test client identity attributes are empty when using a certificate with dummy attributes */ @Test - public void createClientIdentityWithDummyAttributesCert() throws Exception { + void createClientIdentityWithDummyAttributesCert() throws Exception { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); // Create a certificate with rubbish attributes final String certWithDummyAttrs = diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java index d0c6c393..4686080b 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextFactoryTest.java @@ -14,17 +14,17 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.jupiter.api.Test; -public class ContextFactoryTest { +final class ContextFactoryTest { @Test - public void getInstance() { + void getInstance() { final ContextFactory f1 = ContextFactory.getInstance(); final ContextFactory f2 = ContextFactory.getInstance(); assertThat(f1, sameInstance(f2)); } @Test - public void createContext() { + void createContext() { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); final Context ctx = ContextFactory.getInstance().createContext(stub); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java index 405e68ff..85aa8b75 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContextTest.java @@ -11,11 +11,11 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.jupiter.api.Test; -public class ContextTest { +final class ContextTest { /** Test creating a new context returns what we expect */ @Test - public void getInstance() { + void getInstance() { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); final Context context1 = new Context(stub); final Context context2 = new Context(stub); @@ -24,7 +24,7 @@ public void getInstance() { /** Test identity created in Context constructor matches getClientIdentity */ @Test - public void getSetClientIdentity() { + void getSetClientIdentity() { final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); final Context context = ContextFactory.getInstance().createContext(stub); assertThat(context.getClientIdentity(), sameInstance(context.clientIdentity)); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java index e3fcdd6a..7df683c4 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractInterfaceTest.java @@ -13,16 +13,15 @@ import org.hyperledger.fabric.shim.ChaincodeException; import org.junit.jupiter.api.Test; -public class ContractInterfaceTest { +final class ContractInterfaceTest { @Test - public void createContext() { + void createContext() { assertThat( - (new ContractInterface() {}).createContext(new ChaincodeStubNaiveImpl()), - is(instanceOf(Context.class))); + new ContractInterface() {}.createContext(new ChaincodeStubNaiveImpl()), is(instanceOf(Context.class))); } @Test - public void unknownTransaction() { + void unknownTransaction() { final ContractInterface c = new ContractInterface() {}; assertThatThrownBy(() -> c.unknownTransaction(c.createContext(new ChaincodeStubNaiveImpl()))) @@ -31,14 +30,14 @@ public void unknownTransaction() { } @Test - public void beforeTransaction() { + void beforeTransaction() { final ContractInterface c = new ContractInterface() {}; c.beforeTransaction(c.createContext(new ChaincodeStubNaiveImpl())); } @Test - public void afterTransaction() { + void afterTransaction() { final ContractInterface c = new ContractInterface() {}; c.afterTransaction(c.createContext(new ChaincodeStubNaiveImpl()), "ReturnValue"); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java index b5692cc2..210321be 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/ContractRouterTest.java @@ -28,9 +28,9 @@ import org.hyperledger.fabric.shim.NettyChaincodeServer; import org.junit.jupiter.api.Test; -public class ContractRouterTest { +final class ContractRouterTest { @Test - public void testCreateFailsWithoutValidOptions() { + void testCreateFailsWithoutValidOptions() { assertThatThrownBy(() -> new ContractRouter(new String[] {})) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("The chaincode id must be specified using either the -i or --i command " @@ -38,7 +38,7 @@ public void testCreateFailsWithoutValidOptions() { } @Test - public void testCreateAndScan() { + void testCreateAndScan() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -58,7 +58,7 @@ public void testCreateAndScan() { } @Test - public void testInit() { + void testInit() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -86,7 +86,7 @@ public void testInit() { /** Test invoking two transaction functions in a contract via fully qualified name */ @Test - public void testInvokeTwoTxnsThatExist() { + void testInvokeTwoTxnsThatExist() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -133,7 +133,7 @@ public void testInvokeTwoTxnsThatExist() { } @Test - public void testInvokeTxnWithDefinedName() { + void testInvokeTxnWithDefinedName() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -161,7 +161,7 @@ public void testInvokeTxnWithDefinedName() { /** Test invoking two transaction functions in a contract via default name name */ @Test - public void testInvokeTwoTxnsWithDefaultNamespace() { + void testInvokeTwoTxnsWithDefaultNamespace() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -208,7 +208,7 @@ public void testInvokeTwoTxnsWithDefaultNamespace() { } @Test - public void testInvokeTxnWithDefinedNameUsingMethodName() { + void testInvokeTxnWithDefinedNameUsingMethodName() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -235,7 +235,7 @@ public void testInvokeTxnWithDefinedNameUsingMethodName() { } @Test - public void testInvokeContractThatDoesNotExist() { + void testInvokeContractThatDoesNotExist() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -262,7 +262,7 @@ public void testInvokeContractThatDoesNotExist() { } @Test - public void testInvokeTxnThatDoesNotExist() { + void testInvokeTxnThatDoesNotExist() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -289,7 +289,7 @@ public void testInvokeTxnThatDoesNotExist() { } @Test - public void testInvokeTxnThatReturnsNullString() { + void testInvokeTxnThatReturnsNullString() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -316,7 +316,7 @@ public void testInvokeTxnThatReturnsNullString() { } @Test - public void testInvokeTxnThatThrowsAnException() { + void testInvokeTxnThatThrowsAnException() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -342,7 +342,7 @@ public void testInvokeTxnThatThrowsAnException() { } @Test - public void testInvokeTxnThatThrowsAChaincodeException() { + void testInvokeTxnThatThrowsAChaincodeException() { final ContractRouter r = new ContractRouter(new String[] {"-a", "127.0.0.1:7052", "-i", "testId"}); r.findAllContracts(); final ChaincodeStub s = new ChaincodeStubNaiveImpl(); @@ -369,14 +369,14 @@ public void testInvokeTxnThatThrowsAChaincodeException() { /** Test confirming ContractRuntimeExceptions can be created. */ @Test - public void createContractRuntimeExceptions() { + void createContractRuntimeExceptions() { final ContractRuntimeException cre1 = new ContractRuntimeException("failure"); new ContractRuntimeException("another failure", cre1); new ContractRuntimeException(new Exception("cause")); } @Test - public void testStartingContractRouterWithStartingAChaincodeServer() throws IOException { + void testStartingContractRouterWithStartingAChaincodeServer() throws IOException { ChaincodeServerProperties chaincodeServerProperties = new ChaincodeServerProperties(); chaincodeServerProperties.setServerAddress(new InetSocketAddress("0.0.0.0", 9999)); final ContractRouter r = new ContractRouter(new String[] {"-i", "testId"}); @@ -397,12 +397,12 @@ public void testStartingContractRouterWithStartingAChaincodeServer() throws IOEx e.printStackTrace(); } - final ChaincodeStub s = new ChaincodeStubNaiveImpl(); + final ChaincodeStubNaiveImpl s = new ChaincodeStubNaiveImpl(); final List args = new ArrayList<>(); args.add("samplecontract:t1"); args.add("asdf"); - ((ChaincodeStubNaiveImpl) s).setStringArgs(args); + s.setStringArgs(args); SampleContract.setBeforeInvoked(0); SampleContract.setAfterInvoked(0); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java index 893aa81e..6cc39f0e 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/MyType.java @@ -27,12 +27,12 @@ public void setState(final String state) { @JSONPropertyIgnore() public boolean isStarted() { - return state.equals(STARTED); + return STARTED.equals(state); } @JSONPropertyIgnore() public boolean isStopped() { - return state.equals(STARTED); + return STOPPED.equals(state); } public MyType setValue(final String value) { diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java index 3cc4df28..dcf619ad 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/TransactionExceptionTest.java @@ -12,7 +12,7 @@ import org.hyperledger.fabric.shim.ChaincodeException; import org.junit.jupiter.api.Test; -public class TransactionExceptionTest { +final class TransactionExceptionTest { class MyTransactionException extends ChaincodeException { @@ -33,21 +33,21 @@ public byte[] getPayload() { } @Test - public void testNoArgConstructor() { + void testNoArgConstructor() { final ChaincodeException e = new ChaincodeException(); assertThat(e.getMessage(), is(nullValue())); assertThat(e.getPayload(), is(nullValue())); } @Test - public void testMessageArgConstructor() { + void testMessageArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure"); assertThat(e.getMessage(), is("Failure")); assertThat(e.getPayload(), is(nullValue())); } @Test - public void testCauseArgConstructor() { + void testCauseArgConstructor() { final ChaincodeException e = new ChaincodeException(new Error("Cause")); assertThat(e.getMessage(), is("java.lang.Error: Cause")); assertThat(e.getPayload(), is(nullValue())); @@ -55,7 +55,7 @@ public void testCauseArgConstructor() { } @Test - public void testMessageAndCauseArgConstructor() { + void testMessageAndCauseArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure", new Error("Cause")); assertThat(e.getMessage(), is("Failure")); assertThat(e.getPayload(), is(nullValue())); @@ -63,14 +63,14 @@ public void testMessageAndCauseArgConstructor() { } @Test - public void testMessageAndPayloadArgConstructor() { + void testMessageAndPayloadArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure", new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'}); assertThat(e.getMessage(), is("Failure")); assertThat(e.getPayload(), is(new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'})); } @Test - public void testMessagePayloadAndCauseArgConstructor() { + void testMessagePayloadAndCauseArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure", new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'}, new Error("Cause")); assertThat(e.getMessage(), is("Failure")); @@ -79,14 +79,14 @@ public void testMessagePayloadAndCauseArgConstructor() { } @Test - public void testMessageAndStringPayloadArgConstructor() { + void testMessageAndStringPayloadArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure", "Payload"); assertThat(e.getMessage(), is("Failure")); assertThat(e.getPayload(), is(new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'})); } @Test - public void testMessageStringPayloadAndCauseArgConstructor() { + void testMessageStringPayloadAndCauseArgConstructor() { final ChaincodeException e = new ChaincodeException("Failure", "Payload", new Error("Cause")); assertThat(e.getMessage(), is("Failure")); assertThat(e.getPayload(), is(new byte[] {'P', 'a', 'y', 'l', 'o', 'a', 'd'})); @@ -94,7 +94,7 @@ public void testMessageStringPayloadAndCauseArgConstructor() { } @Test - public void testSubclass() { + void testSubclass() { final ChaincodeException e = new MyTransactionException(1); assertThat(e.getMessage(), is("MyTransactionException")); assertThat(e.getPayload(), is(new byte[] {'E', '0', '0', '1'})); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java index 67d006d3..124ccbf9 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/ContractExecutionServiceTest.java @@ -33,9 +33,9 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.jupiter.api.Test; -public final class ContractExecutionServiceTest { +final class ContractExecutionServiceTest { @Test - public void noReturnValue() + void noReturnValue() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException { JSONTransactionSerializer jts = new JSONTransactionSerializer(); @@ -50,7 +50,7 @@ public void noReturnValue() ChaincodeStub stub = new ChaincodeStubNaiveImpl(); when(txFn.getRouting()).thenReturn(routing); - when(req.getArgs()).thenReturn(new ArrayList()); + when(req.getArgs()).thenReturn(new ArrayList<>()); when(routing.getMethod()) .thenReturn(SampleContract.class.getMethod("noReturn", new Class[] {Context.class})); when(routing.getContractInstance()).thenReturn(contract); @@ -61,7 +61,7 @@ public void noReturnValue() } @Test() - public void failureToInvoke() + void failureToInvoke() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException { JSONTransactionSerializer jts = new JSONTransactionSerializer(); @@ -76,7 +76,7 @@ public void failureToInvoke() ChaincodeStub stub = mock(ChaincodeStub.class); when(txFn.getRouting()).thenReturn(routing); - when(req.getArgs()).thenReturn(new ArrayList() {}); + when(req.getArgs()).thenReturn(new ArrayList<>() {}); when(routing.getContractInstance()).thenThrow(IllegalAccessException.class); when(routing.toString()).thenReturn("MockMethodName:MockClassName"); @@ -88,7 +88,7 @@ public void failureToInvoke() } @Test() - public void invokeWithDifferentSerializers() + void invokeWithDifferentSerializers() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { JSONTransactionSerializer defaultSerializer = spy(new JSONTransactionSerializer()); SerializerInterface customSerializer = mock(SerializerInterface.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java index eb15c8c9..15d0a52a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializerTest.java @@ -21,9 +21,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -public class JSONTransactionSerializerTest { +final class JSONTransactionSerializerTest { @Test - public void toBuffer() { + void toBuffer() { final TypeRegistry tr = TypeRegistry.getRegistry(); tr.addDataType(MyType.class); @@ -53,14 +53,12 @@ public void toBuffer() { final byte[] buffer = "[{\"value\":\"hello\"},{\"value\":\"world\"}]".getBytes(StandardCharsets.UTF_8); - System.out.println(new String(buffer, StandardCharsets.UTF_8)); - System.out.println(new String(bytes, StandardCharsets.UTF_8)); assertThat(bytes, equalTo(buffer)); } @Nested @DisplayName("Complex Data types") - class ComplexDataTypes { + final class ComplexDataTypes { @Test public void alltypes() { @@ -74,22 +72,18 @@ public void alltypes() { final AllTypesAsset all = new AllTypesAsset(); final TypeSchema ts = TypeSchema.typeConvert(AllTypesAsset.class); - System.out.println("TS = " + ts); final byte[] bytes = serializer.toBuffer(all, ts); - System.out.println("Data as toBuffer-ed " + new String(bytes, StandardCharsets.UTF_8)); final AllTypesAsset returned = (AllTypesAsset) serializer.fromBuffer(bytes, ts); - System.out.println("Start object = " + all); - System.out.println("Returned object = " + returned); assertTrue(all.equals(returned)); } } @Nested @DisplayName("Primitive Arrays") - class PrimitiveArrays { + final class PrimitiveArrays { @Test - public void ints() { + void ints() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); // convert array of primitive final int[] intarray = new int[] {42, 83}; @@ -101,7 +95,7 @@ public void ints() { } @Test - public void bytes() { + void bytes() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); // convert array of primitive final byte[] array = new byte[] {42, 83}; @@ -113,7 +107,7 @@ public void bytes() { } @Test - public void floats() { + void floats() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); // convert array of primitive final float[] array = new float[] {42.5F, 83.5F}; @@ -125,7 +119,7 @@ public void floats() { } @Test - public void booleans() { + void booleans() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); // convert array of primitive final boolean[] array = new boolean[] {true, false, true}; @@ -137,7 +131,7 @@ public void booleans() { } @Test - public void chars() { + void chars() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); // convert array of primitive final char[] array = new char[] {'a', 'b', 'c'}; @@ -151,9 +145,9 @@ public void chars() { @Nested @DisplayName("Nested Arrays") - class NestedArrays { + final class NestedArrays { @Test - public void ints() { + void ints() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); final int[][] array = new int[][] {{42, 83}, {83, 42}}; final byte[] bytes = serializer.toBuffer(array, TypeSchema.typeConvert(int[][].class)); @@ -164,7 +158,7 @@ public void ints() { } @Test - public void longs() { + void longs() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); final long[][] array = new long[][] {{42L, 83L}, {83L, 42L}}; final byte[] bytes = serializer.toBuffer(array, TypeSchema.typeConvert(long[][].class)); @@ -175,7 +169,7 @@ public void longs() { } @Test - public void doubles() { + void doubles() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); final double[][] array = new double[][] {{42.42d, 83.83d}, {83.23d, 42.33d}}; final byte[] bytes = serializer.toBuffer(array, TypeSchema.typeConvert(double[][].class)); @@ -186,7 +180,7 @@ public void doubles() { } @Test - public void bytes() { + void bytes() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); final byte[][] array = new byte[][] {{42, 83}, {83, 42}}; final byte[] bytes = serializer.toBuffer(array, TypeSchema.typeConvert(byte[][].class)); @@ -197,7 +191,7 @@ public void bytes() { } @Test - public void shorts() { + void shorts() { final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); final short[][] array = new short[][] {{42, 83}, {83, 42}}; final byte[] bytes = serializer.toBuffer(array, TypeSchema.typeConvert(short[][].class)); @@ -209,7 +203,7 @@ public void shorts() { } @Test - public void fromBufferObject() { + void fromBufferObject() { final byte[] buffer = "[{\"value\":\"hello\"},{\"value\":\"world\"}]".getBytes(StandardCharsets.UTF_8); final TypeRegistry tr = TypeRegistry.getRegistry(); @@ -226,7 +220,7 @@ public void fromBufferObject() { } @Test - public void toBufferPrimitive() { + void toBufferPrimitive() { final TypeRegistry tr = TypeRegistry.getRegistry(); final JSONTransactionSerializer serializer = new JSONTransactionSerializer(); @@ -267,7 +261,7 @@ public void toBufferPrimitive() { } @Test - public void fromBufferErrors() { + void fromBufferErrors() { final TypeRegistry tr = new TypeRegistryImpl(); tr.addDataType(MyType.class); MetadataBuilder.addComponent(tr.getDataType("MyType")); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java index 903a287f..2c55d199 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/MetadataBuilderTest.java @@ -7,7 +7,6 @@ import contract.SampleContract; import java.io.InputStream; -import java.io.Serializable; import java.lang.reflect.Field; import java.util.HashMap; import org.everit.json.schema.loader.SchemaClient; @@ -22,46 +21,27 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public final class MetadataBuilderTest { - private final String expectedMetadataString = " {\n" + " \"components\": {\"schemas\": {}},\n" - + " \"$schema\": \"https://fabric-shim.github.io/contract-schema.json\",\n" - + " \"contracts\": {\"SampleContract\": {\n" - + " \"name\": \"SampleContract\",\n" + " \"transactions\": [],\n" - + " \"info\": {\n" - + " \"license\": {\"name\": \"\"},\n" + " \"description\": \"\",\n" - + " \"termsOfService\": \"\",\n" - + " \"title\": \"\",\n" + " \"version\": \"\",\n" - + " \"contact\": {\"email\": \"fred@example.com\"}\n" - + " }\n" + " }},\n" + " \"info\": {\n" + " \"license\": {\"name\": \"\"},\n" - + " \"description\": \"\",\n" - + " \"termsOfService\": \"\",\n" + " \"title\": \"\",\n" - + " \"version\": \"\",\n" - + " \"contact\": {\"email\": \"fred@example.com\"}\n" + " }\n" + " }\n" + ""; - +final class MetadataBuilderTest { // fields are private, so use reflection to bypass this for unit testing - private void setMetadataBuilderField(final String name, final Object value) { - try { - final Field f = MetadataBuilder.class.getDeclaredField(name); - f.setAccessible(true); - f.set(null, value); - } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - throw new RuntimeException("Unable to set field " + e.getMessage()); - } + private void setMetadataBuilderField(final String name, final Object value) + throws NoSuchFieldException, IllegalAccessException { + final Field f = MetadataBuilder.class.getDeclaredField(name); + f.setAccessible(true); + f.set(null, value); } @BeforeEach @AfterEach - public void beforeAndAfterEach() { + void beforeAndAfterEach() throws NoSuchFieldException, IllegalAccessException { - setMetadataBuilderField("componentMap", new HashMap()); - setMetadataBuilderField("contractMap", new HashMap>()); - setMetadataBuilderField("overallInfoMap", new HashMap()); + setMetadataBuilderField("componentMap", new HashMap<>()); + setMetadataBuilderField("contractMap", new HashMap<>()); + setMetadataBuilderField("overallInfoMap", new HashMap<>()); setMetadataBuilderField("schemaClient", new DefaultSchemaClient()); } @Test - public void systemContract() { + void systemContract() { final SystemContract system = new SystemContract(); final ChaincodeStub stub = new ChaincodeStubNaiveImpl(); @@ -69,14 +49,14 @@ public void systemContract() { } @Test - public void defaultSchemasNotLoadedFromNetwork() { + void defaultSchemasNotLoadedFromNetwork() throws NoSuchFieldException, IllegalAccessException { final ContractDefinition contractDefinition = new ContractDefinitionImpl(SampleContract.class); MetadataBuilder.addContract(contractDefinition); setMetadataBuilderField("schemaClient", new SchemaClient() { @Override public InputStream get(final String uri) { - throw new RuntimeException("Refusing to load schema: " + uri); + throw new IllegalStateException("Refusing to load schema: " + uri); } }); MetadataBuilder.validate(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java index 4139c165..7274e654 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/metadata/TypeSchemaTest.java @@ -18,32 +18,29 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class TypeSchemaTest { +final class TypeSchemaTest { @BeforeEach - public void beforeEach() {} + void beforeEach() {} @Test - public void putIfNotNull() { + void putIfNotNull() { final TypeSchema ts = new TypeSchema(); - System.out.println("Key - value"); ts.putIfNotNull("Key", "value"); - System.out.println("Key - null"); final String nullstr = null; ts.putIfNotNull("Key", nullstr); assertThat(ts.get("Key"), equalTo("value")); - System.out.println("Key - "); ts.putIfNotNull("Key", ""); assertThat(ts.get("Key"), equalTo("value")); } @Test - public void getType() { + void getType() { final TypeSchema ts = new TypeSchema(); ts.put("type", "MyType"); assertThat(ts.getType(), equalTo("MyType")); @@ -54,7 +51,7 @@ public void getType() { } @Test - public void getFormat() { + void getFormat() { final TypeSchema ts = new TypeSchema(); ts.put("format", "MyFormat"); assertThat(ts.getFormat(), equalTo("MyFormat")); @@ -65,7 +62,7 @@ public void getFormat() { } @Test - public void getRef() { + void getRef() { final TypeSchema ts = new TypeSchema(); ts.put("$ref", "#/ref/to/MyType"); assertThat(ts.getRef(), equalTo("#/ref/to/MyType")); @@ -76,7 +73,7 @@ public void getRef() { } @Test - public void getItems() { + void getItems() { final TypeSchema ts1 = new TypeSchema(); final TypeSchema ts = new TypeSchema(); @@ -92,7 +89,7 @@ public void getItems() { class MyType {} @Test - public void getTypeClass() { + void getTypeClass() { final TypeSchema ts = new TypeSchema(); ts.put("type", "string"); @@ -139,7 +136,7 @@ public void getTypeClass() { } @Test - public void unknownConversions() { + void unknownConversions() { assertThrows(RuntimeException.class, () -> { final TypeSchema ts = new TypeSchema(); final TypeRegistry mockRegistry = new TypeRegistryImpl(); @@ -158,7 +155,7 @@ public void unknownConversions() { } @Test - public void typeConvertPrimitives() { + void typeConvertPrimitives() { TypeSchema rts; final String[] array = new String[] {}; @@ -188,7 +185,7 @@ public void typeConvertPrimitives() { } @Test - public void typeConvertObjects() { + void typeConvertObjects() { TypeSchema rts; rts = TypeSchema.typeConvert(String.class); assertThat(rts.getType(), equalTo("string")); @@ -223,7 +220,7 @@ public void typeConvertObjects() { } @Test - public void validate() { + void validate() { final TypeSchema ts = TypeSchema.typeConvert(org.hyperledger.fabric.contract.MyType.class); final DataTypeDefinition dtd = new DataTypeDefinitionImpl(org.hyperledger.fabric.contract.MyType.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java index a948720c..7ba81940 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java @@ -21,9 +21,9 @@ import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; import org.junit.jupiter.api.Test; -public class ContractDefinitionTest { +final class ContractDefinitionTest { @Test - public void constructor() throws NoSuchMethodException, SecurityException { + void constructor() throws NoSuchMethodException, SecurityException { final ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); assertThat(cf.toString(), startsWith("samplecontract:")); @@ -33,10 +33,10 @@ public void constructor() throws NoSuchMethodException, SecurityException { public class FailureTestObject {} private boolean fail; - private final int step = 1; + private static final int STEP = 1; @Test - public void unknownRoute() { + void unknownRoute() { final SecurityManager tmp = new SecurityManager() { private int count = 0; @@ -45,7 +45,7 @@ public void unknownRoute() { public void checkPackageAccess(final String pkg) { if (pkg.startsWith("org.hyperledger.fabric.contract")) { - if (count >= step) { + if (count >= STEP) { throw new SecurityException("Sorry I can't do that"); } count++; @@ -54,9 +54,7 @@ public void checkPackageAccess(final String pkg) { } @Override - public void checkPermission(final Permission perm) { - return; - } + public void checkPermission(final Permission perm) {} }; try { @@ -73,7 +71,7 @@ public void checkPermission(final Permission perm) { } @Test - public void duplicateTransaction() throws NoSuchMethodException, SecurityException { + void duplicateTransaction() throws NoSuchMethodException, SecurityException { final ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); final ContractInterface contract = new SampleContract(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java index f08e3bd4..84ca808c 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/DataTypeDefinitionTest.java @@ -5,37 +5,38 @@ */ package org.hyperledger.fabric.contract.routing; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasKey; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; import java.util.Map; import org.hyperledger.fabric.contract.MyType2; +import org.hyperledger.fabric.contract.metadata.TypeSchema; import org.hyperledger.fabric.contract.routing.impl.DataTypeDefinitionImpl; import org.junit.jupiter.api.Test; -public class DataTypeDefinitionTest { +final class DataTypeDefinitionTest { @Test - public void constructor() { + void constructor() { final DataTypeDefinitionImpl dtd = new DataTypeDefinitionImpl(MyType2.class); - assertThat(dtd.getTypeClass(), equalTo(MyType2.class)); - assertThat(dtd.getName(), equalTo("org.hyperledger.fabric.contract.MyType2")); - assertThat(dtd.getSimpleName(), equalTo("MyType2")); + assertThat(dtd.getTypeClass()).isEqualTo(MyType2.class); + assertThat(dtd.getName()).isEqualTo("org.hyperledger.fabric.contract.MyType2"); + assertThat(dtd.getSimpleName()).isEqualTo("MyType2"); final Map properties = dtd.getProperties(); - assertThat(properties.size(), equalTo(2)); - assertThat(properties, hasKey("value")); - assertThat(properties, hasKey("constrainedValue")); + assertThat(properties.size()).isEqualTo(2); + assertThat(properties).containsKey("value"); + assertThat(properties).containsKey("constrainedValue"); final PropertyDefinition pd = properties.get("constrainedValue"); - final Map ts = pd.getSchema(); + final TypeSchema ts = pd.getSchema(); - assertThat(ts, hasEntry("title", "MrProperty")); - assertThat(ts, hasEntry("Pattern", "[a-z]")); - assertThat(ts, hasEntry("uniqueItems", false)); - assertThat(ts, hasEntry("required", new String[] {"true", "false"})); - assertThat(ts, hasEntry("enum", new String[] {"a", "bee", "cee", "dee"})); - assertThat(ts, hasEntry("minimum", 42)); + assertThat(ts) + .contains( + entry("title", "MrProperty"), + entry("Pattern", "[a-z]"), + entry("uniqueItems", false), + entry("required", new String[] {"true", "false"}), + entry("enum", new String[] {"a", "bee", "cee", "dee"}), + entry("minimum", 42)); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java index 84524443..8349527b 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ParameterDefinitionTest.java @@ -13,9 +13,9 @@ import org.hyperledger.fabric.contract.routing.impl.ParameterDefinitionImpl; import org.junit.jupiter.api.Test; -public class ParameterDefinitionTest { +final class ParameterDefinitionTest { @Test - public void constructor() throws NoSuchMethodException, SecurityException { + void constructor() throws NoSuchMethodException, SecurityException { final Parameter[] params = String.class.getMethod("concat", String.class).getParameters(); final ParameterDefinition pd = new ParameterDefinitionImpl("test", String.class, new TypeSchema(), params[0]); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java index 9ec68a68..cb73dbca 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/PropertyDefinitionTest.java @@ -13,9 +13,9 @@ import org.hyperledger.fabric.contract.routing.impl.PropertyDefinitionImpl; import org.junit.jupiter.api.Test; -public class PropertyDefinitionTest { +final class PropertyDefinitionTest { @Test - public void constructor() throws NoSuchMethodException, SecurityException { + void constructor() throws NoSuchMethodException, SecurityException { final Field[] props = String.class.getFields(); final TypeSchema ts = new TypeSchema(); final PropertyDefinition pd = new PropertyDefinitionImpl("test", String.class, ts, props[0]); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java index 428a9483..d110dfa9 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TxFunctionTest.java @@ -24,7 +24,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public class TxFunctionTest { +final class TxFunctionTest { @Contract() class TestObject implements ContractInterface { @@ -39,7 +39,7 @@ public void wibble(final String arg1) {} } @Test - public void constructor() throws NoSuchMethodException, SecurityException { + void constructor() throws NoSuchMethodException, SecurityException { final TestObject test = new TestObject(); final ContractDefinition cd = mock(ContractDefinition.class); Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class)); @@ -53,7 +53,7 @@ public void constructor() throws NoSuchMethodException, SecurityException { } @Test - public void property() throws NoSuchMethodException, SecurityException { + void property() throws NoSuchMethodException, SecurityException { final TestObject test = new TestObject(); final ContractDefinition cd = mock(ContractDefinition.class); Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class)); @@ -70,12 +70,11 @@ public void property() throws NoSuchMethodException, SecurityException { final TypeSchema ts = new TypeSchema(); txfn.setReturnSchema(ts); final TypeSchema rts = txfn.getReturnSchema(); - System.out.println(ts); assertEquals(ts, rts); } @Test - public void invaldtxfn() throws NoSuchMethodException, SecurityException { + void invaldtxfn() throws NoSuchMethodException, SecurityException { final TestObject test = new TestObject(); final ContractDefinition cd = mock(ContractDefinition.class); Mockito.when(cd.getAnnotation()).thenReturn(test.getClass().getAnnotation(Contract.class)); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java index 16c59648..7c38c01b 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/TypeRegistryTest.java @@ -13,9 +13,9 @@ import org.hyperledger.fabric.contract.routing.impl.TypeRegistryImpl; import org.junit.jupiter.api.Test; -public class TypeRegistryTest { +final class TypeRegistryTest { @Test - public void addDataType() { + void addDataType() { final TypeRegistryImpl tr = new TypeRegistryImpl(); tr.addDataType(String.class); @@ -24,7 +24,7 @@ public void addDataType() { } @Test - public void addDataTypeDefinition() { + void addDataTypeDefinition() { final DataTypeDefinitionImpl dtd = new DataTypeDefinitionImpl(String.class); final TypeRegistryImpl tr = new TypeRegistryImpl(); tr.addDataType(dtd); @@ -34,7 +34,7 @@ public void addDataTypeDefinition() { } @Test - public void getAllDataTypes() { + void getAllDataTypes() { final TypeRegistryImpl tr = new TypeRegistryImpl(); tr.addDataType(String.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java index 489919d4..1b292661 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/simplepath/ContractSimplePathTest.java @@ -31,14 +31,14 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -public final class ContractSimplePathTest { +final class ContractSimplePathTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); private ChaincodeMockPeer server; @AfterEach - public void afterTest() throws Exception { + void afterTest() throws Exception { if (server != null) { server.stop(); server = null; @@ -51,7 +51,7 @@ public void afterTest() throws Exception { * @throws Exception */ @Test - public void testContract() throws Exception { + void testContract() throws Exception { final List scenario = new ArrayList<>(); scenario.add(new RegisterStep()); @@ -66,7 +66,7 @@ public void testContract() throws Exception { setLogLevel("INFO"); } - public ChaincodeMessage newInvokeFn(final String[] args) { + private ChaincodeMessage newInvokeFn(final String[] args) { final Builder invokePayload = ChaincodeInput.newBuilder(); for (final String arg : args) { invokePayload.addArgs(ByteString.copyFromUtf8(arg)); @@ -76,12 +76,12 @@ public ChaincodeMessage newInvokeFn(final String[] args) { TRANSACTION, "testChannel", "0", invokePayload.build().toByteString(), null); } - public String getLastReturnString() throws Exception { + private String getLastReturnString() throws Exception { final Response resp = Response.parseFrom(server.getLastMessageRcvd().getPayload()); - return (resp.getPayload().toStringUtf8()); + return resp.getPayload().toStringUtf8(); } - public void setLogLevel(final String logLevel) { + private void setLogLevel(final String logLevel) { environmentVariables.set("CORE_CHAINCODE_LOGGING_SHIM", logLevel); environmentVariables.set("CORE_CHAINCODE_LOGGING_LEVEL", logLevel); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java index 42800291..fac77201 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/ledger/LedgerTest.java @@ -12,10 +12,10 @@ import org.hyperledger.fabric.contract.Context; import org.junit.jupiter.api.Test; -public class LedgerTest { +final class LedgerTest { @Test - public void getLedger() { + void getLedger() { final Context ctx = mock(Context.class); final Ledger ledger = Ledger.getLedger(ctx); @@ -29,7 +29,7 @@ public void getLedger() { } @Test - public void getCollection() { + void getCollection() { final Context ctx = mock(Context.class); final Ledger ledger = Ledger.getLedger(ctx); @@ -44,7 +44,7 @@ public void getCollection() { } @Test - public void getNamedCollection() { + void getNamedCollection() { final Context ctx = mock(Context.class); final Ledger ledger = Ledger.getLedger(ctx); @@ -57,7 +57,7 @@ public void getNamedCollection() { } @Test - public void getOrganizationCollection() { + void getOrganizationCollection() { final Context ctx = mock(Context.class); final Ledger ledger = Ledger.getLedger(ctx); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java index eb562ade..8da2694f 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/MetricsTest.java @@ -16,9 +16,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -public class MetricsTest { +final class MetricsTest { - public static class TestProvider implements MetricsProvider { + private static final class TestProvider implements MetricsProvider { public TestProvider() {} @@ -31,16 +31,16 @@ public void initialize(final Properties props) {} @Nested @DisplayName("Metrics initialize") - class Initialize { + final class Initialize { @Test - public void metricsDisabled() { + void metricsDisabled() { final MetricsProvider provider = Metrics.initialize(new Properties()); assertThat(provider).isExactlyInstanceOf(NullProvider.class); } @Test - public void metricsEnabledUnknownProvider() { + void metricsEnabledUnknownProvider() { final Properties props = new Properties(); props.put("CHAINCODE_METRICS_PROVIDER", "org.example.metrics.provider"); props.put("CHAINCODE_METRICS_ENABLED", "true"); @@ -54,7 +54,7 @@ public void metricsEnabledUnknownProvider() { } @Test - public void metricsNoProvider() { + void metricsNoProvider() { final Properties props = new Properties(); props.put("CHAINCODE_METRICS_ENABLED", "true"); @@ -63,7 +63,7 @@ public void metricsNoProvider() { } @Test - public void metricsValid() { + void metricsValid() { final Properties props = new Properties(); props.put("CHAINCODE_METRICS_PROVIDER", MetricsTest.TestProvider.class.getName()); props.put("CHAINCODE_METRICS_ENABLED", "true"); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java index 0da931aa..a3fecb8d 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/metrics/impl/DefaultProviderTest.java @@ -13,17 +13,16 @@ import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; -import org.hyperledger.fabric.metrics.MetricsProvider; import org.hyperledger.fabric.metrics.TaskMetricsCollector; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; -public class DefaultProviderTest { +final class DefaultProviderTest { @Test - public void allMethods() { - MetricsProvider provider = new DefaultProvider(); + void allMethods() throws InterruptedException { + DefaultProvider provider = new DefaultProvider(); provider.setTaskMetricsCollector(new TaskMetricsCollector() { @Override @@ -73,13 +72,8 @@ public int getActiveCount() { perfLogger.addHandler(mockHandler); provider.initialize(new Properties()); - ((DefaultProvider) provider).logMetrics(); - try { - Thread.sleep(6000); - } catch (InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } + provider.logMetrics(); + Thread.sleep(6000); Mockito.verify(mockHandler, Mockito.atLeast(1)).publish(argumentCaptor.capture()); LogRecord lr = argumentCaptor.getValue(); String msg = lr.getMessage(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java index 7cd97a1a..894c60fe 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeBaseTest.java @@ -34,12 +34,12 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -public class ChaincodeBaseTest { +final class ChaincodeBaseTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @Test - public void testNewSuccessResponseEmpty() { + void testNewSuccessResponseEmpty() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse(); assertThat(response.getStatus()) .as("Response status") @@ -49,7 +49,7 @@ public void testNewSuccessResponseEmpty() { } @Test - public void testNewSuccessResponseWithMessage() { + void testNewSuccessResponseWithMessage() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message"); assertThat(response.getStatus()) @@ -60,7 +60,7 @@ public void testNewSuccessResponseWithMessage() { } @Test - public void testNewSuccessResponseWithPayload() { + void testNewSuccessResponseWithPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple payload".getBytes(Charset.defaultCharset())); assertThat(response.getStatus()) @@ -73,7 +73,7 @@ public void testNewSuccessResponseWithPayload() { } @Test - public void testNewSuccessResponseWithMessageAndPayload() { + void testNewSuccessResponseWithMessageAndPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newSuccessResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); assertThat(response.getStatus()) @@ -86,7 +86,7 @@ public void testNewSuccessResponseWithMessageAndPayload() { } @Test - public void testNewErrorResponseEmpty() { + void testNewErrorResponseEmpty() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(); assertThat(response.getStatus()) .as("Response status") @@ -96,7 +96,7 @@ public void testNewErrorResponseEmpty() { } @Test - public void testNewErrorResponseWithMessage() { + void testNewErrorResponseWithMessage() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message"); assertThat(response.getStatus()) @@ -107,7 +107,7 @@ public void testNewErrorResponseWithMessage() { } @Test - public void testNewErrorResponseWithPayload() { + void testNewErrorResponseWithPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple payload".getBytes(Charset.defaultCharset())); assertThat(response.getStatus()) @@ -120,7 +120,7 @@ public void testNewErrorResponseWithPayload() { } @Test - public void testNewErrorResponseWithMessageAndPayload() { + void testNewErrorResponseWithMessageAndPayload() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse("Simple message", "Simple payload".getBytes(Charset.defaultCharset())); assertThat(response.getStatus()) @@ -133,7 +133,7 @@ public void testNewErrorResponseWithMessageAndPayload() { } @Test - public void testNewErrorResponseWithException() { + void testNewErrorResponseWithException() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new Exception("Simple exception")); assertThat(response.getStatus()) @@ -144,7 +144,7 @@ public void testNewErrorResponseWithException() { } @Test - public void testNewErrorResponseWithChaincodeException() { + void testNewErrorResponseWithChaincodeException() { final org.hyperledger.fabric.shim.Chaincode.Response response = ResponseUtils.newErrorResponse(new ChaincodeException("Chaincode exception")); assertThat(response.getStatus()) @@ -155,7 +155,7 @@ public void testNewErrorResponseWithChaincodeException() { } @Test - public void testOptions() throws Exception { + void testOptions() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); assertThat(cb.getHost()).as("Host incorrect").isEqualTo(ChaincodeBase.DEFAULT_HOST); @@ -197,7 +197,7 @@ public void testOptions() throws Exception { } @Test - public void testUnsetOptionId() { + void testUnsetOptionId() { final ChaincodeBase cb = new EmptyChaincode(); assertThatThrownBy(cb::validateOptions) .isInstanceOf(IllegalArgumentException.class) @@ -205,7 +205,7 @@ public void testUnsetOptionId() { } @Test - public void testUnsetOptionClientCertPath() { + void testUnsetOptionClientCertPath() { final ChaincodeBase cb = new EmptyChaincode(); environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); environmentVariables.set("CORE_PEER_TLS_ENABLED", "true"); @@ -216,7 +216,7 @@ public void testUnsetOptionClientCertPath() { } @Test - public void testUnsetOptionClientKeyPath() { + void testUnsetOptionClientKeyPath() { final ChaincodeBase cb = new EmptyChaincode(); environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); environmentVariables.set("CORE_PEER_TLS_ENABLED", "true"); @@ -229,7 +229,7 @@ public void testUnsetOptionClientKeyPath() { @Test @Disabled - public void testNewChannelBuilder() throws Exception { + void testNewChannelBuilder() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); @@ -245,7 +245,7 @@ public void testNewChannelBuilder() throws Exception { } @Test - public void testInitializeLogging() { + void testInitializeLogging() { final ChaincodeBase cb = new EmptyChaincode(); cb.processEnvironmentOptions(); @@ -291,7 +291,7 @@ public void testInitializeLogging() { } @Test - public void testStartFailsWithoutValidOptions() { + void testStartFailsWithoutValidOptions() { final String[] args = new String[0]; final ChaincodeBase cb = new EmptyChaincode(); @@ -311,7 +311,7 @@ public void testStartFailsWithoutValidOptions() { "The chaincode id must be specified using either the -i or --i command line options or the CORE_CHAINCODE_ID_NAME environment variable."); } - public static void setLogLevelForChaincode( + private static void setLogLevelForChaincode( final EnvironmentVariables environmentVariables, final ChaincodeBase cb, final String shimLevel, @@ -323,7 +323,7 @@ public static void setLogLevelForChaincode( } @Test - public void connectChaincodeBase() throws IOException { + void connectChaincodeBase() throws IOException { final ChaincodeBase cb = new EmptyChaincode(); environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); @@ -337,7 +337,7 @@ public void connectChaincodeBase() throws IOException { Metrics.initialize(props); Traces.initialize(props); - cb.connectToPeer(new StreamObserver() { + cb.connectToPeer(new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage value) {} @@ -354,7 +354,7 @@ public void onCompleted() {} } @Test - public void connectChaincodeBaseNull() { + void connectChaincodeBaseNull() { Assertions.assertThrows(IllegalArgumentException.class, () -> { final ChaincodeBase cb = new EmptyChaincode(); cb.connectToPeer(null); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java index 3ab40706..3d143458 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeServerImplTest.java @@ -18,7 +18,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -class ChaincodeServerImplTest { +final class ChaincodeServerImplTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java index ccf3185a..0a583dea 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeStubTest.java @@ -19,9 +19,10 @@ import org.hyperledger.fabric.shim.ledger.QueryResultsIteratorWithMetadata; import org.junit.jupiter.api.Test; -public class ChaincodeStubTest { +final class ChaincodeStubTest { - class FakeStub implements ChaincodeStub { + @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") + private static final class FakeStub implements ChaincodeStub { @Override public List getArgs() { @@ -289,13 +290,13 @@ public String getMspId() { } @Test - public void testDefaultMethods() { + void testDefaultMethods() { final ChaincodeStub stub = new FakeStub(); final String chaincodeName = "ACME_SHIPPING"; - stub.invokeChaincode(chaincodeName, new ArrayList()); - stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList(), "channel"); - stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList()); + stub.invokeChaincode(chaincodeName, new ArrayList<>()); + stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList<>(), "channel"); + stub.invokeChaincodeWithStringArgs(chaincodeName, new ArrayList<>()); stub.invokeChaincodeWithStringArgs(chaincodeName, "anvil", "tnt"); stub.getStringState("key"); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java index 7b70b388..2eaa38ca 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChaincodeTest.java @@ -11,9 +11,9 @@ import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; -public class ChaincodeTest { +final class ChaincodeTest { @Test - public void testResponse() { + void testResponse() { final Chaincode.Response resp = new Chaincode.Response( Chaincode.Response.Status.SUCCESS, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus()); @@ -22,7 +22,7 @@ public void testResponse() { } @Test - public void testResponseWithCode() { + void testResponseWithCode() { Chaincode.Response resp = new Chaincode.Response(200, "No message", "no payload".getBytes(StandardCharsets.UTF_8)); assertThat(Chaincode.Response.Status.SUCCESS).as("Incorrect status").isEqualTo(resp.getStatus()); @@ -46,7 +46,7 @@ public void testResponseWithCode() { } @Test - public void testStatus() { + void testStatus() { assertThat(Chaincode.Response.Status.SUCCESS) .as("Wrong status") .isEqualTo(Chaincode.Response.Status.forCode(200)); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java index d3832502..d6093a5d 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ChatChaincodeWithPeerTest.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.List; import java.util.Properties; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.hyperledger.fabric.metrics.Metrics; import org.hyperledger.fabric.protos.peer.ChaincodeID; @@ -42,7 +41,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -class ChatChaincodeWithPeerTest { +final class ChatChaincodeWithPeerTest { private static final String TEST_CHANNEL = "testChannel"; @SystemStub @@ -138,6 +137,7 @@ void connectNull() throws IOException { } @Test + @SuppressWarnings("PMD.SystemPrintln") void connectAndReceiveRegister() throws IOException { environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); ChaincodeBase chaincodeBase = new EmptyChaincode(); @@ -149,32 +149,31 @@ void connectAndReceiveRegister() throws IOException { Metrics.initialize(props); ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase); - final StreamObserver connect = - chatChaincodeWithPeer.connect(new StreamObserver() { - @Override - public void onNext(final ChaincodeMessage value) { - assertEquals(ChaincodeMessage.Type.REGISTER, value.getType()); - assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8()); - } - - @Override - public void onError(final Throwable t) { - assertNull(t); - } - - @Override - public void onCompleted() {} - }); + final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver<>() { + @Override + public void onNext(final ChaincodeMessage value) { + assertEquals(ChaincodeMessage.Type.REGISTER, value.getType()); + assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8()); + } + + @Override + public void onError(final Throwable t) { + assertNull(t); + } + + @Override + public void onCompleted() {} + }); assertNotNull(connect); - final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder() + final ByteString payload = ChaincodeInput.newBuilder() .addArgs(ByteString.copyFromUtf8("")) .build() .toByteString(); final ChaincodeMessage initMsg = MessageUtil.newEventMessage(INIT, TEST_CHANNEL, "0", payload, null); connect.onNext(initMsg); - try { + { final List args = Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList()); final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder() @@ -182,7 +181,7 @@ public void onCompleted() {} .setName(chaincodeBase.getId()) .build()) .setInput(ChaincodeInput.newBuilder() - .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())) + .addAllArgs(args.stream().map(ByteString::copyFrom).collect(toList())) .build()) .build() .toByteString(); @@ -195,11 +194,9 @@ public void onCompleted() {} .build(); connect.onNext(invokeChaincodeMessage); System.out.println(invokeChaincodeMessage.getPayload().toStringUtf8()); - } catch (Exception e) { - } - try { + { final List args = Stream.of("invoke", "a", "1").map(x -> x.getBytes(UTF_8)).collect(toList()); final ByteString invocationSpecPayload = ChaincodeSpec.newBuilder() @@ -207,7 +204,7 @@ public void onCompleted() {} .setName(chaincodeBase.getId()) .build()) .setInput(ChaincodeInput.newBuilder() - .addAllArgs(args.stream().map(ByteString::copyFrom).collect(Collectors.toList())) + .addAllArgs(args.stream().map(ByteString::copyFrom).collect(toList())) .build()) .build() .toByteString(); @@ -220,8 +217,6 @@ public void onCompleted() {} .build(); connect.onNext(invokeChaincodeMessage); System.out.println(invokeChaincodeMessage.getPayload().toStringUtf8()); - } catch (Exception e) { - } } @@ -237,22 +232,21 @@ void connectAndReceiveRegisterComplete() throws IOException { Metrics.initialize(props); ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase); - final StreamObserver connect = - chatChaincodeWithPeer.connect(new StreamObserver() { - @Override - public void onNext(final ChaincodeMessage value) { - assertEquals(ChaincodeMessage.Type.REGISTER, value.getType()); - assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8()); - } - - @Override - public void onError(final Throwable t) { - assertNull(t); - } - - @Override - public void onCompleted() {} - }); + final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver<>() { + @Override + public void onNext(final ChaincodeMessage value) { + assertEquals(ChaincodeMessage.Type.REGISTER, value.getType()); + assertEquals("\u0012\u0004mycc", value.getPayload().toStringUtf8()); + } + + @Override + public void onError(final Throwable t) { + assertNull(t); + } + + @Override + public void onCompleted() {} + }); connect.onCompleted(); } @@ -268,21 +262,21 @@ void connectAndReceiveRegisterException() throws IOException { Metrics.initialize(props); ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(chaincodeBase); - final StreamObserver connect = - chatChaincodeWithPeer.connect(new StreamObserver() { - @Override - public void onNext(final ChaincodeMessage value) {} + final StreamObserver connect = chatChaincodeWithPeer.connect(new StreamObserver<>() { + @Override + public void onNext(final ChaincodeMessage value) {} - @Override - public void onError(final Throwable t) {} + @Override + public void onError(final Throwable t) {} - @Override - public void onCompleted() {} - }); + @Override + public void onCompleted() {} + }); connect.onError(new Exception("some_error")); } @Test + @SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes") void connectOnCompletedException() throws IOException { environmentVariables.set("CORE_CHAINCODE_ID_NAME", "mycc"); ChaincodeBase chaincodeBase = new EmptyChaincode(); @@ -297,19 +291,18 @@ void connectOnCompletedException() throws IOException { Assertions.assertDoesNotThrow( () -> { - final StreamObserver connect = - chatChaincodeWithPeer.connect(new StreamObserver() { - @Override - public void onNext(final ChaincodeMessage value) {} - - @Override - public void onError(final Throwable t) {} - - @Override - public void onCompleted() { - throw new RuntimeException("some_error"); - } - }); + chatChaincodeWithPeer.connect(new StreamObserver<>() { + @Override + public void onNext(final ChaincodeMessage value) {} + + @Override + public void onError(final Throwable t) {} + + @Override + public void onCompleted() { + throw new RuntimeException("some_error"); + } + }); }, "some_error"); } @@ -323,7 +316,7 @@ void testMockChaincodeBase() throws IOException { ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(mockChaincodeBase); assertNotNull(chatChaincodeWithPeer); - assertNull(chatChaincodeWithPeer.connect(new StreamObserver() { + assertNull(chatChaincodeWithPeer.connect(new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage value) {} @@ -346,7 +339,7 @@ void testMockChaincodeBaseThrowIOException() throws IOException { ChatChaincodeWithPeer chatChaincodeWithPeer = new ChatChaincodeWithPeer(mockChaincodeBase); assertNotNull(chatChaincodeWithPeer); - assertNull(chatChaincodeWithPeer.connect(new StreamObserver() { + assertNull(chatChaincodeWithPeer.connect(new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage value) {} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java index 87e8474e..05bfb3ff 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/NettyGrpcServerTest.java @@ -21,7 +21,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -class NettyGrpcServerTest { +final class NettyGrpcServerTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java index 3983ce57..3ab30011 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/StateBasedEndorsementTest.java @@ -10,9 +10,9 @@ import org.junit.jupiter.api.Test; -public class StateBasedEndorsementTest { +final class StateBasedEndorsementTest { @Test - public void testRoleType() { + void testRoleType() { assertThat(StateBasedEndorsement.RoleType.forVal("MEMBER")) .isEqualTo(StateBasedEndorsement.RoleType.RoleTypeMember); assertThat(StateBasedEndorsement.RoleType.forVal("PEER")) diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java index 750e24f0..c980b5a2 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementFactoryTest.java @@ -11,15 +11,15 @@ import org.junit.jupiter.api.Test; -public class StateBasedEndorsementFactoryTest { +final class StateBasedEndorsementFactoryTest { @Test - public void getInstance() { + void getInstance() { assertNotNull(StateBasedEndorsementFactory.getInstance()); assertInstanceOf(StateBasedEndorsementFactory.class, StateBasedEndorsementFactory.getInstance()); } @Test - public void newStateBasedEndorsement() { + void newStateBasedEndorsement() { assertNotNull(StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(new byte[] {})); assertThatThrownBy(() -> StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(new byte[] {0})) .isInstanceOf(IllegalArgumentException.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java index 195a672e..fe6482fb 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImplTest.java @@ -20,10 +20,10 @@ import org.hyperledger.fabric.shim.ext.sbe.StateBasedEndorsement.RoleType; import org.junit.jupiter.api.Test; -public class StateBasedEndorsementImplTest { +final class StateBasedEndorsementImplTest { @Test - public void addOrgs() { + void addOrgs() { // add an org final StateBasedEndorsement ep = StateBasedEndorsementFactory.getInstance().newStateBasedEndorsement(null); @@ -39,7 +39,7 @@ public void addOrgs() { } @Test - public void delOrgs() { + void delOrgs() { final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER) .toByteString() @@ -66,7 +66,7 @@ public void delOrgs() { } @Test - public void listOrgs() { + void listOrgs() { final byte[] initEPBytes = StateBasedEndorsementUtils.signedByFabricEntity("Org1", MSPRoleType.PEER) .toByteString() .toByteArray(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java index 490be49b..0148486a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/fvt/ChaincodeFVTest.java @@ -61,7 +61,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -public final class ChaincodeFVTest { +final class ChaincodeFVTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @@ -69,7 +69,7 @@ public final class ChaincodeFVTest { private ChaincodeMockPeer server; @AfterEach - public void afterTest() throws Exception { + void afterTest() throws Exception { if (server != null) { server.stop(); server = null; @@ -77,7 +77,7 @@ public void afterTest() throws Exception { } @Test - public void testRegister() throws Exception { + void testRegister() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); final List scenario = new ArrayList<>(); @@ -94,7 +94,7 @@ public void testRegister() throws Exception { } @Test - public void testRegisterAndEmptyInit() throws Exception { + void testRegisterAndEmptyInit() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -107,7 +107,7 @@ public Response invoke(final ChaincodeStub stub) { } }; - final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder() + final ByteString payload = ChaincodeInput.newBuilder() .addArgs(ByteString.copyFromUtf8("")) .build() .toByteString(); @@ -130,7 +130,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testInitAndInvoke() throws Exception { + void testInitAndInvoke() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -204,7 +204,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testStateValidationParameter() throws Exception { + void testStateValidationParameter() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -272,7 +272,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testInvokeRangeQ() throws Exception { + void testInvokeRangeQ() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -351,7 +351,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testGetQueryResult() throws Exception { + void testGetQueryResult() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -426,7 +426,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testGetHistoryForKey() throws Exception { + void testGetHistoryForKey() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -490,7 +490,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testInvokeChaincode() throws Exception { + void testInvokeChaincode() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -540,7 +540,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testErrorInitInvoke() throws Exception { + void testErrorInitInvoke() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { @@ -553,7 +553,7 @@ public Response invoke(final ChaincodeStub stub) { } }; - final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder() + final ByteString payload = ChaincodeInput.newBuilder() .addArgs(ByteString.copyFromUtf8("")) .build() .toByteString(); @@ -575,9 +575,9 @@ public Response invoke(final ChaincodeStub stub) { assertThat(server.getLastMessageSend().getType(), is(INIT)); assertThat(server.getLastMessageRcvd().getType(), is(COMPLETED)); - String resp1 = (Response.parseFrom(server.getLastMessageRcvd().getPayload()) + String resp1 = Response.parseFrom(server.getLastMessageRcvd().getPayload()) .getPayload() - .toStringUtf8()); + .toStringUtf8(); assertThat(resp1, is("Wrong response1")); final ByteString invokePayload = ChaincodeInput.newBuilder().build().toByteString(); @@ -596,13 +596,13 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testStreamShutdown() throws Exception { + void testStreamShutdown() throws Exception { final ChaincodeBase cb = new ChaincodeBase() { @Override public Response init(final ChaincodeStub stub) { try { Thread.sleep(10); - } catch (final InterruptedException e) { + } catch (final InterruptedException ignored) { } return ResponseUtils.newSuccessResponse(); } @@ -613,7 +613,7 @@ public Response invoke(final ChaincodeStub stub) { } }; - final ByteString payload = org.hyperledger.fabric.protos.peer.ChaincodeInput.newBuilder() + final ByteString payload = ChaincodeInput.newBuilder() .addArgs(ByteString.copyFromUtf8("")) .build() .toByteString(); @@ -634,7 +634,7 @@ public Response invoke(final ChaincodeStub stub) { } @Test - public void testChaincodeLogLevel() throws Exception { + void testChaincodeLogLevel() throws Exception { final ChaincodeBase cb = new EmptyChaincode(); final List scenario = new ArrayList<>(); @@ -652,7 +652,7 @@ public void testChaincodeLogLevel() throws Exception { "Wrong debug level for " + cb.getClass().getPackage().getName()); } - public void setLogLevel(final String logLevel) { + private void setLogLevel(final String logLevel) { environmentVariables.set("CORE_CHAINCODE_LOGGING_SHIM", logLevel); environmentVariables.set("CORE_CHAINCODE_LOGGING_LEVEL", logLevel); } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java index 2a7c561e..ca152f9a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeMessageFactoryTest.java @@ -15,7 +15,7 @@ import org.hyperledger.fabric.shim.ResponseUtils; import org.junit.jupiter.api.Test; -class ChaincodeMessageFactoryTest { +final class ChaincodeMessageFactoryTest { private final String txId = "txid"; private final String key = "key"; diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java index 2bdf9c87..369f22cc 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/ChaincodeSupportClientTest.java @@ -24,7 +24,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -class ChaincodeSupportClientTest { +final class ChaincodeSupportClientTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @@ -74,7 +74,7 @@ void testStartInvocationTaskManagerNullAndRequestObserver() throws IOException { assertThatThrownBy( () -> { - chaincodeSupportClient.start(null, new StreamObserver() { + chaincodeSupportClient.start(null, new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage value) {} diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java index fd51e718..a7f1348a 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InnvocationTaskManagerTest.java @@ -28,7 +28,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; @ExtendWith(SystemStubsExtension.class) -class InnvocationTaskManagerTest { +final class InnvocationTaskManagerTest { @SystemStub private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java index b053a869..63aa35f0 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationStubImplTest.java @@ -25,21 +25,21 @@ import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -public class InvocationStubImplTest { +final class InvocationStubImplTest { private final String channelId = "mychannel"; private final String txId = "0xCAFEBABE"; private final String simpleKeyStartNamespace = new String(Character.toChars(0x000001)); @Nested - class GetStateByRangeTests { + final class GetStateByRangeTests { private InvocationStubImpl stubImpl; private ArgumentCaptor chaincodeMessageCaptor; private ChaincodeInvocationTask mockHandler; @BeforeEach - public void beforeEach() throws Exception { + void beforeEach() throws Exception { final ChaincodeMessage mockMessage = ChaincodeMessageFactory.newGetStateEventMessage(channelId, txId, "", "key"); mockHandler = mock(ChaincodeInvocationTask.class); @@ -52,7 +52,7 @@ public void beforeEach() throws Exception { } @Test - public void regular() throws InvalidProtocolBufferException { + void regular() throws InvalidProtocolBufferException { final QueryResultsIterator qri = stubImpl.getStateByRange("Aardvark", "Zebra"); verify(mockHandler).invoke(chaincodeMessageCaptor.capture()); @@ -68,7 +68,7 @@ public void regular() throws InvalidProtocolBufferException { } @Test - public void nullvalues() throws InvalidProtocolBufferException { + void nullvalues() throws InvalidProtocolBufferException { final QueryResultsIterator qri = stubImpl.getStateByRange(null, null); verify(mockHandler).invoke(chaincodeMessageCaptor.capture()); @@ -85,7 +85,7 @@ public void nullvalues() throws InvalidProtocolBufferException { } @Test - public void unbounded() throws InvalidProtocolBufferException { + void unbounded() throws InvalidProtocolBufferException { final QueryResultsIterator qri = stubImpl.getStateByRange("", ""); verify(mockHandler).invoke(chaincodeMessageCaptor.capture()); @@ -102,7 +102,7 @@ public void unbounded() throws InvalidProtocolBufferException { } @Test - public void simplekeys() { + void simplekeys() { assertThatThrownBy(() -> { final QueryResultsIterator qri = stubImpl.getStateByRange(new String(Character.toChars(Character.MIN_CODE_POINT)), ""); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java index 7fd6b760..a7299c53 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/InvocationTaskManagerTest.java @@ -23,14 +23,14 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public final class InvocationTaskManagerTest { +final class InvocationTaskManagerTest { private InvocationTaskManager itm; private ChaincodeBase chaincode; private Logger perfLogger; @BeforeEach - public void setup() { + void setup() { Metrics.initialize(new Properties()); Traces.initialize(new Properties()); @@ -45,19 +45,19 @@ public void setup() { } @AfterEach - public void teardown() { + void teardown() { itm.shutdown(); perfLogger.setLevel(Level.INFO); } @Test - public void register() throws UnsupportedEncodingException { + void register() throws UnsupportedEncodingException { itm.register(); } @Test - public void onMessageTestTx() throws UnsupportedEncodingException { + void onMessageTestTx() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage( ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); @@ -68,7 +68,7 @@ public void onMessageTestTx() throws UnsupportedEncodingException { } @Test - public void onWrongCreatedState() throws UnsupportedEncodingException { + void onWrongCreatedState() throws UnsupportedEncodingException { perfLogger.setLevel(Level.ALL); final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage( @@ -80,7 +80,7 @@ public void onWrongCreatedState() throws UnsupportedEncodingException { } @Test - public void onWrongEstablishedState() throws UnsupportedEncodingException { + void onWrongEstablishedState() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage( ChaincodeMessage.Type.TRANSACTION, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); @@ -93,7 +93,7 @@ public void onWrongEstablishedState() throws UnsupportedEncodingException { } @Test - public void onErrorResponse() throws UnsupportedEncodingException { + void onErrorResponse() throws UnsupportedEncodingException { final ChaincodeMessage msg = ChaincodeMessageFactory.newEventMessage( ChaincodeMessage.Type.ERROR, "mychannel", "txid", ByteString.copyFrom("Hello", "UTF-8")); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java index 2dc72dc9..28527224 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyModificationImplTest.java @@ -7,25 +7,18 @@ package org.hyperledger.fabric.shim.impl; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.google.protobuf.ByteString; import com.google.protobuf.Timestamp; -import java.time.Instant; import java.util.stream.Stream; import org.hyperledger.fabric.shim.ledger.KeyModification; import org.junit.jupiter.api.Test; -public class KeyModificationImplTest { +final class KeyModificationImplTest { @Test - public void testKeyModificationImpl() { + void testKeyModificationImpl() { new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setTxId("txid") .setValue(ByteString.copyFromUtf8("value")) @@ -35,72 +28,70 @@ public void testKeyModificationImpl() { } @Test - public void testGetTxId() { + void testGetTxId() { final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setTxId("txid") .build()); - assertThat(km.getTxId(), is(equalTo("txid"))); + assertThat(km.getTxId()).isEqualTo("txid"); } @Test - public void testGetValue() { + void testGetValue() { final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setValue(ByteString.copyFromUtf8("value")) .build()); - assertThat(km.getValue(), is(equalTo("value".getBytes(UTF_8)))); + assertThat(km.getValue()).isEqualTo("value".getBytes(UTF_8)); } @Test - public void testGetStringValue() { + void testGetStringValue() { final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setValue(ByteString.copyFromUtf8("value")) .build()); - assertThat(km.getStringValue(), is(equalTo("value"))); + assertThat(km.getStringValue()).isEqualTo("value"); } @Test - public void testGetTimestamp() { + void testGetTimestamp() { final KeyModification km = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setTimestamp( Timestamp.newBuilder().setSeconds(1234567890L).setNanos(123456789)) .build()); - assertThat(km.getTimestamp(), hasProperty("epochSecond", equalTo(1234567890L))); - assertThat(km.getTimestamp(), hasProperty("nano", equalTo(123456789))); + assertThat(km.getTimestamp().getEpochSecond()).isEqualTo(1234567890L); + assertThat(km.getTimestamp().getNano()).isEqualTo(123456789); } @Test - public void testIsDeleted() { + void testIsDeleted() { Stream.of(true, false).forEach(b -> { final KeyModification km = new KeyModificationImpl( org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setIsDelete(b) .build()); - assertThat(km.isDeleted(), is(b)); + assertThat(km.isDeleted()).isEqualTo(b); }); } @Test - public void testHashCode() { - final KeyModification km = + void testHashCode() { + final KeyModification km1 = + new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() + .setIsDelete(false) + .build()); + final KeyModification km2 = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setIsDelete(false) .build()); - int expectedHashCode = 31; - expectedHashCode = expectedHashCode + 1237; - expectedHashCode = expectedHashCode * 31 + Instant.EPOCH.hashCode(); - expectedHashCode = expectedHashCode * 31 + "".hashCode(); - expectedHashCode = expectedHashCode * 31 + ByteString.copyFromUtf8("").hashCode(); - - assertEquals(expectedHashCode, km.hashCode(), "Wrong hash code"); + assertThat(km1.hashCode()).isEqualTo(km2.hashCode()); } @Test - public void testEquals() { + void testEquals() { final KeyModification km1 = new KeyModificationImpl(org.hyperledger.fabric.protos.ledger.queryresult.KeyModification.newBuilder() .setIsDelete(false) @@ -115,7 +106,7 @@ public void testEquals() { .setIsDelete(false) .build()); - assertFalse(km1.equals(km2)); - assertTrue(km1.equals(km3)); + assertThat(km1).isNotEqualTo(km2); + assertThat(km1).isEqualTo(km3); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java index 3b8bbf43..219aaf46 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/KeyValueImplTest.java @@ -7,21 +7,16 @@ package org.hyperledger.fabric.shim.impl; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.google.protobuf.ByteString; import org.hyperledger.fabric.protos.ledger.queryresult.KV; import org.junit.jupiter.api.Test; -public class KeyValueImplTest { +final class KeyValueImplTest { @Test - public void testKeyValueImpl() { + void testKeyValueImpl() { new KeyValueImpl(KV.newBuilder() .setKey("key") .setValue(ByteString.copyFromUtf8("value")) @@ -29,45 +24,42 @@ public void testKeyValueImpl() { } @Test - public void testGetKey() { + void testGetKey() { final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder() .setKey("key") .setValue(ByteString.copyFromUtf8("value")) .build()); - assertThat(kv.getKey(), is(equalTo("key"))); + assertThat(kv.getKey()).isEqualTo("key"); } @Test - public void testGetValue() { + void testGetValue() { final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder() .setKey("key") .setValue(ByteString.copyFromUtf8("value")) .build()); - assertThat(kv.getValue(), is(equalTo("value".getBytes(UTF_8)))); + assertThat(kv.getValue()).isEqualTo("value".getBytes(UTF_8)); } @Test - public void testGetStringValue() { + void testGetStringValue() { final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder() .setKey("key") .setValue(ByteString.copyFromUtf8("value")) .build()); - assertThat(kv.getStringValue(), is(equalTo("value"))); + assertThat(kv.getStringValue()).isEqualTo("value"); } @Test - public void testHashCode() { - final KeyValueImpl kv = new KeyValueImpl(KV.newBuilder().build()); + void testHashCode() { + final KeyValueImpl kv1 = new KeyValueImpl(KV.newBuilder().build()); + final KeyValueImpl kv2 = new KeyValueImpl(KV.newBuilder().build()); - int expectedHashCode = 31; - expectedHashCode = expectedHashCode + "".hashCode(); - expectedHashCode = expectedHashCode * 31 + ByteString.copyFromUtf8("").hashCode(); - - assertEquals(expectedHashCode, kv.hashCode(), "Wrong hashcode"); + assertThat(kv1.hashCode()).isEqualTo(kv2.hashCode()); } @Test - public void testEquals() { + void testEquals() { final KeyValueImpl kv1 = new KeyValueImpl(KV.newBuilder() .setKey("a") .setValue(ByteString.copyFromUtf8("valueA")) @@ -88,8 +80,8 @@ public void testEquals() { .setValue(ByteString.copyFromUtf8("valueA")) .build()); - assertFalse(kv1.equals(kv2)); - assertFalse(kv1.equals(kv3)); - assertTrue(kv1.equals(kv4)); + assertThat(kv1).isNotEqualTo(kv2); + assertThat(kv1).isNotEqualTo(kv3); + assertThat(kv1).isEqualTo(kv4); } } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java index 3d1b299f..73cc0079 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorWithMetadataImplTest.java @@ -6,9 +6,8 @@ package org.hyperledger.fabric.shim.impl; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.google.protobuf.ByteString; import java.util.function.Function; @@ -17,33 +16,24 @@ import org.hyperledger.fabric.protos.peer.QueryResultBytes; import org.junit.jupiter.api.Test; -public class QueryResultsIteratorWithMetadataImplTest { +final class QueryResultsIteratorWithMetadataImplTest { + private static final Function QUERY_RESULT_BYTES_TO_KV = queryResultBytes -> 0; @Test - public void getMetadata() { + void getMetadata() { final QueryResultsIteratorWithMetadataImpl testIter = new QueryResultsIteratorWithMetadataImpl<>( - null, "", "", prepareQueryResponse().toByteString(), queryResultBytesToKv); - assertThat(testIter.getMetadata().getBookmark(), is("asdf")); - assertThat(testIter.getMetadata().getFetchedRecordsCount(), is(2)); + null, "", "", prepareQueryResponse().toByteString(), QUERY_RESULT_BYTES_TO_KV); + assertThat(testIter.getMetadata().getBookmark()).isEqualTo("asdf"); + assertThat(testIter.getMetadata().getFetchedRecordsCount()).isEqualTo(2); } @Test - public void getInvalidMetadata() { - try { - new QueryResultsIteratorWithMetadataImpl<>( - null, "", "", prepareQueryResponseWrongMeta().toByteString(), queryResultBytesToKv); - fail(); - } catch (final RuntimeException e) { - } + void getInvalidMetadata() { + assertThatThrownBy(() -> new QueryResultsIteratorWithMetadataImpl<>( + null, "", "", prepareQueryResponseWrongMeta().toByteString(), QUERY_RESULT_BYTES_TO_KV)) + .isInstanceOf(RuntimeException.class); } - private final Function queryResultBytesToKv = new Function() { - @Override - public Integer apply(final QueryResultBytes queryResultBytes) { - return 0; - } - }; - private QueryResponse prepareQueryResponse() { final QueryResponseMetadata qrm = QueryResponseMetadata.newBuilder() .setBookmark("asdf") diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java index d2bac2f8..21293a01 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/ledger/CompositeKeyTest.java @@ -16,20 +16,20 @@ import java.util.Arrays; import org.junit.jupiter.api.Test; -public class CompositeKeyTest { +final class CompositeKeyTest { @Test - public void testValidateSimpleKeys() { + void testValidateSimpleKeys() { CompositeKey.validateSimpleKeys("abc", "def", "ghi"); } @Test - public void testValidateSimpleKeysException() { + void testValidateSimpleKeysException() { assertThatThrownBy(() -> CompositeKey.validateSimpleKeys("\u0000abc")) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testCompositeKeyStringStringArray() { + void testCompositeKeyStringStringArray() { final CompositeKey key = new CompositeKey("abc", "def", "ghi", "jkl", "mno"); assertThat(key.getObjectType(), is(equalTo("abc"))); assertThat(key.getAttributes(), hasSize(4)); @@ -37,7 +37,7 @@ public void testCompositeKeyStringStringArray() { } @Test - public void testCompositeKeyStringListOfString() { + void testCompositeKeyStringListOfString() { final CompositeKey key = new CompositeKey("abc", Arrays.asList("def", "ghi", "jkl", "mno")); assertThat(key.getObjectType(), is(equalTo("abc"))); assertThat(key.getAttributes(), hasSize(4)); @@ -45,7 +45,7 @@ public void testCompositeKeyStringListOfString() { } @Test - public void testEmptyAttributes() { + void testEmptyAttributes() { final CompositeKey key = new CompositeKey("abc"); assertThat(key.getObjectType(), is(equalTo("abc"))); assertThat(key.getAttributes(), hasSize(0)); @@ -53,37 +53,37 @@ public void testEmptyAttributes() { } @Test - public void testCompositeKeyWithInvalidObjectTypeDelimiter() { + void testCompositeKeyWithInvalidObjectTypeDelimiter() { assertThatThrownBy(() -> new CompositeKey("ab\u0000c", Arrays.asList("def", "ghi", "jkl", "mno"))) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testCompositeKeyWithInvalidAttributeDelimiter() { + void testCompositeKeyWithInvalidAttributeDelimiter() { assertThatThrownBy(() -> new CompositeKey("abc", Arrays.asList("def", "ghi", "j\u0000kl", "mno"))) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testCompositeKeyWithInvalidObjectTypeMaxCodePoint() { + void testCompositeKeyWithInvalidObjectTypeMaxCodePoint() { assertThatThrownBy(() -> new CompositeKey("ab\udbff\udfffc", Arrays.asList("def", "ghi", "jkl", "mno"))) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testCompositeKeyWithInvalidAttributeMaxCodePoint() { + void testCompositeKeyWithInvalidAttributeMaxCodePoint() { assertThatThrownBy(() -> new CompositeKey("abc", Arrays.asList("def", "ghi", "jk\udbff\udfffl", "mno"))) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testGetObjectType() { + void testGetObjectType() { final CompositeKey key = new CompositeKey("abc", Arrays.asList("def", "ghi", "jkl", "mno")); assertThat(key.getObjectType(), is(equalTo("abc"))); } @Test - public void testGetAttributes() { + void testGetAttributes() { final CompositeKey key = new CompositeKey("abc", Arrays.asList("def", "ghi", "jkl", "mno")); assertThat(key.getObjectType(), is(equalTo("abc"))); assertThat(key.getAttributes(), hasSize(4)); @@ -91,13 +91,13 @@ public void testGetAttributes() { } @Test - public void testToString() { + void testToString() { final CompositeKey key = new CompositeKey("abc", Arrays.asList("def", "ghi", "jkl", "mno")); assertThat(key.toString(), is(equalTo("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"))); } @Test - public void testParseCompositeKey() { + void testParseCompositeKey() { final CompositeKey key = CompositeKey.parseCompositeKey("\u0000abc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000"); assertThat(key.getObjectType(), is(equalTo("abc"))); assertThat(key.getAttributes(), hasSize(4)); @@ -106,14 +106,14 @@ public void testParseCompositeKey() { } @Test - public void testParseCompositeKeyInvalidObjectType() { + void testParseCompositeKeyInvalidObjectType() { assertThatThrownBy(() -> CompositeKey.parseCompositeKey("ab\udbff\udfffc\u0000def\u0000ghi\u0000jkl\u0000mno\u0000")) .isInstanceOf(CompositeKeyFormatException.class); } @Test - public void testParseCompositeKeyInvalidAttribute() { + void testParseCompositeKeyInvalidAttribute() { assertThatThrownBy(() -> CompositeKey.parseCompositeKey("abc\u0000def\u0000ghi\u0000jk\udbff\udfffl\u0000mno\u0000")) .isInstanceOf(CompositeKeyFormatException.class); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java index 710b9eb0..cf89c888 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/ChaincodeMockPeer.java @@ -45,13 +45,14 @@ public ChaincodeMockPeer(final List scenario, final int port) { } /** Start serving requests. */ + @SuppressWarnings("PMD.SystemPrintln") public void start() throws IOException { server.start(); - LOGGER.info("Server started, listening on " + port); + LOGGER.info(() -> "Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - // Use stderr here since the logger may has been reset by its JVM shutdown hook. + // Use stderr here since the logger may have been reset by its JVM shutdown hook. System.err.println("*** shutting down gRPC server since JVM is shutting down"); ChaincodeMockPeer.this.stop(); System.err.println("*** server shut down"); @@ -65,7 +66,7 @@ public void stop() { server.shutdownNow(); try { server.awaitTermination(); - } catch (final InterruptedException e) { + } catch (final InterruptedException ignored) { } } } @@ -78,7 +79,7 @@ public void stop() { public void send(final ChaincodeMessage msg) { this.service.lastMessageSend = msg; - LOGGER.info("Mock peer => Sending message: " + msg); + LOGGER.info(() -> "Mock peer => Sending message: " + msg); this.service.send(msg); } @@ -96,7 +97,7 @@ public ChaincodeMessage getLastMessageRcvd() { return this.service.lastMessageRcvd; } - public ArrayList getAllReceivedMessages() { + public List getAllReceivedMessages() { return this.service.allMessages; } @@ -123,7 +124,7 @@ private static class ChaincodeMockPeerService extends ChaincodeSupportGrpc.Chain private int lastExecutedStepNumber; private ChaincodeMessage lastMessageRcvd; private ChaincodeMessage lastMessageSend; - private final ArrayList allMessages = new ArrayList<>(); + private final List allMessages = new ArrayList<>(); private StreamObserver observer; // create a lock, with fair property @@ -150,7 +151,7 @@ public void send(final ChaincodeMessage msg) { @Override public StreamObserver register(final StreamObserver responseObserver) { observer = responseObserver; - return new StreamObserver() { + return new StreamObserver<>() { /** * Handling incoming messages @@ -158,9 +159,10 @@ public StreamObserver register(final StreamObserver Got message: " + chaincodeMessage); + LOGGER.info(() -> "Mock peer => Got message: " + chaincodeMessage); ChaincodeMockPeerService.this.lastMessageRcvd = chaincodeMessage; ChaincodeMockPeerService.this.allMessages.add(chaincodeMessage); if (chaincodeMessage.getType().equals(PUT_STATE)) { @@ -178,11 +180,11 @@ public void onNext(final ChaincodeMessage chaincodeMessage) { final List nextSteps = step.next(); for (final ChaincodeMessage m : nextSteps) { ChaincodeMockPeerService.this.lastMessageSend = m; - LOGGER.info("Mock peer => Sending response message: " + m); + LOGGER.info(() -> "Mock peer => Sending response message: " + m); ChaincodeMockPeerService.this.send(m); } } else { - LOGGER.warning("Non expected message rcvd in step " + LOGGER.warning(() -> "Non expected message rcvd in step " + step.getClass().getSimpleName()); } ChaincodeMockPeerService.this.lastExecutedStepNumber++; @@ -194,7 +196,7 @@ public void onNext(final ChaincodeMessage chaincodeMessage) { @Override public void onError(final Throwable throwable) { - System.out.println(throwable); + throwable.printStackTrace(); } @Override @@ -203,6 +205,7 @@ public void onCompleted() {} } } + @SuppressWarnings("PMD.SystemPrintln") public static void checkScenarioStepEnded( final ChaincodeMockPeer s, final int step, final int timeout, final TimeUnit units) throws Exception { try { @@ -214,7 +217,7 @@ public static void checkScenarioStepEnded( } try { Thread.sleep(500); - } catch (final InterruptedException e) { + } catch (final InterruptedException ignored) { } } }), diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java index 96e2fcc0..c307d6ae 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/GetHistoryForKeyStep.java @@ -28,7 +28,7 @@ public final class GetHistoryForKeyStep implements ScenarioStep { * @param vals list of keys to generate ("key" => "key Value") pairs */ public GetHistoryForKeyStep(final boolean hasNext, final String... vals) { - this.values = vals; + this.values = Arrays.copyOf(vals, vals.length); this.hasNext = hasNext; } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java index 26c52724..69712719 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/shim/mock/peer/QueryResultStep.java @@ -29,7 +29,7 @@ public abstract class QueryResultStep implements ScenarioStep { * @param vals list of keys to generate ("key" => "key Value") pairs */ QueryResultStep(final boolean hasNext, final String... vals) { - this.values = vals; + this.values = Arrays.copyOf(vals, vals.length); this.hasNext = hasNext; } diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java index 51e0a1bf..f175484c 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/TracesTest.java @@ -19,9 +19,9 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -public class TracesTest { +final class TracesTest { - public static final class TestProvider implements TracesProvider { + private static final class TestProvider implements TracesProvider { public TestProvider() {} @@ -36,16 +36,16 @@ public Span createSpan(final ChaincodeStub stub) { @Nested @DisplayName("Traces initialize") - class Initialize { + final class Initialize { @Test - public void tracesDisabled() { + void tracesDisabled() { final TracesProvider provider = Traces.initialize(new Properties()); assertThat(provider).isExactlyInstanceOf(NullProvider.class); } @Test - public void tracesEnabledUnknownProvider() { + void tracesEnabledUnknownProvider() { final Properties props = new Properties(); props.put("CHAINCODE_TRACES_PROVIDER", "org.example.traces.provider"); props.put("CHAINCODE_TRACES_ENABLED", "true"); @@ -59,7 +59,7 @@ public void tracesEnabledUnknownProvider() { } @Test - public void tracesNoProvider() { + void tracesNoProvider() { final Properties props = new Properties(); props.put("CHAINCODE_TRACES_ENABLED", "true"); @@ -68,7 +68,7 @@ public void tracesNoProvider() { } @Test - public void tracesOpenTelemetryProvider() { + void tracesOpenTelemetryProvider() { final Properties props = new Properties(); props.put("CHAINCODE_TRACES_PROVIDER", "org.hyperledger.fabric.traces.impl.OpenTelemetryTracesProvider"); props.put("CHAINCODE_TRACES_ENABLED", "true"); @@ -78,7 +78,7 @@ public void tracesOpenTelemetryProvider() { } @Test - public void tracesValid() { + void tracesValid() { final Properties props = new Properties(); props.put("CHAINCODE_TRACES_PROVIDER", TracesTest.TestProvider.class.getName()); props.put("CHAINCODE_TRACES_ENABLED", "true"); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java index e36075fd..2c07a3d4 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/DefaultProviderTest.java @@ -12,10 +12,10 @@ import org.hyperledger.fabric.shim.ChaincodeStub; import org.junit.jupiter.api.Test; -public class DefaultProviderTest { +final class DefaultProviderTest { @Test - public void testDefaultProvider() { + void testDefaultProvider() { DefaultTracesProvider provider = new DefaultTracesProvider(); ChaincodeStub stub = new ChaincodeStubNaiveImpl(); Span span = provider.createSpan(stub); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java index 9c9278be..96d89537 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryPropertiesTest.java @@ -21,94 +21,94 @@ import java.util.Map; import org.junit.jupiter.api.Test; -public class OpenTelemetryPropertiesTest { +final class OpenTelemetryPropertiesTest { @Test - public void testOverrideValue() { + void testOverrideValue() { OpenTelemetryProperties props = new OpenTelemetryProperties( Collections.singletonMap("foo", "bar"), Collections.singletonMap("foo", "foobar")); assertThat(props.getString("foo")).isEqualTo("foobar"); } @Test - public void testCanGetDurationDays() { + void testCanGetDurationDays() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5d")); assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, DAYS)); } @Test - public void testCanGetDurationHours() { + void testCanGetDurationHours() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5h")); assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, HOURS)); } @Test - public void testCanGetDurationMinutes() { + void testCanGetDurationMinutes() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5m")); assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, MINUTES)); } @Test - public void testCanGetDurationSeconds() { + void testCanGetDurationSeconds() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5s")); assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, SECONDS)); } @Test - public void testCanGetDurationMilliSeconds() { + void testCanGetDurationMilliSeconds() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5ms")); assertThat(props.getDuration("foo")).isEqualTo(Duration.of(5, MILLIS)); } @Test - public void testCanGetDurationInvalid() { + void testCanGetDurationInvalid() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5foo")); assertThatThrownBy(() -> props.getDuration("foo")).isInstanceOf(ConfigurationException.class); } @Test - public void testGetDouble() { + void testGetDouble() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5.23")); assertThat(props.getDouble("foo")).isEqualTo(5.23d); assertThat(props.getDouble("bar")).isNull(); } @Test - public void testGetDoubleInvalid() { + void testGetDoubleInvalid() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "5foo")); assertThatThrownBy(() -> props.getDouble("foo")).isInstanceOf(ConfigurationException.class); } @Test - public void testGetLong() { + void testGetLong() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "500003")); assertThat(props.getLong("foo")).isEqualTo(500003L); assertThat(props.getLong("bar")).isNull(); } @Test - public void testGetInt() { + void testGetInt() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "500003")); assertThat(props.getInt("foo")).isEqualTo(500003); assertThat(props.getInt("bar")).isNull(); } @Test - public void testGetBoolean() { + void testGetBoolean() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "true")); assertThat(props.getBoolean("foo")).isTrue(); assertThat(props.getBoolean("bar")).isNull(); } @Test - public void testGetList() { + void testGetList() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "foo,bar,foobar")); assertThat(props.getList("foo")).isEqualTo(Arrays.asList("foo", "bar", "foobar")); assertThat(props.getList("bar")).isEqualTo(Collections.emptyList()); } @Test - public void testGetMap() { + void testGetMap() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "foo=bar,foobar=noes")); Map expected = new HashMap<>(); @@ -118,7 +118,7 @@ public void testGetMap() { } @Test - public void testGetMapInvalid() { + void testGetMapInvalid() { OpenTelemetryProperties props = new OpenTelemetryProperties(Collections.singletonMap("foo", "foo/bar,foobar/noes")); Map expected = new HashMap<>(); diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java index 6aeda3e8..af8689ef 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProviderTest.java @@ -37,7 +37,7 @@ import org.hyperledger.fabric.traces.Traces; import org.junit.jupiter.api.Test; -public final class OpenTelemetryTracesProviderTest { +final class OpenTelemetryTracesProviderTest { private final class ContextGetterChaincode extends ChaincodeBase { @@ -58,7 +58,7 @@ public Properties getChaincodeConfig() { } @Test - public void testProvider() { + void testProvider() { OpenTelemetryTracesProvider provider = new OpenTelemetryTracesProvider(); provider.initialize(new Properties()); ChaincodeStub stub = new ChaincodeStubNaiveImpl(); @@ -68,7 +68,7 @@ public void testProvider() { } @Test - public void testTracing() throws Exception { + void testTracing() throws Exception { Properties props = new Properties(); props.put("CHAINCODE_TRACES_ENABLED", "true"); @@ -82,7 +82,7 @@ public void testTracing() throws Exception { // set up a grpc server in process ServerCallHandler handler = (call, headers) -> { call.close(Status.OK, headers); - return new ServerCall.Listener() {}; + return new ServerCall.Listener<>() {}; }; ServerServiceDefinition.Builder builder = ServerServiceDefinition.builder(ChaincodeGrpc.getServiceDescriptor()) @@ -110,7 +110,7 @@ public void testTracing() throws Exception { CompletableFuture wait = new CompletableFuture<>(); StreamObserver requestObserver = chaincodeSupportClient .getStub() - .register(new StreamObserver() { + .register(new StreamObserver<>() { @Override public void onNext(final ChaincodeMessage chaincodeMessage) { // message off to the ITM... diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java index 5baa2ff9..95891c67 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/traces/impl/TestSpanExporterProvider.java @@ -21,7 +21,7 @@ public final class TestSpanExporterProvider implements ConfigurableSpanExporterP @Override public CompletableResultCode export(final Collection spans) { - TestSpanExporterProvider.SPANS.addAll(spans); + SPANS.addAll(spans); return CompletableResultCode.ofSuccess(); } diff --git a/pmd-ruleset.xml b/pmd-ruleset.xml new file mode 100644 index 00000000..3c886141 --- /dev/null +++ b/pmd-ruleset.xml @@ -0,0 +1,54 @@ + + + Custom PMD ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0d50c5f4cd9ed252523027d693b4c2b80473cda3 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 28 Nov 2024 02:22:59 +0000 Subject: [PATCH 018/178] Updates to test chaincode to exploit new microfab (#363) New microfab version provides an up-to-date Gradle version, which the test chaincode can be updated to exploit. This change also updates several dependencies to current versions. Signed-off-by: Mark S. Lewis --- .gitignore | 1 + build.gradle | 13 ++++---- fabric-chaincode-docker/Dockerfile | 32 +++++++++++-------- fabric-chaincode-integration-test/.gitignore | 1 + .../src/contracts/bare-gradle/build.gradle | 8 ++--- .../contracts/fabric-ledger-api/build.gradle | 4 +-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../contracts/fabric-shim-api/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- fabric-chaincode-shim/build.gradle | 10 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 11 files changed, 42 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 78211b3e..6512bbc6 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /build/ build/* settings-gradle.lockfile +config/ _cfg repository diff --git a/build.gradle b/build.gradle index 2540fb8a..654a4d7f 100644 --- a/build.gradle +++ b/build.gradle @@ -63,14 +63,15 @@ subprojects { dependencies { implementation 'commons-cli:commons-cli:1.9.0' implementation 'commons-logging:commons-logging:1.3.4' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0' - - testImplementation 'org.hamcrest:hamcrest-library:3.0' - testImplementation 'org.mockito:mockito-core:5.13.0' - testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.6' + testImplementation platform('org.junit:junit-bom:5.11.3') + testImplementation 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.26.3' + testImplementation 'org.mockito:mockito-core:5.14.2' + testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.7' + + testImplementation 'org.hamcrest:hamcrest-library:3.0' } test { diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 25fbde49..44a5a423 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,5 +1,7 @@ -FROM eclipse-temurin:11-jdk as builder -ENV DEBIAN_FRONTEND=noninteractive +ARG JAVA_IMAGE=eclipse-temurin:11-jdk + +FROM ${JAVA_IMAGE} as builder +ENV DEBIAN_FRONTEND=noninteractive # Build tools RUN apt-get update \ @@ -10,10 +12,11 @@ RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] -RUN source /root/.sdkman/bin/sdkman-init.sh; sdk install gradle 8.6 -RUN source /root/.sdkman/bin/sdkman-init.sh; sdk install maven 3.9.6 +RUN source /root/.sdkman/bin/sdkman-init.sh \ + && sdk install gradle 8.11.1 \ + && sdk install maven 3.9.9 -FROM eclipse-temurin:11-jdk as dependencies +FROM ${JAVA_IMAGE} as dependencies COPY --from=builder /root/.sdkman/candidates/gradle/current /usr/bin/gradle COPY --from=builder /root/.sdkman/candidates/maven/current /usr/bin/maven @@ -25,12 +28,10 @@ ENV PATH="/usr/bin/maven/bin:/usr/bin/maven/:/usr/bin/gradle:/usr/bin/gradle/bin ADD build/distributions/ /root/ #Creating folders structure -RUN mkdir -p /root/chaincode-java/chaincode/src -RUN mkdir -p /root/chaincode-java/chaincode/build/out +RUN mkdir -p /root/chaincode-java/chaincode/src /root/chaincode-java/chaincode/build/out #Making scripts runnable -RUN chmod +x /root/chaincode-java/start -RUN chmod +x /root/chaincode-java/build.sh +RUN chmod +x /root/chaincode-java/start /root/chaincode-java/build.sh # Build protos and shim jar and installing them to maven local and gradle cache WORKDIR /root/chaincode-java/shim-src @@ -41,19 +42,21 @@ RUN gradle \ -x javadoc \ -x test \ -x pmdMain \ - -x pmdTest + -x pmdTest \ + -x spotlessCheck WORKDIR /root/chaincode-java # Run the Gradle and Maven commands to generate the wrapper variants # of each tool #Gradle doesn't run without settings.gradle file, so create one -RUN touch settings.gradle -RUN gradle wrapper -RUN mvn -N io.takari:maven:wrapper +RUN touch settings.gradle \ + && gradle wrapper \ + && ./gradlew --version \ + && mvn -N wrapper:wrapper # Creating final javaenv image which will include all required # dependencies to build and compile java chaincode -FROM eclipse-temurin:11-jdk +FROM ${JAVA_IMAGE} RUN apt-get update \ && apt-get -y install zip unzip \ @@ -66,6 +69,7 @@ SHELL ["/bin/bash", "-c"] # Copy setup scripts, and the cached dependencies COPY --from=dependencies /root/chaincode-java /root/chaincode-java +COPY --from=dependencies /root/.gradle /root/.gradle COPY --from=dependencies /root/.m2 /root/.m2 WORKDIR /root/chaincode-java diff --git a/fabric-chaincode-integration-test/.gitignore b/fabric-chaincode-integration-test/.gitignore index 04cc8e93..32a86ea4 100644 --- a/fabric-chaincode-integration-test/.gitignore +++ b/fabric-chaincode-integration-test/.gitignore @@ -1,3 +1,4 @@ repository _cfg *.tar.gz +log.txt diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 42a075f9..b5ea23f8 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.github.johnrengelman.shadow' version '5.2.0' + id 'com.gradleup.shadow' version '8.3.5' id 'java' } @@ -29,9 +29,9 @@ dependencies { } shadowJar { - baseName = 'chaincode' - version = null - classifier = null + archiveBaseName = 'chaincode' + archiveVersion = '' + archiveClassifier = '' mergeServiceFiles() manifest { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index a4d9619d..a8d488c3 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,10 +1,10 @@ plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.5' id 'java' } group 'org.hyperledger.fabric-chaincode-java' -version '1.0-SNAPSHOT' +version '' java { sourceCompatibility = JavaVersion.VERSION_11 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties index a80b22ce..e2847c82 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 79ef721a..b128a4c8 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.5' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties index a80b22ce..e2847c82 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 5a42b332..eff78a88 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -42,13 +42,13 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { dependencies { implementation platform('com.google.protobuf:protobuf-bom:3.25.5') - implementation platform('io.grpc:grpc-bom:1.68.0') + implementation platform('io.grpc:grpc-bom:1.68.1') implementation platform('io.opentelemetry:opentelemetry-bom:1.42.1') implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.78.1' - implementation 'org.bouncycastle:bcprov-jdk18on:1.78.1' - implementation 'io.github.classgraph:classgraph:4.8.176' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.79' + implementation 'org.bouncycastle:bcprov-jdk18on:1.79' + implementation 'io.github.classgraph:classgraph:4.8.179' implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' implementation 'org.json:json:20240303' implementation 'com.google.protobuf:protobuf-java-util' @@ -86,7 +86,7 @@ sourceSets { } jacoco { - toolVersion = "0.8.6" + toolVersion = "0.8.12" } jacocoTestReport { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index df97d72b..e2847c82 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From cb29b364b66050347babfb8c2acebc5f09b1ef3c Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Sat, 23 Nov 2024 19:12:18 +0000 Subject: [PATCH 019/178] Use Java 21 runtime Using Java 21 as the runtime allows chaincode developers to exploit newer Java features, and provides JVM performance improvements. Java 11 is no longer supported by RedHat and public support from other vendors ends in 2027. This change removes a test for a security manager failure since the security manager is deprecated and its use is disallowed by Java 21. Chaincode must now use Gradle wrappers at version 8.5 or later, since that version of Gradle added support for execution using Java 21. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 4 +- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +-- fabric-chaincode-docker/Dockerfile | 6 +-- .../routing/ContractDefinitionTest.java | 52 ++----------------- 5 files changed, 12 insertions(+), 58 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ed4a411..cec6c666 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Push to registry ${{ matrix.publish_target }} run: | @@ -65,7 +65,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index e87983eb..3bf42b58 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Set up Go uses: actions/setup-go@v5 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ae6e959..942cc24f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -36,7 +36,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Populate chaincode with latest java-version run: | @@ -69,7 +69,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 11 + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 44a5a423..d8ae4229 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,6 +1,6 @@ -ARG JAVA_IMAGE=eclipse-temurin:11-jdk +ARG JAVA_IMAGE=eclipse-temurin:21-jdk -FROM ${JAVA_IMAGE} as builder +FROM ${JAVA_IMAGE} AS builder ENV DEBIAN_FRONTEND=noninteractive # Build tools @@ -16,7 +16,7 @@ RUN source /root/.sdkman/bin/sdkman-init.sh \ && sdk install gradle 8.11.1 \ && sdk install maven 3.9.9 -FROM ${JAVA_IMAGE} as dependencies +FROM ${JAVA_IMAGE} AS dependencies COPY --from=builder /root/.sdkman/candidates/gradle/current /usr/bin/gradle COPY --from=builder /root/.sdkman/candidates/maven/current /usr/bin/maven diff --git a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java index 7ba81940..fe57c1c9 100644 --- a/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java +++ b/fabric-chaincode-shim/src/test/java/org/hyperledger/fabric/contract/routing/ContractDefinitionTest.java @@ -5,69 +5,23 @@ */ package org.hyperledger.fabric.contract.routing; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.startsWith; import contract.SampleContract; import java.lang.reflect.Method; -import java.security.Permission; import org.hyperledger.fabric.contract.Context; import org.hyperledger.fabric.contract.ContractInterface; import org.hyperledger.fabric.contract.ContractRuntimeException; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Info; import org.hyperledger.fabric.contract.routing.impl.ContractDefinitionImpl; import org.junit.jupiter.api.Test; final class ContractDefinitionTest { @Test - void constructor() throws NoSuchMethodException, SecurityException { + void constructor() throws SecurityException { final ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); - assertThat(cf.toString(), startsWith("samplecontract:")); - } - - @Contract(name = "", info = @Info()) - public class FailureTestObject {} - - private boolean fail; - private static final int STEP = 1; - - @Test - void unknownRoute() { - - final SecurityManager tmp = new SecurityManager() { - private int count = 0; - - @Override - public void checkPackageAccess(final String pkg) { - - if (pkg.startsWith("org.hyperledger.fabric.contract")) { - if (count >= STEP) { - throw new SecurityException("Sorry I can't do that"); - } - count++; - } - super.checkPackageAccess(pkg); - } - - @Override - public void checkPermission(final Permission perm) {} - }; - - try { - final ContractDefinition cf = new ContractDefinitionImpl(SampleContract.class); - System.setSecurityManager(tmp); - this.fail = true; - - cf.getUnknownRoute(); - } catch (final Exception e) { - assertThat(e.getMessage(), equalTo("Failure to find unknownTransaction method")); - } finally { - System.setSecurityManager(null); - } + assertThat(cf.toString()).startsWith("samplecontract:"); } @Test From 09839fc266aaa9150027d75967bc196cc22e29aa Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 28 Nov 2024 10:15:42 +0000 Subject: [PATCH 020/178] Ensure tests wait for microfab to start Rather than fixed sleep after lauching microfab, watch the container logs until the "Microfab started" message appears. Signed-off-by: Mark S. Lewis --- .../src/test/resources/scripts/mfsetup.sh | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh b/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh index 6d03c869..8329c270 100755 --- a/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh +++ b/fabric-chaincode-integration-test/src/test/resources/scripts/mfsetup.sh @@ -21,11 +21,9 @@ docker run --name microfab \ -e MICROFAB_CONFIG="${MICROFAB_CONFIG}" \ -e FABRIC_LOGGING_SPEC=info \ ghcr.io/hyperledger-labs/microfab +timeout 60s bash -c 'docker logs -f microfab | grep --max-count=1 "Microfab started"' - -sleep 10 - -curl -sSL http://console.localho.st:8080/ak/api/v1/components > $CFG/cfg.json +curl -sSL http://console.localho.st:8080/ak/api/v1/components > $CFG/cfg.json npx @hyperledger-labs/weft microfab -w $CFG/_wallets -p $CFG/_gateways -m $CFG/_msp -f --config $CFG/cfg.json # bring in the helper bash scripts @@ -33,40 +31,40 @@ npx @hyperledger-labs/weft microfab -w $CFG/_wallets -p $CFG/_gateways -m $CFG/_ function deployCC() { -## package the chaincode -packageChaincode + ## package the chaincode + packageChaincode -## Install chaincode on peer0.org1 and peer0.org2 -infoln "Installing chaincode on peer0.org1..." -installChaincode 1 -infoln "Install chaincode on peer0.org2..." -installChaincode 2 + ## Install chaincode on peer0.org1 and peer0.org2 + infoln "Installing chaincode on peer0.org1..." + installChaincode 1 + infoln "Install chaincode on peer0.org2..." + installChaincode 2 -## query whether the chaincode is installed -queryInstalled 1 + ## query whether the chaincode is installed + queryInstalled 1 -## approve the definition for org1 -approveForMyOrg 1 + ## approve the definition for org1 + approveForMyOrg 1 -## check whether the chaincode definition is ready to be committed -## expect org1 to have approved and org2 not to -checkCommitReadiness 1 "\"org1MSP\": true" "\"org2MSP\": false" -checkCommitReadiness 2 "\"org1MSP\": true" "\"org2MSP\": false" + ## check whether the chaincode definition is ready to be committed + ## expect org1 to have approved and org2 not to + checkCommitReadiness 1 "\"org1MSP\": true" "\"org2MSP\": false" + checkCommitReadiness 2 "\"org1MSP\": true" "\"org2MSP\": false" -## now approve also for org2 -approveForMyOrg 2 + ## now approve also for org2 + approveForMyOrg 2 -## check whether the chaincode definition is ready to be committed -## expect them both to have approved -checkCommitReadiness 1 "\"org1MSP\": true" "\"org2MSP\": true" -checkCommitReadiness 2 "\"org1MSP\": true" "\"org2MSP\": true" + ## check whether the chaincode definition is ready to be committed + ## expect them both to have approved + checkCommitReadiness 1 "\"org1MSP\": true" "\"org2MSP\": true" + checkCommitReadiness 2 "\"org1MSP\": true" "\"org2MSP\": true" -## now that we know for sure both orgs have approved, commit the definition -commitChaincodeDefinition 1 2 + ## now that we know for sure both orgs have approved, commit the definition + commitChaincodeDefinition 1 2 -## query on both orgs to see that the definition committed successfully -queryCommitted 1 -queryCommitted 2 + ## query on both orgs to see that the definition committed successfully + queryCommitted 1 + queryCommitted 2 } #./gradlew -I ./chaincode-init.gradle -PchaincodeRepoDir=$(realpath ./fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/repository) publishShimPublicationToFabricRepository From a65c0435b71d71ca411efcd901b8e83c19c88be0 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 29 Nov 2024 10:48:00 +0000 Subject: [PATCH 021/178] Update versions following v2.5.5 release Signed-off-by: Mark S. Lewis --- build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 654a4d7f..97b79582 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id "com.diffplug.spotless" version "6.25.0" } -version = '2.5.5' +version = '2.5.6' // If the nightly property is set, then this is the scheduled main diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index e5ba5d6c..324b3a7c 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -65,5 +65,5 @@ task copyAllDeps(type: Copy) { task buildImage(type: DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.5', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.6', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index b5ea23f8..5a82082e 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 9740748d..fccbc9e0 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.5 + 2.5.6 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index a8d488c3..56c0f251 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index b128a4c8..06b4af17 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' implementation 'commons-logging:commons-logging:1.2' implementation 'com.google.code.gson:gson:2.10.1' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index f9e59238..894443ea 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.5 + 2.5.6 From b640ba38f2e7d571bc6eb96370db266d3e47446b Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Wed, 4 Dec 2024 19:19:04 +0000 Subject: [PATCH 022/178] Push identical image to all Docker registries (#368) The current GitHub Actions workflow builds and pushes separate Docker images for each registry. This results in the images published to each registry having a different hash, despite having the same version tag. This change modifies the Docker publishing job in the release workflow so that a single step builds and publishes the same Docker image to all Docker registries. For reproducability, the timestamp of the image is also set to the last commit timestamp. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cec6c666..1a0c8693 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,14 +47,8 @@ jobs: TARGET: ${{ matrix.publish_target }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Publish to docker registries docker.io and ghcr.io + # Publish to Docker registries: docker.io and ghcr.io publishdocker: - strategy: - fail-fast: false - matrix: - DOCKER_REGISTRY: - - 'docker.io' - - 'ghcr.io' runs-on: ubuntu-latest needs: test permissions: @@ -78,24 +72,36 @@ jobs: buildkitd-config-inline: | [worker.oci] max-parallelism = 1 - - name: Login to the ${{ matrix.DOCKER_REGISTRY }} Container Registry + - name: Login to Docker Hub + # If testing on a fork, login error may occur and can be ignored + continue-on-error: true uses: docker/login-action@v3 with: - registry: ${{ matrix.DOCKER_REGISTRY }} - username: ${{ matrix.DOCKER_REGISTRY == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} - password: ${{ matrix.DOCKER_REGISTRY == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@v5 with: - images: ${{ matrix.DOCKER_REGISTRY }}/${{ github.repository_owner }}/fabric-javaenv + # If testing on a fork, Docker Hub publish might fail so place it last + images: | + ghcr.io/${{ github.repository_owner }}/fabric-javaenv + docker.io/${{ github.repository_owner }}/fabric-javaenv tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} + - name: Get Git commit timestamps + run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV - name: Build and push image id: push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: platforms: linux/amd64,linux/arm64 file: fabric-chaincode-docker/Dockerfile @@ -103,3 +109,5 @@ jobs: tags: ${{ steps.meta.outputs.tags }} push: ${{ github.event_name != 'pull_request' }} labels: ${{ steps.meta.outputs.labels }} + env: + SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }} From 6db0d3bd4090a580fe4fbfa4525001679c0afd44 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Wed, 11 Dec 2024 17:13:44 +0000 Subject: [PATCH 023/178] Update compatibility information (#369) Also fix some out-of-date links in the contributing documentation. Signed-off-by: Mark S. Lewis --- COMPATIBILITY.md | 74 +++++++++++++++--------------------------------- CONTRIBUTING.md | 16 +++++------ 2 files changed, 31 insertions(+), 59 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 6c1708b6..57924e50 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -1,68 +1,40 @@ -# Support and Compatibility for fabric-chaincode-java - -Github is used for code base management, issues should reported in the [FABCJ](https://jira.hyperledger.org/projects/FABCJ/issues/) component in JIRA. +# Support and Compatibility +Github is used for code base management and issue tracking. ## Summary of Compatibility -This table shows the summary of the compatibility of the Java libraries, together with the JVM version they require and the Fabric Peer versions they can communicate with. - -| | Fabric Peer v1.4 connectivity | Java 8 VM | Fabric Peer v2.2/2.5 Connectivity | Java 11 VM | -| ----------------------- | ----------------------------- | --------- | ----------------------------- | ---------- | -| Java libraries **v1.4** | Yes | Yes | Yes | Yes | -| Java libraries **v2.1** | Yes | No | Yes | Yes | -| Java libraries **v2.4** | Yes | No | Yes | Yes | -| Java libraries **v2.5** | Yes | No | Yes | Yes | - - -Testing is performed with - - Java v8: OpenJDK - - Java v11: Eclipse Temurin (this has changed from OpenJDK) - - -By default a Fabric Peer v1.4 will create a Java 8 VM, and a Fabric Peer v2.x will create a Java 11 VM. Whilst is the default, the docker image used to host the chaincode and contracts can be altered. Set the environment variable `CORE_CHAINCODE_JAVA_RUNTIME` on the peer to the name of the docker image. For example `CORE_CHAINCODE_JAVA_RUNTIME=example/customJavaRuntime:latest` - -The Java Libraries will connect to the peer whilst running; this is referred to as 'Fabric Peer Connectivity' in the table. For example, whilst the Fabric Peer v1.4 will create a Java 8 environment, if a Java 11 environment was configured, the Java Libraries at v2.5 still function when connecting to the Fabric Peer v1.4. - -## Compatibility - -The key elements are: - -- the version of the Fabric Contract Java libraries used -- the version of the JVM used to run the code -- When starting a chaincode container to run a Smart Contract the version of the runtime that is used is determined by these factors: - -Fabric v1.4.2, and Fabric v2.5.x will, by default, start up docker image to host the chaincode and contracts. The version of the docker image used is defined by the version of Fabric in use. - -With Fabric v2.1.0 and later, the chaincode container can be configured to be started by different chaincode builders, and not the Peer. In this case, the environment used is not in the control of Fabric. +This table shows the summary of the compatibility of the Java chaincode libraries, together with the JVM version they require. -The Java libraries are produced are `group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim'` +| Java chaincode version | Minimum supported Java | Java runtime | Docker image platforms | +|------------------------|------------------------|--------------|------------------------| +| v1.4 | 8 | 8 | amd64 | +| v2.2 | 11 | 11 | amd64 | +| v2.5.0 - v2.5.4 | 11 | 11 | amd64, arm64 | +| v2.5.5+ | 11 | 21 | amd64, arm64 | -### Supported JVMs +The Java runtime provided by the chaincode Docker image determines the maximum Java version (and features) that smart contract code can exploit when using the default Java chaincode container. -v1.4.x and v2.5.x Java Libraries are supported running in Java 11 with the x86_64 architecture. Later Java 11 versions are supported but are not tested. +Subject to a suitable runtime environment, the Java chaincode libraries can be used to communicate with Fabric peers at different LTS versions. The level of functionality is determined by the Fabric version in use and channel capabilities. -v1.4.x Java Libraries are supported running in Java 8 with the x86_64 architecture. Later Java 8 versions are supported but are not tested. +All Docker images, chaincode libraries and tools are tested using amd64 (x86-64) only. -Architecture Support: all docker images, JVMs, tools are tested under x86_64 ONLY +## Chaincode builder +The default Fabric chaincode builder creates a Docker container to run deployed smart contracts. Java chaincode Docker containers are built using the `hyperledger/fabric-javaenv` Docker image, tagged with the same major and minor version as the Fabric peer version. For example, Fabric v2.5 creates Java chaincode containers using the `hyperledger/fabric-javaenv:2.5` Docker image. Fabric v3 continues to use the v2.5 Java chaincode image. -### Default Peer Runtime selection +A different chaincode Docker image can be specified using the `CORE_CHAINCODE_JAVA_RUNTIME` environment variable on the Fabric peer. For example, `CORE_CHAINCODE_JAVA_RUNTIME=example/customJavaRuntime:latest`. -When using Fabric v2.5, the default docker image that is used to run the Java chaincode is *eclipse-temurin:11.0.21_9-jdk* +With Fabric v2 and later, an alternative chaincode builder can be configured on the Fabric peer. In this case the configured chaincode builder controls how chaincode is launched. See the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/release-2.5/cc_launcher.html) for further details. -With the default docker image used by Fabric v2.5, if the packaged Java code contains a build script or a wrapper for either Maven or Gradle, it will be built using Gradle 7.0 wrapper, or Maven 3.8.1 wrapper. +## Chaincode packaging - - If both Gradle and Maven files are present Gradle is used. - - Gradle build files can be groovy, or kotlin. - - If the Gradle or Maven wrappers are present, this will used in preference to the installed wrappers. - -Remember that when using the wrappers, code will be downloaded from the internet. Keep this in mind for any installation with limited or no internet access. - -Alternatively it is recommended to package prebuilt jar files, including the contract and all dependencies, in which case no build or Internet access is required when installing Java chaincode. +When using the `hyperledger/fabric-javaenv` Java chaincode Docker images, deployed chaincode is built as follows: -Please check the [Dockerfile](./fabric-chaincode-docker/Dockerfile) that is used for the environment to see exactly how these versions are installed. +- If both Gradle and Maven files are present, Gradle is used. +- Gradle build files can be either Groovy or Kotlin. +- If Gradle or Maven wrappers are present, they will be used instead of the preinstalled Gradle or Maven versions. -### Supported Runtime communication with the Peer +Remember that when using the wrappers, code will be downloaded from the Internet. Keep this in mind for any installation with limited network access. -Subject to a suitable runtime environment, the 1.4 and 2.5 Java Libraries can used to communicate with Fabric Peers at 2.5 and previous LTS versions. The level of functionality that is implied by the Fabric version in use and channel capabilities. +Alternatively, it is recommended to package prebuilt JAR files, including the smart contract and all dependencies. In this case, no Internet access is required when deploying Java chaincode. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d872b5bc..20f0f0d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,29 +2,29 @@ We welcome contributions to the [Hyperledger Fabric](https://hyperledger-fabric.readthedocs.io) Project. There's always plenty to do! -If you have any questions about the project or how to contribute, you can find us in the [fabric-contracts-api](https://discordapp.com/channels/905194001349627914/943090527920877598) channel on Discord. +If you have any questions about the project or how to contribute, you can find us in the [fabric-contracts-api](https://discordapp.com/channels/905194001349627914/943090527920877598) channel on [Discord](https://discord.lfdecentralizedtrust.org/). Here are a few guidelines to help you contribute successfully... ## Issues -All issues are tracked in the issues tab in github. If you find a bug which we don't already know about, you can help us by creating a new issue describing the problem. Please include as much detail as possible to help us track down the cause.If you want to begin contributing code, looking through our open issues is a good way to start. Try looking for recent issues with detailed descriptions first, or ask us on Discord if you're unsure which issue to choose. +All issues are tracked in the issues tab in GitHub. If you find a bug which we don't already know about, you can help us by creating a new issue describing the problem. Please include as much detail as possible to help us track down the cause.If you want to begin contributing code, looking through our open issues is a good way to start. Try looking for recent issues with detailed descriptions first, or ask us on Discord if you're unsure which issue to choose. ## Enhancements -Make sure you have the support of the Hyperledger Fabric community before investing a lot of effort in project enhancements. Please look up the Fabric RFC process for large changes. +Make sure you have the support of the Hyperledger Fabric community before investing a lot of effort in project enhancements. Please look up the [Fabric RFC](https://github.com/hyperledger/fabric-rfcs) process for large changes. ## Pull Requests -We use our own forks and [Github Flow](https://guides.github.com/introduction/flow/index.html) to deliver changes to the code. Follow these steps to deliver your first pull request: +We use our own forks and [Github Flow](https://docs.github.com/en/get-started/using-github/github-flow) to deliver changes to the code. Follow these steps to deliver your first pull request: -1. [Fork the repository](https://guides.github.com/activities/forking/#fork) and create a new branch from `main`. +1. [Fork the repository](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) and create a new branch from `main`. 2. If you've added code that should be tested, add tests! 3. If you've added any new features or made breaking changes, update the documentation. 4. Ensure all the tests pass. -5. Include the JIRA issue number, a descriptive message, and the [Developer Certificate of Origin (DCO) sign-off](https://github.com/probot/dco#how-it-works) on all commit messages. -6. [Issue a pull request](https://guides.github.com/activities/forking/#making-a-pull-request)! -7. [Azure DevOps](https://dev.azure.com/Hyperledger/Fabric-Chaincode-Java) builds must succeed before the pull request can be reviewed and merged. +5. Include the JIRA issue number, a descriptive message, and the [Developer Certificate of Origin (DCO) sign-off](https://github.com/dcoapp/app#how-it-works) on all commit messages. +6. [Issue a pull request](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project#making-a-pull-request)! +7. [GitHub Actions](https://github.com/hyperledger/fabric-chaincode-java/actions) builds must succeed before the pull request can be reviewed and merged. ## Coding Style From 951e684fbc93e3919f6e0090d7c790eafba82e56 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Wed, 11 Dec 2024 18:44:20 +0000 Subject: [PATCH 024/178] Add an overview for the javaenv Docker image (#370) Signed-off-by: Mark S. Lewis --- fabric-chaincode-docker/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 fabric-chaincode-docker/README.md diff --git a/fabric-chaincode-docker/README.md b/fabric-chaincode-docker/README.md new file mode 100644 index 00000000..028052a0 --- /dev/null +++ b/fabric-chaincode-docker/README.md @@ -0,0 +1,16 @@ +# Quick reference + +- **Maintained by**: + [The Fabric Java chaincode maintainers](https://github.com/hyperledger/fabric-chaincode-java) + +# Overview + +This image is used by the default [Hyperledger Fabric](https://hyperledger-fabric.readthedocs.io/) chaincode builder when deploying Java smart contracts. It is not intended for use independently of Hyperledger Fabric. + +# Image variants + +Image tags correspond broadly to the major and minor version of Hyperledger Fabric for which they are primarily intended. More detailed information on image tags, interoperability, and supported Java versions can be found in the [compatibility](https://github.com/hyperledger/fabric-chaincode-java/blob/main/COMPATIBILITY.md) documentation. + +# License + +This image is provided under the [Apache-2.0](https://github.com/hyperledger/fabric-chaincode-java/blob/main/LICENSE) license. From 106cbd12c2148cc178ff9cdeb386b9462477bf56 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 13 Dec 2024 13:10:46 +0000 Subject: [PATCH 025/178] Update Docker image overview (#371) Simplify to text to avoid confusion on the relationship between image tags and Fabric versions. Signed-off-by: Mark S. Lewis --- fabric-chaincode-docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-docker/README.md b/fabric-chaincode-docker/README.md index 028052a0..4c87631d 100644 --- a/fabric-chaincode-docker/README.md +++ b/fabric-chaincode-docker/README.md @@ -9,7 +9,7 @@ This image is used by the default [Hyperledger Fabric](https://hyperledger-fabri # Image variants -Image tags correspond broadly to the major and minor version of Hyperledger Fabric for which they are primarily intended. More detailed information on image tags, interoperability, and supported Java versions can be found in the [compatibility](https://github.com/hyperledger/fabric-chaincode-java/blob/main/COMPATIBILITY.md) documentation. +Detailed information on image tags, interoperability, and supported Java versions can be found in the [compatibility](https://github.com/hyperledger/fabric-chaincode-java/blob/main/COMPATIBILITY.md) documentation. # License From bb141b3fd46eeaf029f114aba21eb04f48a4fb37 Mon Sep 17 00:00:00 2001 From: Dave Enyeart Date: Wed, 15 Jan 2025 16:24:30 -0500 Subject: [PATCH 026/178] Bump logback to 1.5.15 (#373) Signed-off-by: David Enyeart --- examples/fabric-contract-example-maven/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index b022d5aa..df343844 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -7,15 +7,15 @@ - 1.8 + 21 UTF-8 UTF-8 - 2.5.4 + 2.5.5 - 1.3.14 + 1.5.15 1.7.5 From 8fb3168255f307dcf0580338ccb546fd9d5feb65 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Sat, 22 Mar 2025 12:54:19 +0000 Subject: [PATCH 027/178] Use native runners to build Docker images (#374) Instead of relying on QEMU emulation to build multi-arch images, use native arm64 and amd64 build runners to build architecture-specific images, then publish multi-arch metadata with each of the image manifests. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 129 ++++++++++++++++++++++------------ .github/workflows/test.yml | 27 +++---- RELEASING.md | 9 ++- 3 files changed, 105 insertions(+), 60 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a0c8693..3ed40537 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,14 +7,14 @@ name: Release on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-*' + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+-*" workflow_dispatch: -jobs: - test: - uses: ./.github/workflows/test.yml +env: + IMAGE_NAME: ${{ github.repository_owner }}/fabric-javaenv +jobs: # Publishing steps to both the Github Packages and the Sonatype publishjars: strategy: @@ -24,7 +24,6 @@ jobs: - publishAllPublicationsToGithubPackagesRepository - publishAllPublicationsToReleaseRepository runs-on: ubuntu-latest - needs: test permissions: contents: read packages: write @@ -32,7 +31,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: "temurin" java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Push to registry ${{ matrix.publish_target }} @@ -47,67 +46,107 @@ jobs: TARGET: ${{ matrix.publish_target }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Publish to Docker registries: docker.io and ghcr.io - publishdocker: - runs-on: ubuntu-latest - needs: test + docker-build-push: + name: Push Docker image + runs-on: ${{ matrix.arch.runner }} permissions: contents: read packages: write + strategy: + fail-fast: false + matrix: + arch: + - platform: linux-amd64 + runner: ubuntu-24.04 + - platform: linux-arm64 + runner: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: - distribution: 'temurin' + distribution: "temurin" java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + - name: Get commit timestamp + run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 with: - buildkitd-flags: --debug - buildkitd-config-inline: | - [worker.oci] - max-parallelism = 1 + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - # If testing on a fork, login error may occur and can be ignored - continue-on-error: true uses: docker/login-action@v3 with: + registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Login to GitHub Container Registry + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build image + id: build + uses: docker/build-push-action@v6 + with: + file: fabric-chaincode-docker/Dockerfile + context: fabric-chaincode-docker + outputs: type=registry,"name=${{ format('ghcr.io/{0},docker.io/{0}', env.IMAGE_NAME) }}",push-by-digest=true,name-canonical=true + env: + SOURCE_DATE_EPOCH: ${{ env.SOURCE_DATE_EPOCH }} + - name: Export digest + run: | + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digest-${{ matrix.arch.platform }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + + docker-meta: + needs: docker-build-push + name: Publish Docker metadata + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + registry: + - docker.io + - ghcr.io + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: ${{ runner.temp }}/digests + pattern: digest-* + merge-multiple: true + - name: Login to ${{ matrix.registry }} uses: docker/login-action@v3 with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Docker meta + registry: ${{ matrix.registry }} + username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} + password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} + - name: Docker metadata id: meta uses: docker/metadata-action@v5 with: - # If testing on a fork, Docker Hub publish might fail so place it last - images: | - ghcr.io/${{ github.repository_owner }}/fabric-javaenv - docker.io/${{ github.repository_owner }}/fabric-javaenv + images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} - - name: Get Git commit timestamps - run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV - - name: Build and push image - id: push - uses: docker/build-push-action@v6 - with: - platforms: linux/amd64,linux/arm64 - file: fabric-chaincode-docker/Dockerfile - context: fabric-chaincode-docker - tags: ${{ steps.meta.outputs.tags }} - push: ${{ github.event_name != 'pull_request' }} - labels: ${{ steps.meta.outputs.labels }} - env: - SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }} + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Create and push manifest list + working-directory: ${{ runner.temp }}/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("--tag " + .) | join(" ")' <<< "${DOCKER_METADATA_OUTPUT_JSON}") \ + $(printf '${{ matrix.registry }}/${{ env.IMAGE_NAME }}@sha256:%s ' *) + - name: Inspect image + run: docker buildx imagetools inspect '${{ matrix.registry }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 942cc24f..9d45c2a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ on: workflow_call: inputs: ref: - default: '' + default: "" required: false type: string @@ -16,16 +16,16 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 21 - - uses: gradle/actions/setup-gradle@v4 - - name: Build and Unit test - run: ./gradlew :fabric-chaincode-shim:build + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Build and Unit test + run: ./gradlew :fabric-chaincode-shim:build intergationtest: runs-on: ubuntu-latest @@ -37,6 +37,9 @@ jobs: with: distribution: temurin java-version: 21 + - uses: actions/setup-node@v4 + with: + node-version: "lts/*" - uses: gradle/actions/setup-gradle@v4 - name: Populate chaincode with latest java-version run: | @@ -49,7 +52,7 @@ jobs: run: | curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh | bash -s -- binary npm install -g @hyperledger-labs/weft - + # set the path and cfg env var for the rest of the step echo "FABRIC_CFG_PATH=$GITHUB_WORKSPACE/config" >> $GITHUB_ENV echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH diff --git a/RELEASING.md b/RELEASING.md index 16288ffc..7550061e 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,9 +3,9 @@ The following artifacts are created as a result of releasing Fabric Chaincode Java: - docker images - - [fabric-javaenv](https://hub.docker.com/r/hyperledger/fabric-javaenv) + - [fabric-javaenv](https://hub.docker.com/r/hyperledger/fabric-javaenv) - Java libraries - - [fabric-chaincode-shim](https://search.maven.org/search?q=a:fabric-chaincode-shim) + - [fabric-chaincode-shim](https://search.maven.org/search?q=a:fabric-chaincode-shim) **Note:** A docker image with a matching V.R version is required before releasing a new version of Fabric. @@ -17,10 +17,12 @@ The following tasks are required before releasing: - Update version numbers in `build.gradle` files to the required version - Update test, sample, and docs files to match the new version -- Update the [`COMPATIBILITY.md`](./COMPATIBILITY.md) +- Update the [`COMPATIBILITY.md`](./COMPATIBILITY.md) See the [[FABCJ-289] release: 2.2.0 LTS](https://github.com/hyperledger/fabric-chaincode-java/pull/124) pull request for an example, although be careful to search for all versions in the codebase as they're easy to miss and things change! +Ensure the last branch build passed since exactly this repository state will be released. + ## Create release Creating a GitHub release on the [releases page](https://github.com/hyperledger/fabric-chaincode-java/releases) will trigger the build to publish the new release. @@ -57,6 +59,7 @@ See the [Bump version to 2.2.1](https://github.com/hyperledger/fabric-chaincode- ## Interim Build Publishing The nightly Azure Pipeline Builds will also publish the 'dev' drivers to Artifactory. These can be accessed via the repository at + ``` maven { url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" From 48f96069ce69bfd5cefdf6e6e195594196b357a8 Mon Sep 17 00:00:00 2001 From: Muthu Date: Wed, 2 Apr 2025 00:37:20 +0530 Subject: [PATCH 028/178] Update to PMD 7.12.0 for static analysis (#375) Addresses CVE-2025-23215. Signed-off-by: Muthu Co-authored-by: Mark S. Lewis --- fabric-chaincode-shim/build.gradle | 2 +- .../fabric/contract/execution/ExecutionService.java | 1 + .../contract/execution/impl/ContractInvocationRequest.java | 2 +- .../fabric/contract/routing/impl/SerializerRegistryImpl.java | 4 ++-- .../main/java/org/hyperledger/fabric/ledger/Collection.java | 1 + .../fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java | 2 +- .../hyperledger/fabric/shim/impl/InvocationTaskManager.java | 3 --- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index eff78a88..e5602c7c 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -12,7 +12,7 @@ plugins { } pmd { - toolVersion = '7.7.0' + toolVersion = '7.12.0' ruleSetFiles = files('../pmd-ruleset.xml') ruleSets = [] // explicitly set to empty to avoid using the default configuration ignoreFailures = false diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java index 8c859680..629f21bb 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/ExecutionService.java @@ -15,6 +15,7 @@ * *

    Service that executes {@link InvocationRequest} (wrapped Init/Invoke + extra data) using routing information */ +@FunctionalInterface public interface ExecutionService { /** diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java index 7a3e0ff3..82a0f996 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/impl/ContractInvocationRequest.java @@ -15,7 +15,7 @@ import org.hyperledger.fabric.shim.ChaincodeStub; public final class ContractInvocationRequest implements InvocationRequest { - @SuppressWarnings("PMD.ProperLogger") // PMD 7.7.0 gives a false positive here + @SuppressWarnings("PMD.ProperLogger") // PMD 7.12.0 gives a false positive here private static final Log LOGGER = LogFactory.getLog(ContractInvocationRequest.class); private static final Pattern NS_REGEX = Pattern.compile(":"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java index 728966f0..99a41e03 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java @@ -24,7 +24,7 @@ public class SerializerRegistryImpl { private static final Logger LOGGER = Logger.getLogger(SerializerRegistryImpl.class); - private final Class annotationClass = Serializer.class; + private static final Class ANNOTATION_CLASS = Serializer.class; // Could index these by name and or type. private final Map contents = new HashMap<>(); @@ -68,7 +68,7 @@ public void findAndSetContents() throws InstantiationException, IllegalAccessExc try (ScanResult scanResult = classGraph.scan()) { for (final ClassInfo classInfo : - scanResult.getClassesWithAnnotation(this.annotationClass.getCanonicalName())) { + scanResult.getClassesWithAnnotation(this.ANNOTATION_CLASS.getCanonicalName())) { LOGGER.debug(() -> "Found class with contract annotation: " + classInfo.getName()); final Class cls = (Class) classInfo.loadClass(); LOGGER.debug("Loaded class"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java index 1f109da8..42a26107 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/Collection.java @@ -6,6 +6,7 @@ package org.hyperledger.fabric.ledger; /** Place holder. */ +@SuppressWarnings("PMD.ImplicitFunctionalInterface") public interface Collection { /** Constant that can be used to refer to the 'Worldstate' collection explicitly. */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java index 1226a3cb..56cae1a0 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java @@ -23,7 +23,7 @@ /** Implements {@link StateBasedEndorsement}. */ public final class StateBasedEndorsementImpl implements StateBasedEndorsement { - @SuppressWarnings("PMD.ProperLogger") // PMD 7.7.0 reports a false positive + @SuppressWarnings("PMD.ProperLogger") // PMD 7.12.0 reports a false positive private static final Log LOGGER = LogFactory.getLog(StateBasedEndorsementImpl.class); private final Map orgs = new HashMap<>(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java index aecc8e64..bbed26d7 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/InvocationTaskManager.java @@ -183,9 +183,6 @@ private void processChaincodeMessage(final ChaincodeMessage chaincodeMessage) { case READY: handleMsg(chaincodeMessage, msgType); break; - default: - LOGGER.warning(() -> String.format(CANNOT_HANDLE_FORMAT, chaincodeMessage.getTxid(), msgType)); - break; } } From 13918c9be1dfcbb2118879f0a77cb8c28a4ea512 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 3 Apr 2025 18:51:40 +0100 Subject: [PATCH 029/178] Use OSV-Scanner v2 (#376) Update the vulnerability scan of dependencies to use OSV-Scanner v2. Also rework the Makefile targets so that a precompiled OSV-Scanner binary is downloaded and avoid the need for Go to be installed. Signed-off-by: Mark S. Lewis --- .github/workflows/scan.yml | 5 ----- Makefile | 31 +++++++++++++++++++++++++----- fabric-chaincode-shim/build.gradle | 10 ---------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 3bf42b58..8b648f14 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -24,10 +24,5 @@ jobs: distribution: temurin java-version: 21 - uses: gradle/actions/setup-gradle@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: stable - cache: false - name: Scan run: make scan diff --git a/Makefile b/Makefile index f8f60fbf..44118a94 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,29 @@ # SPDX-License-Identifier: Apache-2.0 # -.PHONEY: scan -scan: - go install github.com/google/osv-scanner/cmd/osv-scanner@latest - ./gradlew --quiet resolveAndLockAll --write-locks - osv-scanner scan --lockfile=fabric-chaincode-shim/gradle.lockfile +bin_dir := bin +osv-scanner := $(bin_dir)/osv-scanner + +kernel_name := $(shell uname -s | tr '[:upper:]' '[:lower:]') +machine_hardware := $(shell uname -m) +ifeq ($(machine_hardware), x86_64) + machine_hardware := amd64 +endif +ifeq ($(machine_hardware), aarch64) + machine_hardware := arm64 +endif + +.PHONY: scan +scan: $(osv-scanner) + ./gradlew --quiet :fabric-chaincode-shim:dependencies --write-locks --configuration runtimeClasspath + bin/osv-scanner scan --lockfile=fabric-chaincode-shim/gradle.lockfile + +.PHONY: install-osv-scanner +install-osv-scanner: + mkdir -p '$(bin_dir)' + curl --fail --location --show-error --silent --output '$(osv-scanner)' \ + 'https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_$(kernel_name)_$(machine_hardware)' + chmod u+x '$(osv-scanner)' + +$(osv-scanner): + $(MAKE) install-osv-scanner diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index e5602c7c..326225ea 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -26,16 +26,6 @@ configurations { } } -tasks.register('resolveAndLockAll') { - notCompatibleWithConfigurationCache("Filters configurations at execution time") - doFirst { - assert gradle.startParameter.writeDependencyLocks : "$path must be run from the command line with the `--write-locks` flag" - } - doLast { - configurations.findAll { it.canBeResolved }.each { it.resolve() } - } -} - tasks.withType(org.gradle.api.tasks.testing.Test) { systemProperty 'CORE_CHAINCODE_LOGGING_LEVEL', 'DEBUG' } From 826f0779d1d8dc0a41b042f3346563bc8094c050 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 4 Apr 2025 15:15:52 +0100 Subject: [PATCH 030/178] Setup Go for vulnerability scan (#377) Go is still needed to run the vulnerability scan successfully on v2.5.5 and earlier. Signed-off-by: Mark S. Lewis --- .github/workflows/scan.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 8b648f14..b0754fd5 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -19,6 +19,10 @@ jobs: - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} + - uses: actions/setup-go@v5 # Needed for scanning of v2.5.5 and earlier + with: + go-version: stable + cache: false - uses: actions/setup-java@v4 with: distribution: temurin From fd50d8a8cbfac8c2b45002ffe330dbbba5db6fd2 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 9 Jun 2025 21:24:18 +0100 Subject: [PATCH 031/178] Update dependencies (#379) - Update Gradle and Maven build tools in Docker image to latest versions. - Update project dependencies, including fabric-protos, which now requires protobuf-java v4 instead of v3. - Gradle build file modifications to avoid deprecated features. Signed-off-by: Mark S. Lewis --- build.gradle | 20 +++++----- .../Dockerfile | 8 ++-- .../build.gradle | 37 ++++++++----------- .../build.gradle.kts | 9 ++--- .../build.gradle | 36 +++++++----------- .../fabric-contract-example-maven/pom.xml | 12 ++---- examples/ledger-api/build.gradle | 32 ++++++---------- fabric-chaincode-docker/Dockerfile | 4 +- fabric-chaincode-docker/build.gradle | 36 ++++++++---------- .../build.gradle | 14 +++---- .../src/contracts/bare-gradle/build.gradle | 5 +-- .../contracts/fabric-ledger-api/build.gradle | 5 +-- .../contracts/fabric-shim-api/build.gradle | 9 ++--- fabric-chaincode-shim/build.gradle | 35 +++++++++--------- .../fabric/contract/metadata/TypeSchema.java | 2 +- .../shim/ChaincodeServerProperties.java | 2 +- .../impl/OpenTelemetryTracesProvider.java | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 18 files changed, 115 insertions(+), 157 deletions(-) diff --git a/build.gradle b/build.gradle index 97b79582..d0be9fd6 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ */ plugins { - id "com.github.ben-manes.versions" version "0.51.0" - id "com.diffplug.spotless" version "6.25.0" + id "com.github.ben-manes.versions" version "0.52.0" + id "com.diffplug.spotless" version "7.0.4" } version = '2.5.6' @@ -28,15 +28,13 @@ allprojects { repositories { mavenCentral() - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url "https://www.jitpack.io" } } spotless { format 'misc', { target '*.gradle', '.gitattributes', '.gitignore' trimTrailingWhitespace() - indentWithSpaces() + leadingTabsToSpaces() endWithNewline() } } @@ -62,14 +60,14 @@ subprojects { dependencies { implementation 'commons-cli:commons-cli:1.9.0' - implementation 'commons-logging:commons-logging:1.3.4' + implementation 'commons-logging:commons-logging:1.3.5' - testImplementation platform('org.junit:junit-bom:5.11.3') + testImplementation platform('org.junit:junit-bom:5.13.1') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.assertj:assertj-core:3.26.3' - testImplementation 'org.mockito:mockito-core:5.14.2' - testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.7' + testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' testImplementation 'org.hamcrest:hamcrest-library:3.0' } @@ -81,7 +79,7 @@ subprojects { spotless { java { removeUnusedImports() - palantirJavaFormat('2.50.0').formatJavadoc(true) + palantirJavaFormat('2.67.0').formatJavadoc(true) formatAnnotations() } } diff --git a/examples/fabric-contract-example-as-service/Dockerfile b/examples/fabric-contract-example-as-service/Dockerfile index 2afd44b6..8e21e344 100644 --- a/examples/fabric-contract-example-as-service/Dockerfile +++ b/examples/fabric-contract-example-as-service/Dockerfile @@ -4,7 +4,7 @@ # Example multi-stage dockerfile for Java Chaincode # the first stage -FROM gradle:jdk11 AS GRADLE_BUILD +FROM gradle:8-jdk21 AS gradle_build # copy the build.gradle and src code to the container COPY src/ src/ @@ -15,11 +15,11 @@ RUN gradle build shadowJar # the second stage of our build just needs the compiled files -FROM openjdk:11-jre-slim +FROM eclipse-temurin:21-jre # copy only the artifacts we need from the first stage and discard the rest -COPY --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar +COPY --from=gradle_build /home/gradle/build/libs/chaincode.jar /chaincode.jar -ENV PORT 9999 +ENV PORT=9999 EXPOSE 9999 # set the startup command to execute the jar diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index b787d94b..a8d36524 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,31 +1,24 @@ plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } -version '0.0.1' - -tasks.compileJava { - options.release.set(11) -} +version = '0.0.1' repositories { mavenCentral() maven { - url "https://www.jitpack.io" + url = "https://www.jitpack.io" } - maven { - url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" - } - } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20240303' - testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' - testImplementation 'org.assertj:assertj-core:3.26.3' - testImplementation 'org.mockito:mockito-core:5.13.0' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + implementation 'org.json:json:20250517' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.mockito:mockito-core:5.18.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } shadowJar { @@ -39,14 +32,14 @@ shadowJar { } } +compileJava { + options.release.set(11) + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" +} + test { useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "PASSED", "SKIPPED", "FAILED" } } - - -tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" -} diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 5cf57def..92917bed 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -14,11 +14,11 @@ plugins { version = "0.0.1" dependencies { - implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2") - implementation("org.json:json:20240303") + implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5") + implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.junit.jupiter:junit-jupiter:5.11.0") + testImplementation("org.junit.jupiter:junit-jupiter:5.13.1") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0") } @@ -27,9 +27,6 @@ repositories { maven { setUrl("https://jitpack.io") } - maven { - setUrl("https://hyperledger.jfrog.io/hyperledger/fabric-maven") - } } tasks { diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index ceb2a9a2..a4b82222 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,31 +1,23 @@ plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } -version '0.0.1' - -tasks.compileJava { - options.release.set(11) -} +version = '0.0.1' repositories { mavenCentral() maven { - url "https://www.jitpack.io" + url = "https://www.jitpack.io" } - maven { - url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" - } - } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20240303' - testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' - testImplementation 'org.assertj:assertj-core:3.26.3' - testImplementation 'org.mockito:mockito-core:5.13.0' + compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + compile 'org.json:json:20250517' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.mockito:mockito-core:5.18.0' } shadowJar { @@ -39,14 +31,14 @@ shadowJar { } } +compileJava { + options.release.set(11) + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" +} + test { useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "PASSED", "SKIPPED", "FAILED" } } - - -tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" -} diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index df343844..41d2202f 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -19,8 +19,8 @@ 1.7.5 - 5.3.0-RC1 - 1.3.0-RC1 + 5.13.1 + 1.13.1 @@ -29,10 +29,6 @@ jitpack.io https://www.jitpack.io - - artifactory - https://hyperledger.jfrog.io/hyperledger/fabric-maven - @@ -48,7 +44,7 @@ org.hyperledger.fabric fabric-protos - 0.3.3 + 0.3.7 compile @@ -92,7 +88,7 @@ org.mockito mockito-core - 2.10.0 + 5.18.0 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index ceb2a9a2..8f94a9b2 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,31 +1,23 @@ plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } version '0.0.1' -tasks.compileJava { - options.release.set(11) -} - repositories { mavenCentral() maven { url "https://www.jitpack.io" } - maven { - url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" - } - } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.2' - compile 'org.json:json:20240303' - testImplementation 'org.junit.jupiter:junit-jupiter:5.11.0' - testImplementation 'org.assertj:assertj-core:3.26.3' - testImplementation 'org.mockito:mockito-core:5.13.0' + compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + compile 'org.json:json:20250517' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.mockito:mockito-core:5.18.0' } shadowJar { @@ -39,14 +31,14 @@ shadowJar { } } +compileJava { + options.release.set(11) + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" +} + test { useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "PASSED", "SKIPPED", "FAILED" } } - - -tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-parameters" -} diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index d8ae4229..eeaf4303 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -13,8 +13,8 @@ RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] RUN source /root/.sdkman/bin/sdkman-init.sh \ - && sdk install gradle 8.11.1 \ - && sdk install maven 3.9.9 + && sdk install gradle 8.14.2 \ + && sdk install maven 3.9.10 FROM ${JAVA_IMAGE} AS dependencies diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 324b3a7c..b5dbbeb5 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -4,47 +4,41 @@ * SPDX-License-Identifier: Apache-2.0 */ -buildscript { - repositories { - maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - maven { url "https://www.jitpack.io" } - mavenCentral() - gradlePluginPortal() - } - dependencies { - classpath 'com.bmuschko:gradle-docker-plugin:9.4.0' - } +plugins { + id 'com.bmuschko.docker-remote-api' version '9.4.0' } -apply plugin: 'com.bmuschko.docker-remote-api' +repositories { + mavenCentral() +} import com.bmuschko.gradle.docker.tasks.image.* -task copyLib (type: Copy) { +tasks.register('copyLib', Copy) { dependsOn ':fabric-chaincode-shim:build' from project(':fabric-chaincode-shim').configurations.runtimeClasspath into('build/distributions/chaincode-java/lib') } -task copyShimJar(type: Copy) { +tasks.register('copyShimJar', Copy) { dependsOn copyLib from project(':fabric-chaincode-shim').jar into('build/distributions/chaincode-java/lib') } -task copyStartScript(type: Copy) { +tasks.register('copyStartScript', Copy) { dependsOn copyShimJar - from ('start') - into ('build/distributions/chaincode-java') + from('start') + into('build/distributions/chaincode-java') } -task copyBuildScript(type: Copy) { +tasks.register('copyBuildScript', Copy) { dependsOn copyStartScript - from ('build.sh') - into ('build/distributions/chaincode-java') + from('build.sh') + into('build/distributions/chaincode-java') } -task copyAllDeps(type: Copy) { +tasks.register('copyAllDeps', Copy) { dependsOn copyBuildScript copy { from project(':fabric-chaincode-shim').getProjectDir() @@ -62,7 +56,7 @@ task copyAllDeps(type: Copy) { } } -task buildImage(type: DockerBuildImage) { +tasks.register('buildImage', DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.6', 'hyperledger/fabric-javaenv:amd64-latest'] diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 9d2b1fc7..240c506e 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { implementation project(':fabric-chaincode-docker') implementation project(':fabric-chaincode-shim') - implementation 'org.json:json:20240303' + implementation 'org.json:json:20250517' } @@ -12,17 +12,17 @@ dependencies { // Show test results. testLogging { events "passed", "skipped", "failed" - showExceptions true - showCauses true - showStandardStreams true - exceptionFormat "full" + showExceptions = true + showCauses = true + showStandardStreams = true + exceptionFormat = "full" } } -task getLatestDockerImages{ +tasks.register('getLatestDockerImages') { doLast { - exec { + providers.exec { workingDir "." commandLine "sh", "-c", "./getDockerImages.sh" } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 5a82082e..e7479c5c 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.5' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } @@ -17,7 +17,6 @@ compileJava { repositories { mavenCentral() - maven { url = "https://www.jitpack.io" } maven { url "$projectDir/repository" } @@ -25,7 +24,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' - implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' + implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } shadowJar { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 56c0f251..97d99090 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.5' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } @@ -17,7 +17,6 @@ compileJava { repositories { mavenCentral() - maven { url = "https://www.jitpack.io" } maven { url "$projectDir/repository" } @@ -25,7 +24,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' - implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' + implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } shadowJar { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 06b4af17..b59cca3c 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.5' + id 'com.gradleup.shadow' version '8.3.6' id 'java' } @@ -17,7 +17,6 @@ compileJava { repositories { mavenCentral() - maven { url = "https://www.jitpack.io" } maven { url "$projectDir/repository" } @@ -25,9 +24,9 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' - implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'commons-logging:commons-logging:1.2' - implementation 'com.google.code.gson:gson:2.10.1' + implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' + implementation 'commons-logging:commons-logging:1.3.5' + implementation 'com.google.code.gson:gson:2.13.1' } shadowJar { diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 326225ea..896f86c8 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -12,7 +12,7 @@ plugins { } pmd { - toolVersion = '7.12.0' + toolVersion = '7.14.0' ruleSetFiles = files('../pmd-ruleset.xml') ruleSets = [] // explicitly set to empty to avoid using the default configuration ignoreFailures = false @@ -31,33 +31,32 @@ tasks.withType(org.gradle.api.tasks.testing.Test) { } dependencies { - implementation platform('com.google.protobuf:protobuf-bom:3.25.5') - implementation platform('io.grpc:grpc-bom:1.68.1') - implementation platform('io.opentelemetry:opentelemetry-bom:1.42.1') + implementation platform('com.google.protobuf:protobuf-bom:4.31.1') + implementation platform('io.grpc:grpc-bom:1.73.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.51.0') - implementation 'org.hyperledger.fabric:fabric-protos:0.3.3' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.79' - implementation 'org.bouncycastle:bcprov-jdk18on:1.79' + implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.81' + implementation 'org.bouncycastle:bcprov-jdk18on:1.81' implementation 'io.github.classgraph:classgraph:4.8.179' - implementation 'com.github.everit-org.json-schema:org.everit.json.schema:1.14.4' - implementation 'org.json:json:20240303' + implementation 'com.github.erosb:everit-json-schema:1.14.6' + implementation 'org.json:json:20250517' implementation 'com.google.protobuf:protobuf-java-util' implementation 'io.grpc:grpc-netty-shaded' implementation 'io.grpc:grpc-protobuf' implementation 'io.grpc:grpc-stub' testImplementation 'io.grpc:grpc-inprocess' - // Required if using Java 11+ as no longer bundled in the core libraries - testImplementation 'javax.xml.bind:jaxb-api:2.3.1' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha' + implementation 'io.opentelemetry.proto:opentelemetry-proto:1.7.0-alpha' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.8.0-alpha' + implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.32.0' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.16.0-alpha' } sourceSets { @@ -343,10 +342,10 @@ tasks.withType(Test) { TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.STANDARD_OUT - exceptionFormat TestExceptionFormat.FULL - showExceptions true - showCauses true - showStackTraces true + exceptionFormat = TestExceptionFormat.FULL + showExceptions = true + showCauses = true + showStackTraces = true // set options for log level DEBUG and INFO debug { @@ -356,7 +355,7 @@ tasks.withType(Test) { TestLogEvent.SKIPPED, TestLogEvent.STANDARD_ERROR, TestLogEvent.STANDARD_OUT - exceptionFormat TestExceptionFormat.FULL + exceptionFormat = TestExceptionFormat.FULL } info.events = debug.events info.exceptionFormat = debug.exceptionFormat diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java index 8b11eccd..dab261e5 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/metadata/TypeSchema.java @@ -25,7 +25,7 @@ * *

    Does not include the "schema" top level map */ -@SuppressWarnings({"PMD.LooseCoupling", "PMD.GodClass"}) +@SuppressWarnings("PMD.GodClass") public final class TypeSchema extends HashMap { private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(TypeSchema.class.getName()); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java index 4352fe14..8197be59 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java @@ -314,7 +314,7 @@ public void setTlsEnabled(final boolean tlsEnabled) { * * @throws IllegalArgumentException if any properties are not valid. */ - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + @SuppressWarnings("PMD.CyclomaticComplexity") public void validate() { if (this.getServerAddress() == null) { throw new IllegalArgumentException("chaincodeServerProperties.getServerAddress() must be set"); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java index 54a3034f..4801ebe3 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java @@ -13,7 +13,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.grpc.v1_6.GrpcTelemetry; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.semconv.ResourceAttributes; +import io.opentelemetry.semconv.ServiceAttributes; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -32,7 +32,7 @@ public final class OpenTelemetryTracesProvider implements TracesProvider { @Override public void initialize(final Properties props) { String serviceName = props.getProperty(CORE_CHAINCODE_ID_NAME, "unknown"); - props.setProperty(ResourceAttributes.SERVICE_NAME.getKey(), serviceName); + props.setProperty(ServiceAttributes.SERVICE_NAME.getKey(), serviceName); OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.builder() .addPropertiesSupplier(() -> getOpenTelemetryProperties(props)) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e2847c82..ff23a68d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 1056635aa8e31ea3e29b1e54b841e59571bb370a Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 20 Jun 2025 16:33:44 +0100 Subject: [PATCH 032/178] Use JReleaser to publish to new Maven Central API (#380) Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 42 +++++--- fabric-chaincode-shim/build.gradle | 159 +++++++++++++++-------------- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43764 bytes gradlew | 9 +- gradlew.bat | 4 +- 5 files changed, 114 insertions(+), 100 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ed40537..76b72b2d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,14 +15,7 @@ env: IMAGE_NAME: ${{ github.repository_owner }}/fabric-javaenv jobs: - # Publishing steps to both the Github Packages and the Sonatype - publishjars: - strategy: - fail-fast: false - matrix: - publish_target: - - publishAllPublicationsToGithubPackagesRepository - - publishAllPublicationsToReleaseRepository + publish-github: runs-on: ubuntu-latest permissions: contents: read @@ -34,18 +27,35 @@ jobs: distribution: "temurin" java-version: 21 - uses: gradle/actions/setup-gradle@v4 - - name: Push to registry ${{ matrix.publish_target }} + - name: Publish to GitHub Packages run: | - set -xev - ./gradlew -Psigning.key="${SIGNING_KEY}" -Psigning.password="${SIGNING_PASSWORD}" -PossrhUsername="${OSSRH_USER}" -PossrhPassword="${OSSRH_PASSWORD}" ${TARGET} + ./gradlew publishAllPublicationsToGitHubRepository env: - SIGNING_PASSWORD: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} - SIGNING_KEY: ${{ secrets.OSSRH_GPG_SECRET_KEY }} - OSSRH_USER: ${{ secrets.OSSRH_USERNAME }} - OSSRH_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - TARGET: ${{ matrix.publish_target }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSSRH_GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + publish-maven: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: 21 + - uses: gradle/actions/setup-gradle@v4 + - name: Publish to Maven Central + run: | + ./gradlew publishAllPublicationsToStagingRepository + ./gradlew jreleaserDeploy --stacktrace + env: + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSSRH_GPG_SECRET_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.MAVENCENTRAL_USERNAME }} + JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.MAVENCENTRAL_PASSWORD }} + docker-build-push: name: Push Docker image runs-on: ${{ matrix.arch.runner }} diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 896f86c8..8cff266f 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -6,8 +6,9 @@ plugins { id 'maven-publish' - id 'jacoco' id 'signing' + id 'org.jreleaser' version '1.18.0' + id 'jacoco' id 'pmd' } @@ -137,7 +138,7 @@ jacocoTestCoverageVerification { test.finalizedBy(jacocoTestReport) test.finalizedBy(jacocoTestCoverageVerification) -task licenseCheck { +tasks.register('licenseCheck') { group = "license" description = "Checks the License part of each source file" @@ -146,34 +147,37 @@ task licenseCheck { def missing = new LinkedList() sourceSets.forEach { sourceSet -> - sourceSet.allSource.findAll { !it.path.contains("build") && !(it.path.contains("test") && it.path.contains("resources"))}.each { + sourceSet.allSource.findAll { + !it.path.contains("build") && + !(it.path.contains("test") && it.path.contains("resources")) + }.each { file -> - if (!file.name.contains("json")){ - BufferedReader r = new BufferedReader(new FileReader(file)) - def line, hasSPDX = false, hasTraditional = false - while ((line = r.readLine()) != null) { - if (line.contains("SPDX-License-Identifier")) { - hasSPDX = true - break + if (!file.name.contains("json")) { + BufferedReader r = new BufferedReader(new FileReader(file)) + def line, hasSPDX = false, hasTraditional = false + while ((line = r.readLine()) != null) { + if (line.contains("SPDX-License-Identifier")) { + hasSPDX = true + break + } + if (line.contains("http://www.apache.org/licenses/LICENSE-2.0")) { + hasTraditional = true + break + } } - if (line.contains("http://www.apache.org/licenses/LICENSE-2.0")) { - hasTraditional = true - break - } - } - if (!hasSPDX) { - if (hasTraditional) { - noSPDX.add(file) - } else { - missing.add(file) + if (!hasSPDX) { + if (hasTraditional) { + noSPDX.add(file) + } else { + missing.add(file) + } } } - } } } if (noSPDX.isEmpty()) { - println "All remaining files have Apache 2.0 headers" + println "All remaining files have Apache 2.0 headers." } else { println "We are standardizing with the SPDX style license headers." println "The following files contain the traditional license headers which are still valid:" @@ -212,17 +216,13 @@ javadoc { classpath = sourceSets.main.runtimeClasspath - javadoc.options.addStringOption('Xdoclint:none', '-quiet') + options.addStringOption('Xdoclint:none', '-quiet') + options.addStringOption('Xwerror', '-quiet') options.overview = "src/main/java/org/hyperledger/fabric/overview.html" -} -if (JavaVersion.current().isJava8Compatible()) { - project.tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:all', '-quiet') - options.addStringOption('Xwerror', '-quiet') - } } +def final stagingDeployUrl = layout.buildDirectory.dir('staging-deploy') publishing { publications { @@ -235,10 +235,12 @@ publishing { name = 'JavaChaincodeShim' packaging = 'jar' description = 'Hyperledger Fabric Java Chaincode Shim' - url = 'http://www.hyperledger.org/' + url = 'https://hyperledger.github.io/fabric-chaincode-java/' scm { - url = 'https://github.com/hyperledger/fabric-chaincode-java.git' + connection = 'scm:git:https://github.com/hyperledger/fabric-chaincode-java.git' + developerConnection = 'scm:git:ssh://github.com:hyperledger/fabric-chaincode-java.git' + url = 'https://github.com/hyperledger/fabric-chaincode-java' } licenses { license { @@ -248,26 +250,16 @@ publishing { } developers { - developer { - id = 'gennadylaventman' - name = 'Gennady Laventman' - email = 'gennady@il.ibm.com' - } - developer { - id = 'luiss' - name = 'Luis Sanchez' - email = 'luiss@me.com' - } - developer { - id = 'C0rWin' - name = 'Artem Barger' - email = 'bartem@il.ibm.com' - } developer { id = 'denyeart' name = 'David Enyeart' email = 'enyeart@us.ibm.com' } + developer { + id = 'bestbeforetoday' + name = 'Mark S. Lewis' + email = 'Mark.S.Lewis@outlook.com' + } } } } @@ -276,17 +268,12 @@ publishing { repositories { maven { - name = "release" - url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - credentials { - username = project.findProperty('ossrhUsername') - password = project.findProperty('ossrhPassword') - } - + name = "Staging" + url = stagingDeployUrl } maven { - name = "GitHubPackages" + name = "GitHub" url = "https://maven.pkg.github.com/hyperledger/fabric-chaincode-java" credentials { username = System.getenv("GITHUB_ACTOR") @@ -297,16 +284,33 @@ publishing { } signing { - println "Signing" - if (project.findProperty('signing.key')) { - def signingKey = project.findProperty('signing.key') - def signingPassword = project.findProperty('signing.password') - useInMemoryPgpKeys(signingKey, signingPassword) - - sign publishing.publications.shim - println "... signed" - } else { - println "... no keys to use " + required = { gradle.taskGraph.hasTask(":${project.name}:publishShimPublicationToStagingRepository") } + + def signingKey = findProperty('signingKey') + def signingPassword = findProperty('signingPassword') + useInMemoryPgpKeys(signingKey, signingPassword) + + sign publishing.publications.shim +} + +jreleaser { + gitRootSearch = true + deploy { + maven { + mavenCentral { + sonatype { + active = 'ALWAYS' + url = 'https://central.sonatype.com/api/v1/publisher' + sign = false + stagingRepository(file(stagingDeployUrl).toString()) + } + } + } + } + release { + github { + enabled = false + } } } @@ -314,8 +318,8 @@ signing { // otherwise this fails with a duplicates error. // (see https://github.com/gradle/gradle/issues/17236) -task sourcesJar(type: Jar) { - duplicatesStrategy = 'include' +tasks.register('sourcesJar', Jar) { + duplicatesStrategy = DuplicatesStrategy.INCLUDE archiveClassifier = 'sources' from sourceSets.main.allSource } @@ -332,16 +336,16 @@ build.dependsOn licenseCheck import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent -tasks.withType(Test) { +tasks.withType(Test).configureEach { environment "CORE_PEER_LOCALMSPID", "mymsp" testLogging { // set options for log level LIFECYCLE events TestLogEvent.FAILED, - TestLogEvent.PASSED, - TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_OUT + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_OUT exceptionFormat = TestExceptionFormat.FULL showExceptions = true showCauses = true @@ -350,22 +354,23 @@ tasks.withType(Test) { // set options for log level DEBUG and INFO debug { events TestLogEvent.STARTED, - TestLogEvent.FAILED, - TestLogEvent.PASSED, - TestLogEvent.SKIPPED, - TestLogEvent.STANDARD_ERROR, - TestLogEvent.STANDARD_OUT + TestLogEvent.FAILED, + TestLogEvent.PASSED, + TestLogEvent.SKIPPED, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STANDARD_OUT exceptionFormat = TestExceptionFormat.FULL } info.events = debug.events info.exceptionFormat = debug.exceptionFormat - afterSuite { desc, result -> + afterSuite {desc, result -> if (!desc.parent) { // will match the outermost suite def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" def startItem = '| ', endItem = ' |' def repeatLength = startItem.length() + output.length() + endItem.length() - println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) + println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + + ('-' * repeatLength)) } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 34943 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

    Gn4F+B~IivciU9^t0j-Mgao3 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 DDw4oP diff --git a/gradlew b/gradlew index f5feea6d..23d15a93 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -206,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -214,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019c..5eed7ee8 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From b275bd66e9b437d7943c2f7258f7c2800251d873 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 24 Jun 2025 21:22:47 +0100 Subject: [PATCH 033/178] Update versions following v2.5.6 release (#381) Signed-off-by: Mark S. Lewis --- RELEASING.md | 70 ++++--------------- build.gradle | 2 +- .../build.gradle | 2 +- .../build.gradle.kts | 2 +- .../build.gradle | 4 +- .../fabric-contract-example-maven/pom.xml | 2 +- examples/ledger-api/build.gradle | 4 +- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../contracts/fabric-ledger-api/build.gradle | 2 +- .../contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 13 files changed, 28 insertions(+), 70 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 7550061e..c0366a4c 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,74 +2,32 @@ The following artifacts are created as a result of releasing Fabric Chaincode Java: -- docker images - - [fabric-javaenv](https://hub.docker.com/r/hyperledger/fabric-javaenv) -- Java libraries - - [fabric-chaincode-shim](https://search.maven.org/search?q=a:fabric-chaincode-shim) - -**Note:** A docker image with a matching V.R version is required before releasing a new version of Fabric. +- `fabric-javaenv` Docker images: + - [Docker Hub](https://hub.docker.com/r/hyperledger/fabric-javaenv) + - [GitHub Packages](https://github.com/orgs/hyperledger/packages/container/package/fabric-javaenv) +- `fabric-chaincode-shim` Java libraries: + - [Maven Central](https://central.sonatype.com/artifact/org.hyperledger.fabric-chaincode-java/fabric-chaincode-shim) + - [GitHub Packages](https://github.com/hyperledger/fabric-chaincode-java/packages/50049) ## Before releasing -It's useful to create an issue to keep track of each release, for example [Release v2.1.0](https://jira.hyperledger.org/browse/FABCJ-283). - The following tasks are required before releasing: -- Update version numbers in `build.gradle` files to the required version -- Update test, sample, and docs files to match the new version -- Update the [`COMPATIBILITY.md`](./COMPATIBILITY.md) - -See the [[FABCJ-289] release: 2.2.0 LTS](https://github.com/hyperledger/fabric-chaincode-java/pull/124) pull request for an example, although be careful to search for all versions in the codebase as they're easy to miss and things change! - -Ensure the last branch build passed since exactly this repository state will be released. +- Ensure the version number in `build.gradle` is the required release version. +- Check the last branch build passed since exactly this repository state will be released. ## Create release Creating a GitHub release on the [releases page](https://github.com/hyperledger/fabric-chaincode-java/releases) will trigger the build to publish the new release. -When drafting the release, create a new tag for the new version (with a `v` prefix), e.g. `v2.1.4` +When drafting the release, create a new tag for the new version (with a `v` prefix). For example: `v2.1.4` See previous releases for examples of the title and description. -## Publish Java libraries - -Log on to the [nexus repository manager](https://oss.sonatype.org/#welcome) to manually publish the JARs which were pushed by the release build. - -Find the results of the release build under _Build Promotion > Staging Repositories_ and perform the following steps: - -1. Close - - You should see a series of close activities (see note) - -2. Release using the automatically drop option - - You should see a series of release activities (see note) - -Note: you may need to refresh to update the activities view. - -When the release has completed and the _Staging Repositories_ list is empty, the Java chaincode libraries should appear in the maven repository. They can take some time to appear in the UI but they should exist in the repository sooner. - ## After releasing -- Update version numbers in `build.gradle` files to the next version -- Update test, sample, and docs files to match the new version - -See the [Bump version to 2.2.1](https://github.com/hyperledger/fabric-chaincode-java/pull/127) pull request for an example. It should include almost all the files changed to prepare for the release, except for the release notes and changelog which do not need updating. - -## Interim Build Publishing - -The nightly Azure Pipeline Builds will also publish the 'dev' drivers to Artifactory. These can be accessed via the repository at - -``` - maven { - url "https://hyperledger.jfrog.io/hyperledger/fabric-maven" - } -``` - -These 'dev' drivers are built from the main branch only, and have a version format including the date for example `2.3.1.dev.20210303`. They can be accessed in a build file like this - -``` -dependencies { - compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '2.3.1.dev.+' - } -``` +- Update the version number in `build.gradle` to the next version. +- Update version numbers in `fabric-chaincode-docker/build.gradle` to match the next version. +- Update the `fabric-chaincode-shim` dependency version in all `build.gradle` and `pom.xml` files within `fabric-chaincode-integration-test/src/contracts` to match the next version. +- Update the `fabric-chaincode-shim` dependency version in all `build.gradle`, `build.gradle.kts` and `pom.xml` files within `examples` to mast the last _released_ version. +- Check that `COMPATIBILITY.md` is correct and update if required. diff --git a/build.gradle b/build.gradle index d0be9fd6..192a83cd 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id "com.diffplug.spotless" version "7.0.4" } -version = '2.5.6' +version = '2.5.7' // If the nightly property is set, then this is the scheduled main diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index a8d36524..67c0442a 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' testImplementation 'org.assertj:assertj-core:3.27.3' diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 92917bed..ffd88adc 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -14,7 +14,7 @@ plugins { version = "0.0.1" dependencies { - implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5") + implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6") implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index a4b82222..6194c73e 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -13,8 +13,8 @@ repositories { } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' - compile 'org.json:json:20250517' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' testImplementation 'org.assertj:assertj-core:3.27.3' testImplementation 'org.mockito:mockito-core:5.18.0' diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 41d2202f..39f1e39d 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.5 + 2.5.6 1.5.15 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 8f94a9b2..3b01193c 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -13,8 +13,8 @@ repositories { } dependencies { - compile 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.5' - compile 'org.json:json:20250517' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' testImplementation 'org.assertj:assertj-core:3.27.3' testImplementation 'org.mockito:mockito-core:5.18.0' diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index b5dbbeb5..97f95226 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -59,5 +59,5 @@ tasks.register('copyAllDeps', Copy) { tasks.register('buildImage', DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.6', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.7', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index e7479c5c..84e1f21a 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -23,7 +23,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index fccbc9e0..2671d423 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.6 + 2.5.7 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 97d99090..ab453cbe 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -23,7 +23,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index b59cca3c..7eee2b31 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -23,7 +23,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'commons-logging:commons-logging:1.3.5' implementation 'com.google.code.gson:gson:2.13.1' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 894443ea..1f34fa68 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.6 + 2.5.7 From 01c5dd9a07f366704da6d3a7b583d5e6f0eeab26 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 17 Jul 2025 17:42:23 +0100 Subject: [PATCH 034/178] Allow scanning of all dependencies (#383) The default vulnerability scan, run with `make scan`, checks only the runtimeClasspath dependencies. This change add a `scan-all` Makefile target that checks all dependencies, including test and plugin dependencies. Signed-off-by: Mark S. Lewis --- Makefile | 8 ++++++++ fabric-chaincode-shim/build.gradle | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 44118a94..c64334c5 100644 --- a/Makefile +++ b/Makefile @@ -16,9 +16,17 @@ endif .PHONY: scan scan: $(osv-scanner) + rm -f fabric-chaincode-shim/gradle.lockfile ./gradlew --quiet :fabric-chaincode-shim:dependencies --write-locks --configuration runtimeClasspath bin/osv-scanner scan --lockfile=fabric-chaincode-shim/gradle.lockfile +.PHONY: scan-all +scan-all: $(osv-scanner) + rm -f fabric-chaincode-shim/gradle.lockfile + ./gradlew --quiet :fabric-chaincode-shim:dependencies --write-locks + bin/osv-scanner scan --lockfile=fabric-chaincode-shim/gradle.lockfile + + .PHONY: install-osv-scanner install-osv-scanner: mkdir -p '$(bin_dir)' diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 8cff266f..4df93310 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -21,10 +21,8 @@ pmd { pmdTest.enabled = false -configurations { - runtimeClasspath { - resolutionStrategy.activateDependencyLocking() - } +dependencyLocking { + lockAllConfigurations() } tasks.withType(org.gradle.api.tasks.testing.Test) { From 1a2ae9811d2458a21efcc3839f58fc664469095c Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Thu, 17 Jul 2025 17:42:58 +0100 Subject: [PATCH 035/178] Remove unused content (#384) Remove old (Azure Pipelines) build definitions and scripts, and Gradle build tasks. Signed-off-by: Mark S. Lewis --- build.gradle | 6 +- ci/azure-pipelines.yml | 228 ----------------------------- ci/publish_jar_nexus.sh | 33 ----- ci/templates/build-data.yml | 16 -- fabric-chaincode-shim/build.gradle | 2 +- scripts/changelog.sh | 22 --- scripts/gittag.sh | 35 ----- scripts/multiarch.sh | 81 ---------- scripts/verify-commit.sh | 48 ------ 9 files changed, 2 insertions(+), 469 deletions(-) delete mode 100644 ci/azure-pipelines.yml delete mode 100755 ci/publish_jar_nexus.sh delete mode 100644 ci/templates/build-data.yml delete mode 100755 scripts/changelog.sh delete mode 100755 scripts/gittag.sh delete mode 100755 scripts/multiarch.sh delete mode 100755 scripts/verify-commit.sh diff --git a/build.gradle b/build.gradle index 192a83cd..b605ec4f 100644 --- a/build.gradle +++ b/build.gradle @@ -85,12 +85,8 @@ subprojects { } } -task printVersionName() { - println rootProject.version -} - // Get the date in the reverse format for sorting -def getDate() { +static def getDate() { def date = new Date() def formattedDate = date.format('yyyyMMdd') return formattedDate diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml deleted file mode 100644 index 57986c2d..00000000 --- a/ci/azure-pipelines.yml +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# -# fabric-chaincode-java azure pipeline configuration. -# -name: $(SourceBranchName)-$(Date:yyyyMMdd)$(Rev:.rrr) - -# Daily build for final quality -# cf https://crontab.guru/#0_23_*_*_* -schedules: - - cron: "0 10,12,14,16,23 * * *" - displayName: "Chaincode Java Nightly Driver" - branches: - include: - - main - -trigger: - branches: - include: - - "release-2.5" - tags: - include: - - "*" - -# These are custom defined variables, the pipeline one is currently used for the build scripts -# to know to produce tests results in XML format for Azure to consume, for developers -# this isn't set so command line output is given -# -# Chaincode_Java_Creds is the protected group of keys for publishing -# -variables: - - group: Chaincode_Java_Creds - - group: Github-PackageRegistry-Credentials - - group: JARSigningPublish - - name: component - value: fabric-chaincode-java - - name: pipeline - value: ci - - name: PUSH_VERSION - value: stable - - name: FABRIC_VERSION - value: 2.5-stable - -pool: - vmImage: "ubuntu-latest" - -# The stages and jobs, potential for rationalization and optimization -# Keeping it simple and explicit whilst we gain experience -# -stages: - - stage: Build_and_test - jobs: - - job: displayenv - steps: - - template: templates/build-data.yml - - job: main - steps: - - task: Gradle@2 - inputs: - workingDirectory: "" - gradleWrapperFile: "gradlew" - gradleOptions: "-Xmx3072m" - javaHomeOption: "JDKVersion" - jdkVersionOption: "1.8" - jdkArchitectureOption: "x64" - options: "-x javadoc -x :fabric-chaincode-integration-test:test" - publishJUnitResults: true - testResultsFiles: "$(System.DefaultWorkingDirectory)/**/TEST-*.xml" - tasks: "build" - - task: PublishBuildArtifacts@1 - condition: or(succeeded(), failed()) - inputs: - pathToPublish: fabric-chaincode-shim/build/reports/checkstyle/ - artifactName: checkstylereport - displayName: 'Checkstyle' - continueOnError: true - - task: PublishBuildArtifacts@1 - condition: or(succeeded(), failed()) - inputs: - pathToPublish: fabric-chaincode-shim/build/reports/jacoco/ - artifactName: coveragereport - displayName: 'JaCoCo Coverage' - continueOnError: true - - task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: 'fabric-chaincode-shim/build/reports/dependency-check-junit.xml' - mergeTestResults: true - failTaskOnFailedTests: false - testRunTitle: OWASP Dependency Check - displayName: 'Publish OWASP Dependency Check JUnit results' - - task: CopyFiles@2 - inputs: - contents: | - fabric-chaincode-shim/build/reports/dependency-check-*.* - targetFolder: $(Build.ArtifactStagingDirectory)/dependency-check - displayName: 'Collect OWASP Dependency Check results' - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(Build.ArtifactStagingDirectory)/dependency-check - artifactName: 'Dependency Check Report' - displayName: 'Publish full OWASP Dependency Check result' - - task: PublishCodeCoverageResults@1 - inputs: - summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/fabric-chaincode-shim/build/reports/jacoco/test/jacocoTestReport.xml" - # Copy the built artifacts to the staging directory, tgz, and the docker image - - script: | - set -ev - ./gradlew -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} publishShimJarPublicationToMavenLocal - tar -zcvf localmaven.tgz ${HOME}/.m2/repository/org/hyperledger - docker image save hyperledger/fabric-javaenv | gzip > $(Build.ArtifactStagingDirectory)/fabric-javaenv.tar.gz - displayName: 'Package tgz and docker image' - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: localmaven.tgz - artifactName: java-tgz - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: $(Build.ArtifactStagingDirectory)/fabric-javaenv.tar.gz - artifactName: javaenv-docker-image - - - job: javadoc - dependsOn: displayenv - variables: - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: - javadoc_release: main - ${{ if ne(variables['Build.SourceBranch'], 'refs/heads/main') }}: - javadoc_release: $[format('release-{0}',dependencies.displayenv.outputs['BuildData.MINOR_PACKAGE_VERSION'])] - steps: - - script: ./gradlew javadoc - displayName: 'Build JavaDoc' - - script: | - if [ -d docs ]; then - mkdir gh-pages - cp -r docs/* gh-pages - fi - displayName: 'Copy gh-pages doc' - condition: eq(variables['Build.SourceBranch'], 'refs/heads/main') - - script: | - git fetch origin - git checkout -b gh-pages origin/gh-pages - mkdir -p $(javadoc_release)/api - rm -rf $(javadoc_release)/api/* - cp -r fabric-chaincode-shim/build/docs/javadoc/* $(javadoc_release)/api - - # if the gh-pages is present from the previous script, then copy across the files across. - if [ -d gh-pages ]; then - find . -maxdepth 1 ! \( -name [.]* -o -name 'gh-pages' -o -name 'main' -o -name 'release-*' \) -exec rm -rf {} \; - cp -r gh-pages/* . - rm -rf gh-pages - fi - displayName: 'Update gh-pages branch' - - script: | - git config --global user.email "hlfdev.azp@gmail.com" - git config --global user.name "Hyperledger Bot" - git add -A - git commit -m "Publishing GitHub Pages" - git push https://$(GITHUB-PAT)@github.com/hyperledger/fabric-chaincode-java.git gh-pages - displayName: 'Commit gh-pages changes' - condition: and(succeeded(),eq(variables['Build.Reason'], 'IndividualCI')) - - # As the next script is more complex and uses loops, run this discretely in a sh file - # Publishing step for git tags - - stage: Publish_tag - condition: and(succeeded('Build_and_test'), startsWith(variables['Build.SourceBranch'], 'refs/tags')) - jobs: - - job: docker_publish - steps: - - template: templates/build-data.yml - - task: DownloadPipelineArtifact@2 - inputs: - artifact: javaenv-docker-image - path: $(Build.SourcesDirectory)/build - - script: | - wget -qO "$PWD/manifest-tool" https://github.com/estesp/manifest-tool/releases/download/v1.0.0/manifest-tool-linux-amd64 - chmod +x ./manifest-tool - - docker image load --input build/fabric-javaenv.tar.gz - docker images - docker login ${DOCKER_REGISTRY_URL} --username=${DOCKER_REGISTRY_USERNAME} --password=${DOCKER_REGISTRY_PASSWORD} - echo "Logged in to docker registry" - # tag javaenv image to PACKAGE_VERSION - docker tag hyperledger/fabric-javaenv hyperledger/fabric-javaenv:amd64-$(BuildData.PACKAGE_VERSION) - # push javaenv to repository - docker push hyperledger/fabric-javaenv:amd64-$(BuildData.PACKAGE_VERSION) - ./manifest-tool push from-args --platforms linux/amd64 --template "hyperledger/fabric-javaenv:amd64-$(BuildData.PACKAGE_VERSION)" --target "hyperledger/fabric-javaenv:$(BuildData.PACKAGE_VERSION)" - ./manifest-tool push from-args --platforms linux/amd64 --template "hyperledger/fabric-javaenv:amd64-$(BuildData.PACKAGE_VERSION)" --target "hyperledger/fabric-javaenv:$(BuildData.MINOR_PACKAGE_VERSION)" - env: - DOCKER_REGISTRY_USERNAME: $(DockerHub-Username) - DOCKER_REGISTRY_PASSWORD: $(DockerHub-Password) - - job: jar_publish - steps: - - template: templates/build-data.yml - - task: DownloadSecureFile@1 - name: keyring - inputs: - secureFile: secring.gpg - - script: | - ./gradlew -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} -PossrhUsername=${OSSRH_USER} -PossrhPassword=${OSSRH_PASSWORD} publishAllPublicationsToReleaseRepository - ./gradlew -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} -PossrhUsername=${OSSRH_USER} -PossrhPassword=${OSSRH_PASSWORD} publishAllPublicationsToSnapshotRepository - env: - SIGNING_ID: $(JAR-Signing-Id) - SIGNING_PASSWORD: $(JAR-Signing-Password) - KEYRING_FILE: $(keyring.secureFilePath) - OSSRH_USER: $(OSSRH-User) - OSSRH_PASSWORD: $(OSSRH-Password) - - # will re-enable when we get a proper userid/password - # - stage: Publish_tag_nightly - # condition: and(succeeded('Build_and_test'), eq(variables['Build.Reason'], 'Schedule')) # only run on the scheduled builds - # jobs: - # - job: jar_publish - # steps: - # - template: templates/build-data.yml - # - task: DownloadSecureFile@1 - # name: keyring - # inputs: - # secureFile: secring.gpg - # - script: | - # ./gradlew -PNIGHTLY=true -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} -PartifactoryUsername=${ARTIFACTORY_USER} -PartifactoryhPassword=${ARTIFACTORY_PASSWORD} publishAllPublicationsToReleaseRepository - # ./gradlew -PNIGHTLY=true -Psigning.keyId=${SIGNING_ID} -Psigning.password=${SIGNING_PASSWORD} -Psigning.secretKeyRingFile=${KEYRING_FILE} -PartifactoryUsername=${ARTIFACTORY_USER} -PartifactoryhPassword=${ARTIFACTORY_PASSWORD} publishAllPublicationsToSnapshotRepository - # env: - # SIGNING_ID: $(JAR-Signing-Id) - # SIGNING_PASSWORD: $(JAR-Signing-Password) - # KEYRING_FILE: $(keyring.secureFilePath) - # ARTIFACTORY_USER: $(ARTIFACTORY-User) - # ARTIFACTORY_PASSWORD: $(ARTIFACTORY-Password) diff --git a/ci/publish_jar_nexus.sh b/ci/publish_jar_nexus.sh deleted file mode 100755 index 12ff7625..00000000 --- a/ci/publish_jar_nexus.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Exit on first error, print all commands. -set -e -set -o pipefail -WORKSPACE="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" - -function abort { - echo "!! Exiting shell script" - echo "!!" "$1" - exit -1 -} - -for binary in shim; do -echo "Pushing fabric-chaincode-$binary.$PUSH_VERSION.jar to maven releases.." -cp $WORKSPACE/fabric-chaincode-$binary/build/libs/fabric-chaincode-$binary-$PUSH_VERSION.jar $WORKSPACE/fabric-chaincode-$binary/build/libs/fabric-chaincode-$binary.$PUSH_VERSION.jar -mvn org.apache.maven.plugins:maven-deploy-plugin:deploy-file \ - -DupdateReleaseInfo=true \ - -Dfile=$WORKSPACE/fabric-chaincode-$binary/build/libs/fabric-chaincode-$binary.$PUSH_VERSION.jar \ - -DpomFile=$WORKSPACE/fabric-chaincode-$binary/build/publications/"$binary"Jar/pom-default.xml \ - -DrepositoryId=hyperledger-releases \ - -Durl=https://nexus.hyperledger.org/content/repositories/releases/ \ - -DgroupId=org.hyperledger.fabric-chaincode-java \ - -Dversion=$PUSH_VERSION \ - -DartifactId=fabric-chaincode-$binary \ - -DgeneratePom=false \ - -DuniqueVersion=false \ - -Dpackaging=jar \ - -gs $GLOBAL_SETTINGS_FILE -s $SETTINGS_FILE -done \ No newline at end of file diff --git a/ci/templates/build-data.yml b/ci/templates/build-data.yml deleted file mode 100644 index ead7e0bc..00000000 --- a/ci/templates/build-data.yml +++ /dev/null @@ -1,16 +0,0 @@ -steps: -- script: | - env | sort - java -version - # handle full version number - VERSION=$(./gradlew -q printVersionName | head -n 1 | cut -d'-' -f1) - VERSION=${VERSION// } - echo Current version in code is :${VERSION}: - echo "##vso[task.setvariable variable=PACKAGE_VERSION;isOutput=true]${VERSION}" - # handle minor version - MINOR_VERSION=$(echo $VERSION | sed 's/^\([0-9]\{1,\}\.[0-9]\{1,\}\)\..*/\1/') - MINOR_VERSION=${MINOR_VERSION// } - echo Current minor version in code is :${MINOR_VERSION}: - echo "##vso[task.setvariable variable=MINOR_PACKAGE_VERSION;isOutput=true]${MINOR_VERSION}" - name: BuildData - displayName: 'Build data' diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 4df93310..a361d7f1 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -25,7 +25,7 @@ dependencyLocking { lockAllConfigurations() } -tasks.withType(org.gradle.api.tasks.testing.Test) { +tasks.withType(Test).configureEach { systemProperty 'CORE_CHAINCODE_LOGGING_LEVEL', 'DEBUG' } diff --git a/scripts/changelog.sh b/scripts/changelog.sh deleted file mode 100755 index b74634c4..00000000 --- a/scripts/changelog.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# -set -ev - -PREVIOUS_TAG=$1 -NEW_VERSION=$2 - -: ${PREVIOUS_TAG:?} -: ${NEW_VERSION:?} - -echo "## ${NEW_VERSION}" >> CHANGELOG.new -echo "$(date)" >> CHANGELOG.new -echo "" >> CHANGELOG.new -git log ${PREVIOUS_TAG}..HEAD --oneline | grep -v Merge | sed -e "s/\[\{0,1\}\(FAB[^0-9]*-[0-9]*\)\]\{0,1\}/\[\1\](https:\/\/jira.hyperledger.org\/browse\/\1\)/" -e "s/\([0-9|a-z]*\)/* \[\1\](https:\/\/github.com\/hyperledger\/fabric-chaincode-java\/commit\/\1)/" >> CHANGELOG.new -echo "" >> CHANGELOG.new -cat CHANGELOG.md >> CHANGELOG.new -mv -f CHANGELOG.new CHANGELOG.md - diff --git a/scripts/gittag.sh b/scripts/gittag.sh deleted file mode 100755 index c41fd806..00000000 --- a/scripts/gittag.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Exit on first error, print all commands. -set -e -set -o pipefail -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )" - -# release name -RELEASE=release-1.4 - -function abort { - echo "!! Exiting shell script" - echo "!!" "$1" - exit -1 -} - -# Run printVersionName task in the root directory, grab the first line and remove anything after the version number -VERSION=$(cd ../ && ./gradlew -q printVersionName | head -n 1 | cut -d'-' -f1) - -echo New version string will be v${VERSION} - -# do the release notes for this new version exist? -if [[ -f "${DIR}/release_notes/v${VERSION}.txt" ]]; then - echo "Release notes exist, hope they make sense!" -else - abort "No releases notes under the file ${DIR}/release_notes/v${NEW_VERSION}.txt exist"; -fi - -git checkout "${RELEASE}" -git pull -git tag -a "v${VERSION}" `git log -n 1 --pretty=oneline | head -c7` -F release_notes/"v${VERSION}".txt -git push origin v${VERSION} HEAD:refs/heads/${RELEASE} \ No newline at end of file diff --git a/scripts/multiarch.sh b/scripts/multiarch.sh deleted file mode 100755 index 5795a46f..00000000 --- a/scripts/multiarch.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/sh -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - -usage() { - echo "Usage: $0 " - echo " and credentials for the repository" - echo "ENV:" - echo " NS=$NS" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -missing() { - echo "Error: some image(s) missing from registry" - echo "ENV:" - echo " NS=$NS" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -failed() { - echo "Error: multiarch manifest push failed" - echo "ENV:" - echo " NS=$NS" - echo " VERSION=$VERSION" - echo " TWO_DIGIT_VERSION=$TWO_DIGIT_VERSION" - exit 1 -} - -USER=${1:-nobody} -PASSWORD=${2:-nohow} -NS=${NS:-hyperledger} -VERSION=${BASE_VERSION:-1.3.0} -TWO_DIGIT_VERSION=${TWO_DIGIT_VERSION:-1.3} - -if [ "$#" -ne 2 ]; then - usage -fi - -# verify that manifest-tool is installed and found on PATH -which manifest-tool -if [ "$?" -ne 0 ]; then - echo "manifest-tool not installed or not found on PATH" - exit 1 -fi - -IMAGES="fabric-javaenv" - -# check that all images have been published -for image in ${IMAGES}; do - docker pull ${NS}/${image}:amd64-${VERSION} || missing -done - -# push the multiarch manifest and tag with just $VERSION and 'latest' -for image in ${IMAGES}; do - manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ - --platforms linux/amd64 --template "${NS}/${image}:ARCH-${VERSION}"\ - --target "${NS}/${image}:${VERSION}" -# manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ -# --platforms linux/amd64 --template "${NS}/${image}:ARCH-${VERSION}"\ -# --target "${NS}/${image}:latest" - manifest-tool --username ${USER} --password ${PASSWORD} push from-args\ - --platforms linux/amd64 --template "${NS}/${image}:ARCH-${VERSION}"\ - --target "${NS}/${image}:${TWO_DIGIT_VERSION}" -done - -# test that manifest is working as expected -for image in ${IMAGES}; do - docker pull ${NS}/${image}:${VERSION} || failed - docker pull ${NS}/${image}:${TWO_DIGIT_VERSION} || failed -# docker pull ${NS}/${image}:latest || failed -done - -echo "Successfully pushed multiarch manifest" -exit 0 diff --git a/scripts/verify-commit.sh b/scripts/verify-commit.sh deleted file mode 100755 index 0fb1dcd8..00000000 --- a/scripts/verify-commit.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -ue - -# -# SPDX-License-Identifier: Apache-2.0 -############################################################################## -# Copyright (c) 2018 IBM Corporation, The Linux Foundation and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License 2.0 -# which accompanies this distribution, and is available at -# https://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -# This script makes several basic commit message validations. -# This is with the purpose of keeping up with the aesthetics of our code. -# Verify if the commit message contains JIRA URLs. -# its-jira pluggin attempts to process jira links and breaks. - -set +ue # Temporarily ignore any errors - -set -o pipefail -echo "----> verify-commit.sh" - -if git rev-list --format=%B --max-count=1 HEAD | grep -io 'http[s]*://jira\..*' > /dev/null ; then - echo 'Error: Remove JIRA URLs from commit message' - echo 'Add jira references as: Issue: -, instead of URLs' - exit 1 -fi - -# Check for trailing white-space (tab or spaces) in any files that were changed -#commit_files=$(git diff-tree --name-only -r HEAD~2..HEAD) -commit_files=$(find ./fabric-chaincode-shim/src -name *.java) - -found_trailing=false -for filename in $commit_files; do - if [[ $(file -b $filename) == "ASCII text"* ]]; then - if egrep -q "\s$" $filename; then - found_trailing=true - echo "Error: Trailing white spaces found in file: $filename" - fi - fi -done - -#if $found_trailing; then -# echo "#### filename:line-num:line ####" -# egrep -n "\s$" $commit_files -# exit 1 -#fi \ No newline at end of file From c56793c7adef45b52954ffe92b4412a27ae2ac40 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 21 Jul 2025 22:10:34 +0100 Subject: [PATCH 036/178] Use commit hashes for GitHub Action versions Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 36 +++++++++++++++++------------------ .github/workflows/scan.yml | 8 ++++---- .github/workflows/test.yml | 20 +++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76b72b2d..9b2ae89d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,12 +21,12 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -40,12 +40,12 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Publish to Maven Central run: | ./gradlew publishAllPublicationsToStagingRepository @@ -71,33 +71,33 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Build image id: build - uses: docker/build-push-action@v6 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: file: fabric-chaincode-docker/Dockerfile context: fabric-chaincode-docker @@ -110,7 +110,7 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: digest-${{ matrix.arch.platform }} path: ${{ runner.temp }}/digests/* @@ -131,20 +131,20 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: path: ${{ runner.temp }}/digests pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Docker metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 with: images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | @@ -152,7 +152,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Create and push manifest list working-directory: ${{ runner.temp }}/digests run: | diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index b0754fd5..fbd5b37e 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,17 +16,17 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-go@v5 # Needed for scanning of v2.5.5 and earlier + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 # Needed for scanning of v2.5.5 and earlier with: go-version: stable cache: false - - uses: actions/setup-java@v4 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d45c2a4..577227da 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,31 +16,31 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@v4 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@v4 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: temurin java-version: 21 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -66,13 +66,13 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@v4 + - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@v4 + - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From ffba62f78aa85f62361cd0bb996a635a2e6dc72f Mon Sep 17 00:00:00 2001 From: Thomas Leung <32366586+Thomas-Leung@users.noreply.github.com> Date: Wed, 23 Jul 2025 12:31:43 -0400 Subject: [PATCH 037/178] update commons-lang to 3.18 (#382) Signed-off-by: Thomas Leung Co-authored-by: Thomas Leung --- fabric-chaincode-shim/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index a361d7f1..0a4e9f42 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -30,6 +30,11 @@ tasks.withType(Test).configureEach { } dependencies { + constraints { + pmd('org.apache.commons:commons-lang3:3.18.0') { + because('CVE-2025-48924') + } + } implementation platform('com.google.protobuf:protobuf-bom:4.31.1') implementation platform('io.grpc:grpc-bom:1.73.0') implementation platform('io.opentelemetry:opentelemetry-bom:1.51.0') From 248f25200f2fcd622a6644f8376825aa0a3eedcc Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 28 Jul 2025 01:36:38 +0100 Subject: [PATCH 038/178] Enable dependabot dependency updates (#389) Configure dependabot for the following ecosystems: - docker - github-actions - gradle - maven Signed-off-by: Mark S. Lewis --- .github/dependabot.yml | 34 +++++++++++++++++++ .../build.gradle.kts | 2 +- .../fabric-contract-example-maven/pom.xml | 3 +- .../src/contracts/bare-gradle/build.gradle | 7 +--- .../src/contracts/bare-maven/pom.xml | 4 --- .../contracts/fabric-ledger-api/build.gradle | 7 +--- .../contracts/fabric-shim-api/build.gradle | 7 +--- 7 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..eb5341d0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +version: 2 +updates: + - package-ecosystem: docker + directories: + - "/fabric-chaincode-docker" + - "/examples/fabric-contract-example-as-service" + schedule: + interval: daily + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: daily + - package-ecosystem: gradle + directories: + - "/" + - "/fabric-chaincode-docker" + - "/examples/fabric-contract-example-as-service" + - "/examples/fabric-contract-example-gradle" + - "/examples/fabric-contract-example-gradle-kotlin" + - "/examples/ledger-api" + - "/fabric-chaincode-integration-test" + - "/fabric-chaincode-integration-test/src/contracts/bare-gradle" + - "/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api" + - "/fabric-chaincode-integration-test/src/contracts/fabric-shim-api" + - "/fabric-chaincode-shim" + schedule: + interval: daily + - package-ecosystem: maven + directories: + - "/examples/fabric-contract-example-maven" + - "/fabric-chaincode-integration-test/src/contracts/bare-maven" + - "/fabric-chaincode-integration-test/src/contracts/wrapper-maven" + schedule: + interval: daily diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index ffd88adc..f182c963 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.github.johnrengelman.shadow") version "8.1.1" + id("com.gradleup.shadow") version "8.3.6" id("org.jetbrains.kotlin.jvm") version "1.9.22" } diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 39f1e39d..4adbd9f1 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -111,8 +111,7 @@ maven-compiler-plugin 3.1 - ${java.version} - ${java.version} + ${java.version} diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 84e1f21a..4cdac1e7 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -6,13 +6,8 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - compileJava { - options.compilerArgs.addAll(['--release', '11']) + options.release = 11 } repositories { diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 2671d423..8a90c06d 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -21,10 +21,6 @@ jitpack.io https://www.jitpack.io - - artifactory - https://hyperledger.jfrog.io/hyperledger/fabric-maven - localfabirc file://${project.basedir}/repository diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index ab453cbe..8ae407d5 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -6,13 +6,8 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '' -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - compileJava { - options.compilerArgs.addAll(['--release', '11']) + options.release = 11 } repositories { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 7eee2b31..0c7ccc99 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -6,13 +6,8 @@ plugins { group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 -} - compileJava { - options.compilerArgs.addAll(['--release', '11']) + options.release = 11 } repositories { From 35edba3da3ed4151a53bc4e0c4a28cf6a44dc212 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:09:29 +0100 Subject: [PATCH 039/178] Bump junit.jupiter.version in /examples/fabric-contract-example-maven (#390) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 4adbd9f1..ca906e01 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -19,7 +19,7 @@ 1.7.5 - 5.13.1 + 5.13.4 1.13.1 From 438d9b400c6bff87713b41ecba4f651958a4aa4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:10:26 +0100 Subject: [PATCH 040/178] Bump org.apache.maven.plugins:maven-surefire-plugin (#392) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index ca906e01..541b73a8 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -105,7 +105,7 @@ maven-surefire-plugin - 2.22.0 + 3.5.3 maven-compiler-plugin From a8383c2bbba68e36ea58788b5682c590fa59135c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:11:01 +0100 Subject: [PATCH 041/178] Bump ch.qos.logback:logback-classic (#394) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 541b73a8..15ddcbf0 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.6 - 1.5.15 + 1.5.18 1.7.5 From 1a0de89fd39f05027bbe190a9489aec5315a1d2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:11:36 +0100 Subject: [PATCH 042/178] Bump org.jreleaser from 1.18.0 to 1.19.0 (#395) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 0a4e9f42..b7006080 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -7,7 +7,7 @@ plugins { id 'maven-publish' id 'signing' - id 'org.jreleaser' version '1.18.0' + id 'org.jreleaser' version '1.19.0' id 'jacoco' id 'pmd' } From 008a3b605846ed7b87648950b80d16ff4b7ac153 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:12:13 +0100 Subject: [PATCH 043/178] Bump io.opentelemetry:opentelemetry-bom from 1.51.0 to 1.52.0 (#396) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index b7006080..f230cdd6 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -37,7 +37,7 @@ dependencies { } implementation platform('com.google.protobuf:protobuf-bom:4.31.1') implementation platform('io.grpc:grpc-bom:1.73.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.51.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.52.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.81' From 287978557c1f5ac411b04db1b6f8865ab16713ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:12:48 +0100 Subject: [PATCH 044/178] Bump org.apache.maven.plugins:maven-shade-plugin (#397) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 15ddcbf0..6da4f9c7 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -117,7 +117,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.6.0 package From 2a208e34bff52d42a2d2df7e0d44d6ecaee0a0f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:20:06 +0100 Subject: [PATCH 045/178] Bump io.opentelemetry:opentelemetry-bom in /fabric-chaincode-shim (#406) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From a07c37cfbee17522accc8eb20803106c1dcf19ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:20:42 +0100 Subject: [PATCH 046/178] Bump org.apache.maven.plugins:maven-shade-plugin (#404) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/bare-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 8a90c06d..ae1f4205 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -51,7 +51,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.0 + 3.6.0 package From 13d4b31567fd6d7c1a6e21427b31e6510ab06095 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:21:14 +0100 Subject: [PATCH 047/178] Bump org.jreleaser from 1.18.0 to 1.19.0 in /fabric-chaincode-shim (#403) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 403d4962c54f89e990f489659e185ae8d939bc22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:22:00 +0100 Subject: [PATCH 048/178] Bump io.github.classgraph:classgraph in /fabric-chaincode-shim (#402) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index f230cdd6..877d1426 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -42,7 +42,7 @@ dependencies { implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.81' implementation 'org.bouncycastle:bcprov-jdk18on:1.81' - implementation 'io.github.classgraph:classgraph:4.8.179' + implementation 'io.github.classgraph:classgraph:4.8.181' implementation 'com.github.erosb:everit-json-schema:1.14.6' implementation 'org.json:json:20250517' implementation 'com.google.protobuf:protobuf-java-util' From 37196b2d4ab3198a89dda001bb8790240e3138f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:22:31 +0100 Subject: [PATCH 049/178] Bump io.opentelemetry.semconv:opentelemetry-semconv (#391) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 877d1426..fba78dcc 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -59,7 +59,7 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' - implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.32.0' + implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.34.0' implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.16.0-alpha' } From 5e4c2c1b4f7bf1572d8c13a16cf667459a38d990 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:23:31 +0100 Subject: [PATCH 050/178] Bump org.apache.maven.plugins:maven-shade-plugin (#400) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/wrapper-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 1f34fa68..ad5a9dee 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -55,7 +55,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.5.0 + 3.6.0 package From 894f25f3987437a986df3c4333a65494c7fed9ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:24:32 +0100 Subject: [PATCH 051/178] Bump io.opentelemetry.semconv:opentelemetry-semconv (#401) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 21e21e69bf47dae839c1a7821fd2a650f3b9dc08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:25:47 +0100 Subject: [PATCH 052/178] Bump io.github.classgraph:classgraph from 4.8.179 to 4.8.181 (#399) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 6ca405fd1074b6f0f81ca60babd289209db80255 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 12:05:34 +0100 Subject: [PATCH 053/178] Bump io.opentelemetry.instrumentation:opentelemetry-grpc-1.6 (#393) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index fba78dcc..c6f31c40 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -60,7 +60,7 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.34.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.16.0-alpha' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.18.1-alpha' } sourceSets { From 8e857ed3250d16ddf069d5063946d66d7b119fcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 11:11:00 +0000 Subject: [PATCH 054/178] Bump org.slf4j:slf4j-api in /examples/fabric-contract-example-maven (#398) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 6da4f9c7..677ef89f 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -16,7 +16,7 @@ 1.5.18 - 1.7.5 + 2.0.17 5.13.4 From bd2e78dc58ee21666215cdcaf4dd94fad2abc53a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:09:37 +0100 Subject: [PATCH 055/178] Bump org.apache.maven.plugins:maven-compiler-plugin (#407) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 677ef89f..28319bb3 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -109,7 +109,7 @@ maven-compiler-plugin - 3.1 + 3.14.0 ${java.version} From e1f3dd19edd3d13429e7eaef7f0f7661e4875cf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:10:03 +0100 Subject: [PATCH 056/178] Bump org.apache.maven.plugins:maven-compiler-plugin (#409) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/bare-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index ae1f4205..46c182fd 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -43,7 +43,7 @@ maven-compiler-plugin - 3.11.0 + 3.14.0 ${java.version} From c6bca45ea97b4fd72849f20f96c87bdf5a333d00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:10:36 +0100 Subject: [PATCH 057/178] Bump org.json:json in /examples/fabric-contract-example-maven (#408) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 28319bb3..9ba77c9a 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -95,7 +95,7 @@ org.json json - 20231013 + 20250517 From 037f305a2e3fb63e2218e2c7bd35d418e269c633 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:11:07 +0100 Subject: [PATCH 058/178] Bump org.apache.maven.plugins:maven-compiler-plugin (#410) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/wrapper-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index ad5a9dee..da29c9c4 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -47,7 +47,7 @@ maven-compiler-plugin - 3.11.0 + 3.14.0 ${java.version} From 6835f2379b618d75e6257e9de9879952255d108d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:29:04 +0100 Subject: [PATCH 059/178] Bump org.junit.jupiter:junit-jupiter (#413) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 67c0442a..babe9e3d 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.3' testImplementation 'org.mockito:mockito-core:5.18.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' From 3c23c3a5b3731ca2dfe4f6ac53ec75bc2ff0483f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:29:48 +0100 Subject: [PATCH 060/178] Bump com.diffplug.spotless from 7.0.4 to 7.2.1 (#411) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b605ec4f..43178dcb 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "com.github.ben-manes.versions" version "0.52.0" - id "com.diffplug.spotless" version "7.0.4" + id "com.diffplug.spotless" version "7.2.1" } version = '2.5.7' From 0adc54c53d1cbea24b2d3293b0d7a9add97ce3dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 18:30:17 +0100 Subject: [PATCH 061/178] Bump org.junit:junit-bom from 5.13.1 to 5.13.4 (#412) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 43178dcb..a96d39c2 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ subprojects { implementation 'commons-cli:commons-cli:1.9.0' implementation 'commons-logging:commons-logging:1.3.5' - testImplementation platform('org.junit:junit-bom:5.13.1') + testImplementation platform('org.junit:junit-bom:5.13.4') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.3' From 430225bb133ca7e84543f0001b74824b0e6eb026 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 23:01:38 +0100 Subject: [PATCH 062/178] Bump org.junit.jupiter:junit-jupiter (#415) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index f182c963..3feadab4 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.junit.jupiter:junit-jupiter:5.13.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.13.4") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0") } From 3fe5f1d4a5d0c227c6b91099afe7c67db5006f35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 23:04:11 +0100 Subject: [PATCH 063/178] Bump org.junit.jupiter:junit-jupiter in /examples/ledger-api (#416) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/ledger-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 3b01193c..376969f6 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.3' testImplementation 'org.mockito:mockito-core:5.18.0' } From 9113a5adaa28fdd547a1e7d7fbe01be3695c41dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 10:19:23 +0100 Subject: [PATCH 064/178] Bump org.junit.jupiter:junit-jupiter (#414) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 6194c73e..97742d90 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.1' + testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.3' testImplementation 'org.mockito:mockito-core:5.18.0' } From 494a6899c1d5d769e5ef4a8ad6302079f3060ffd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 09:19:30 +0000 Subject: [PATCH 065/178] Bump io.grpc:grpc-bom from 1.73.0 to 1.74.0 (#417) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index c6f31c40..556df472 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -36,7 +36,7 @@ dependencies { } } implementation platform('com.google.protobuf:protobuf-bom:4.31.1') - implementation platform('io.grpc:grpc-bom:1.73.0') + implementation platform('io.grpc:grpc-bom:1.74.0') implementation platform('io.opentelemetry:opentelemetry-bom:1.52.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' From b7e60120061fc9fc49b6fb8844bceed8bc461933 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:08:45 +0100 Subject: [PATCH 066/178] Bump com.gradleup.shadow in /examples/fabric-contract-example-gradle (#419) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 97742d90..c9f95829 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From 147241593ddaebf71ab7476bea0177caf8739719 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 11:18:25 +0100 Subject: [PATCH 067/178] Bump com.gradleup.shadow in /examples/fabric-contract-example-as-service (#418) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index babe9e3d..a8c92c9a 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From adebb7665ef4166dd50c8d5d609729d7f5b38568 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 12:10:43 +0100 Subject: [PATCH 068/178] Bump org.jetbrains.kotlin.jvm (#420) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 3feadab4..a9757930 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -6,7 +6,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id("com.gradleup.shadow") version "8.3.6" - id("org.jetbrains.kotlin.jvm") version "1.9.22" + id("org.jetbrains.kotlin.jvm") version "2.2.0" } From 5f0bb4cb0335190067242807486ed20cc6717192 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:30:43 +0100 Subject: [PATCH 069/178] Bump com.gradleup.shadow (#425) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 0c7ccc99..ec21dd7e 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From 1b14876a53d4acb4c4ea7e5588c51c17efc527b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:31:21 +0100 Subject: [PATCH 070/178] Bump com.gradleup.shadow (#424) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 8ae407d5..39da6710 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From e3bc3ee05b78718b911071337f4d8cfbec760cc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:31:57 +0100 Subject: [PATCH 071/178] Bump com.gradleup.shadow (#423) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../src/contracts/bare-gradle/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 4cdac1e7..d704e1b0 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From 07d9951de4efef6eb749c88eda8aaf2a725a7354 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 15:32:28 +0100 Subject: [PATCH 072/178] Bump com.gradleup.shadow from 8.3.6 to 8.3.8 in /examples/ledger-api (#422) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/ledger-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 376969f6..c25a8f48 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.6' + id 'com.gradleup.shadow' version '8.3.8' id 'java' } From afc96523a41bc1175695bc4b05e08251f7430097 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:39:50 +0000 Subject: [PATCH 073/178] Bump com.gradleup.shadow (#421) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index a9757930..0cc3b430 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "8.3.6" + id("com.gradleup.shadow") version "8.3.8" id("org.jetbrains.kotlin.jvm") version "2.2.0" } From 0c11edebf0ec5f455dd7c2429807840c207bd1ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 09:04:55 +0000 Subject: [PATCH 074/178] Bump com.nhaarman.mockitokotlin2:mockito-kotlin (#428) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 0cc3b430..30f47c9d 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.junit.jupiter:junit-jupiter:5.13.4") - testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0") + testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") } repositories { From 15cf83b4e223127a856256f6858d6664bb3a39f1 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 5 Aug 2025 23:11:57 +0200 Subject: [PATCH 075/178] Group Java dapendabot updates in single PR (#427) Individual dependabot updates across multiple directories and ecosystems (Gradle and Maven) require too much PR maintenance and place a high load on the build system. This change groups all Java updates in a single PR. Signed-off-by: Mark S. Lewis --- .github/dependabot.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index eb5341d0..31ffcd8e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,4 +1,10 @@ version: 2 + +multi-ecosystem-groups: + java: + schedule: + interval: daily + updates: - package-ecosystem: docker directories: @@ -6,11 +12,16 @@ updates: - "/examples/fabric-contract-example-as-service" schedule: interval: daily + - package-ecosystem: "github-actions" directory: "/" schedule: interval: daily + - package-ecosystem: gradle + multi-ecosystem-group: java + patterns: + - "*" directories: - "/" - "/fabric-chaincode-docker" @@ -23,12 +34,12 @@ updates: - "/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api" - "/fabric-chaincode-integration-test/src/contracts/fabric-shim-api" - "/fabric-chaincode-shim" - schedule: - interval: daily + - package-ecosystem: maven + multi-ecosystem-group: java + patterns: + - "*" directories: - "/examples/fabric-contract-example-maven" - "/fabric-chaincode-integration-test/src/contracts/bare-maven" - "/fabric-chaincode-integration-test/src/contracts/wrapper-maven" - schedule: - interval: daily From e458182eba4a5cd6e46210af20028efb0f24b33e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 23:13:33 +0200 Subject: [PATCH 076/178] Bump docker/login-action from 3.4.0 to 3.5.0 (#429) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b2ae89d..e7bde24b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,13 +82,13 @@ jobs: - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -137,7 +137,7 @@ jobs: pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} From 6991fa26b1e9c418964654b8779c49f4c1917731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 23:14:54 +0200 Subject: [PATCH 077/178] Bump docker/metadata-action from 5.7.0 to 5.8.0 (#435) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7bde24b..c9fc27f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -144,7 +144,7 @@ jobs: password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Docker metadata id: meta - uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 + uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 with: images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | From 58651ac767f93089699eb43e7a80edbf67d1c3da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 21:19:32 +0000 Subject: [PATCH 078/178] Bump gradle/actions from 4.4.1 to 4.4.2 (#439) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9fc27f1..5b7587c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Publish to Maven Central run: | ./gradlew publishAllPublicationsToStagingRepository @@ -76,7 +76,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index fbd5b37e..a0c1adc0 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -27,6 +27,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 577227da..a72c7e3f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 02a85cdb1706d27145e9081539f3c8ffac0a9968 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 23:20:52 +0200 Subject: [PATCH 079/178] Bump the java group across 8 directories with 2 updates (#440) - Updates `commons-cli:commons-cli` from 1.9.0 to 1.10.0 - Updates `com.gradleup.shadow` from 8.3.8 to 8.3.9 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index a96d39c2..260241a2 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ subprojects { } dependencies { - implementation 'commons-cli:commons-cli:1.9.0' + implementation 'commons-cli:commons-cli:1.10.0' implementation 'commons-logging:commons-logging:1.3.5' testImplementation platform('org.junit:junit-bom:5.13.4') diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index a8c92c9a..3a0b1881 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 30f47c9d..93885a22 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "8.3.8" + id("com.gradleup.shadow") version "8.3.9" id("org.jetbrains.kotlin.jvm") version "2.2.0" } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index c9f95829..8824efca 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index c25a8f48..bef46101 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index d704e1b0..7f8d4d77 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 39da6710..c04fb9e7 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index ec21dd7e..a920b165 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.8' + id 'com.gradleup.shadow' version '8.3.9' id 'java' } From 5e753de6546c61ac7a57275fe5fd526c956beb3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 10:11:40 +0200 Subject: [PATCH 080/178] Bump gradle in /examples/fabric-contract-example-as-service (#441) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-as-service/Dockerfile b/examples/fabric-contract-example-as-service/Dockerfile index 8e21e344..39ff1e6c 100644 --- a/examples/fabric-contract-example-as-service/Dockerfile +++ b/examples/fabric-contract-example-as-service/Dockerfile @@ -4,7 +4,7 @@ # Example multi-stage dockerfile for Java Chaincode # the first stage -FROM gradle:8-jdk21 AS gradle_build +FROM gradle:9-jdk21 AS gradle_build # copy the build.gradle and src code to the container COPY src/ src/ From ae334d052a3e1f142f17c3e7942b95a19562f912 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Aug 2025 10:49:24 +0200 Subject: [PATCH 081/178] Bump actions/download-artifact from 4.3.0 to 5.0.0 (#442) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5b7587c0..c56cb12a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -131,7 +131,7 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: path: ${{ runner.temp }}/digests pattern: digest-* From 3ccd64d288c3c03662f2bd1856065df43f06433c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 09:28:15 +0000 Subject: [PATCH 082/178] Updates com.gradleup.shadow from 8.3.9 to 9.0.0 (#443) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 3a0b1881..0b4e270b 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 93885a22..c549dd66 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "8.3.9" + id("com.gradleup.shadow") version "9.0.0" id("org.jetbrains.kotlin.jvm") version "2.2.0" } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 8824efca..1b417ef8 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index bef46101..3b8e2639 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 7f8d4d77..a4586895 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index c04fb9e7..7c974b86 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index a920b165..00910f5f 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '8.3.9' + id 'com.gradleup.shadow' version '9.0.0' id 'java' } From 6b954370df2d6b653a92debb001a1170af9005a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:27:44 +0200 Subject: [PATCH 083/178] Update assertj-core from 3.27.3 to 3.27.4 (#444) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 260241a2..914dde65 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ subprojects { testImplementation platform('org.junit:junit-bom:5.13.4') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.assertj:assertj-core:3.27.4' testImplementation 'org.mockito:mockito-core:5.18.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 0b4e270b..24d5eb81 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.assertj:assertj-core:3.27.4' testImplementation 'org.mockito:mockito-core:5.18.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 1b417ef8..1a8b41c1 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.assertj:assertj-core:3.27.4' testImplementation 'org.mockito:mockito-core:5.18.0' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 3b8e2639..38db2cc3 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.3' + testImplementation 'org.assertj:assertj-core:3.27.4' testImplementation 'org.mockito:mockito-core:5.18.0' } From 4be04decba9f1af8de9012c42a8f01d46ca987d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:07:18 +0000 Subject: [PATCH 084/178] Bump actions/checkout from 4.2.2 to 5.0.0 (#446) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c56cb12a..34449620 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" @@ -40,7 +40,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" @@ -71,7 +71,7 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "temurin" diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index a0c1adc0..61179e4d 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,7 +16,7 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 # Needed for scanning of v2.5.5 and earlier diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a72c7e3f..45fe9824 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 @@ -30,7 +30,7 @@ jobs: intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 @@ -66,7 +66,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 From 72dda51c6468ccb80c8aefad9dc78a496e4eabc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 11:57:51 +0200 Subject: [PATCH 085/178] Bump org.mockito:mockito-core (#447) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 9ba77c9a..f79dcc46 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -88,7 +88,7 @@ org.mockito mockito-core - 5.18.0 + 5.19.0 From 26d150e9864a3fa64c49de0bb82f0a6fb820c395 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:37:12 +0200 Subject: [PATCH 086/178] Bump actions/setup-java from 4.7.1 to 5.0.0 (#448) Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.1 to 5.0.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/c5195efecf7bdfc987ee8bae7a71cb8b11521c00...dded0888837ed1f317902acf8a20df0ad188d165) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 34449620..20aedd8d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: packages: write steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" java-version: 21 @@ -41,7 +41,7 @@ jobs: contents: read steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" java-version: 21 @@ -72,7 +72,7 @@ jobs: runner: ubuntu-24.04-arm steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" java-version: 21 diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 61179e4d..329193a8 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -23,7 +23,7 @@ jobs: with: go-version: stable cache: false - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin java-version: 21 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45fe9824..73056be2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin java-version: 21 @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin java-version: 21 @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin java-version: 21 From 358deda58aa609d6ba0bf2f394860d960ba67236 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:14:49 +0100 Subject: [PATCH 087/178] Bump actions/setup-node from 4.4.0 to 5.0.0 (#449) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73056be2..eac7d223 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 21 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 From 2942c2d629b28b37b8644e32fb9024d1231ccbd2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 15:38:25 +0100 Subject: [PATCH 088/178] Bump actions/setup-go from 5.5.0 to 6.0.0 (#450) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mark S. Lewis --- .github/workflows/scan.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 329193a8..142f2eb5 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,17 +16,18 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ inputs.ref }} - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 # Needed for scanning of v2.5.5 and earlier + # Go needed for scanning of v2.5.5 and earlier + - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: stable cache: false - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 - name: Scan run: make scan From 021878b67953e878b740ea0b68e05ef9f150a6d0 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 8 Sep 2025 15:11:12 +0100 Subject: [PATCH 089/178] Bump Gradle shadow plugin to v9.1.0 (#451) Signed-off-by: Mark S. Lewis --- examples/fabric-contract-example-as-service/build.gradle | 3 ++- .../fabric-contract-example-gradle-kotlin/build.gradle.kts | 3 ++- examples/fabric-contract-example-gradle/build.gradle | 3 ++- examples/ledger-api/build.gradle | 3 ++- .../src/contracts/bare-gradle/build.gradle | 3 ++- .../src/contracts/fabric-ledger-api/build.gradle | 3 ++- .../src/contracts/fabric-shim-api/build.gradle | 3 ++- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 24d5eb81..072ec540 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -25,6 +25,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index c549dd66..572156e5 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "9.0.0" + id("com.gradleup.shadow") version "9.1.0" id("org.jetbrains.kotlin.jvm") version "2.2.0" } @@ -34,6 +34,7 @@ tasks { archiveBaseName = "chaincode" archiveVersion = "" archiveClassifier = "" + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { attributes(mapOf("Main-Class" to "org.hyperledger.fabric.contract.ContractRouter")) diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 1a8b41c1..64736e46 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -24,6 +24,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 38db2cc3..4487618a 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -24,6 +24,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index a4586895..17d13b56 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -26,6 +26,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 7c974b86..051f2401 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -26,6 +26,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 00910f5f..aaafd27b 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.0.0' + id 'com.gradleup.shadow' version '9.1.0' id 'java' } @@ -28,6 +28,7 @@ shadowJar { archiveBaseName = 'chaincode' archiveVersion = '' archiveClassifier = '' + duplicatesStrategy = DuplicatesStrategy.INCLUDE mergeServiceFiles() manifest { From 54854e51d88a5983796f378a27231cd836eb1807 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:39:19 +0100 Subject: [PATCH 090/178] Bump gradle/actions from 4.4.2 to 4.4.3 (#452) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20aedd8d..e4c1b63b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Publish to Maven Central run: | ./gradlew publishAllPublicationsToStagingRepository @@ -76,7 +76,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 142f2eb5..4946d9f2 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -28,6 +28,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eac7d223..64dd9c2d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@017a9effdb900e5b5b2fddfb590a105619dca3c3 # v4.4.2 + - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 7cae1fa56a030ae6088fa83b43f76407e77b29f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:58:40 +0100 Subject: [PATCH 091/178] Bump Maven dependencies (#453) - Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.3 to 3.5.4 - Updates `org.apache.maven.plugins:maven-shade-plugin` from 3.6.0 to 3.6.1 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 4 ++-- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index f79dcc46..bd4938f4 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -105,7 +105,7 @@ maven-surefire-plugin - 3.5.3 + 3.5.4 maven-compiler-plugin @@ -117,7 +117,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 package diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 46c182fd..538f171c 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -51,7 +51,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 package diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index da29c9c4..2baa856f 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -55,7 +55,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.0 + 3.6.1 package From 3e4001a4123d2ee537bf3f9f528cb6bf404257d6 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 15 Sep 2025 17:26:12 +0100 Subject: [PATCH 092/178] Update dependencies (#454) - Protobuf - gRPC - OpenTelemetry - Gradle - Maven Signed-off-by: Mark S. Lewis --- build.gradle | 2 +- .../build.gradle | 2 +- .../build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-docker/Dockerfile | 4 +-- .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../src/contracts/fabric-ledger-api/gradlew | 7 ++-- .../contracts/fabric-ledger-api/gradlew.bat | 2 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43764 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../src/contracts/fabric-shim-api/gradlew | 12 ++++--- .../src/contracts/fabric-shim-api/gradlew.bat | 6 ++-- .../.mvn/wrapper/maven-wrapper.jar | Bin 63028 -> 63093 bytes .../.mvn/wrapper/maven-wrapper.properties | 22 ++----------- .../src/contracts/wrapper-maven/mvnw | 30 +++++++++++------- .../src/contracts/wrapper-maven/mvnw.cmd | 6 ++-- fabric-chaincode-shim/build.gradle | 14 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- 19 files changed, 58 insertions(+), 59 deletions(-) diff --git a/build.gradle b/build.gradle index 914dde65..35bdc14b 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ subprojects { testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.4' - testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'org.mockito:mockito-core:5.19.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' testImplementation 'org.hamcrest:hamcrest-library:3.0' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 072ec540..2f4c5e97 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.4' - testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'org.mockito:mockito-core:5.19.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 64736e46..bfebe01c 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.4' - testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'org.mockito:mockito-core:5.19.0' } shadowJar { diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 4487618a..ad54d1d7 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.4' - testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'org.mockito:mockito-core:5.19.0' } shadowJar { diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index eeaf4303..894b6494 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -13,8 +13,8 @@ RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] RUN source /root/.sdkman/bin/sdkman-init.sh \ - && sdk install gradle 8.14.2 \ - && sdk install maven 3.9.10 + && sdk install gradle 8.14.3 \ + && sdk install maven 3.9.11 FROM ${JAVA_IMAGE} AS dependencies diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 34592 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 delta 34555 zcmX7vV`H6d(}mmEwr$(CZQE$vU^m*aZQE(=WXEZ2+l}qF_w)XN>&rEBu9;)4>0JOD zo(HR^Mh47P)@z^^pH!4#b(O8!;$>N+S+v5K5f8RrQ+Qv0_oH#e!pI2>yt4ij>fI9l zW&-hsVAQg%dpn3NRy$kb_vbM2sr`>bZ48b35m{D=OqX;p8A${^Dp|W&J5mXvUl#_I zN!~GCBUzj~C%K?<7+UZ_q|L)EGG#_*2Zzko-&Kck)Qd2%CpS3{P1co1?$|Sj1?E;PO z7alI9$X(MDly9AIEZ-vDLhpAKd1x4U#w$OvBtaA{fW9)iD#|AkMrsSaNz(69;h1iM1#_ z?u?O_aKa>vk=j;AR&*V-p3SY`CI}Uo%eRO(Dr-Te<99WQhi>y&l%UiS%W2m(d#woD zW?alFl75!1NiUzVqgqY98fSQNjhX3uZ&orB08Y*DFD;sjIddWoJF;S_@{Lx#SQk+9 zvSQ-620z0D7cy8-u_7u?PqYt?R0m2k%PWj%V(L|MCO(@3%l&pzEy7ijNv(VXU9byn z@6=4zL|qk*7!@QWd9imT9i%y}1#6+%w=s%WmsHbw@{UVc^?nL*GsnACaLnTbr9A>B zK)H-$tB`>jt9LSwaY+4!F1q(YO!E7@?SX3X-Ug4r($QrmJnM8m#;#LN`kE>?<{vbCZbhKOrMpux zTU=02hy${;n&ikcP8PqufhT9nJU>s;dyl;&~|Cs+o{9pCu{cRF+0{iyuH~6=tIZXVd zR~pJBC3Hf-g%Y|bhTuGyd~3-sm}kaX5=T?p$V?48h4{h2;_u{b}8s~Jar{39PnL7DsXpxcX#3zx@f9K zkkrw9s2*>)&=fLY{=xeIYVICff2Id5cc*~l7ztSsU@xuXYdV1(lLGZ5)?mXyIDf1- zA7j3P{C5s?$Y-kg60&XML*y93zrir8CNq*EMx)Kw)XA(N({9t-XAdX;rjxk`OF%4-0x?ne@LlBQMJe5+$Ir{Oj`@#qe+_-z!g5qQ2SxKQy1ex_x^Huj%u+S@EfEPP-70KeL@7@PBfadCUBt%`huTknOCj{ z;v?wZ2&wsL@-iBa(iFd)7duJTY8z-q5^HR-R9d*ex2m^A-~uCvz9B-1C$2xXL#>ow z!O<5&jhbM&@m=l_aW3F>vjJyy27gY}!9PSU3kITbrbs#Gm0gD?~Tub8ZFFK$X?pdv-%EeopaGB#$rDQHELW!8bVt`%?&>0 zrZUQ0!yP(uzVK?jWJ8^n915hO$v1SLV_&$-2y(iDIg}GDFRo!JzQF#gJoWu^UW0#? z*OC-SPMEY!LYYLJM*(Qov{#-t!3Z!CfomqgzFJld>~CTFKGcr^sUai5s-y^vI5K={ z)cmQthQuKS07e8nLfaIYQ5f}PJQqcmokx?%yzFH*`%k}RyXCt1Chfv5KAeMWbq^2MNft;@`hMyhWg50(!jdAn;Jyx4Yt)^^DVCSu?xRu^$*&&=O6#JVShU_N3?D)|$5pyP8A!f)`| z>t0k&S66T*es5(_cs>0F=twYJUrQMqYa2HQvy)d+XW&rai?m;8nW9tL9Ivp9qi2-` zOQM<}D*g`28wJ54H~1U!+)vQh)(cpuf^&8uteU$G{9BUhOL| zBX{5E1**;hlc0ZAi(r@)IK{Y*ro_UL8Ztf8n{Xnwn=s=qH;fxkK+uL zY)0pvf6-iHfX+{F8&6LzG;&d%^5g`_&GEEx0GU=cJM*}RecV-AqHSK@{TMir1jaFf&R{@?|ieOUnmb?lQxCN!GnAqcii9$ z{a!Y{Vfz)xD!m2VfPH=`bk5m6dG{LfgtA4ITT?Sckn<92rt@pG+sk>3UhTQx9ywF3 z=%B0LZN<=6-B4+UbYWxfQUOe8cmEDY3QL$;mOw&X2;q9x9qNz3J97)3^jb zdlzkDYLKm^5?3IV>t3fdWwNpq3qY;hsj=pk9;P!wVmjP|6Dw^ez7_&DH9X33$T=Q{>Nl zv*a*QMM1-2XQ)O=3n@X+RO~S`N13QM81^ZzljPJIFBh%x<~No?@z_&LAl)ap!AflS zb{yFXU(Uw(dw%NR_l7%eN2VVX;^Ln{I1G+yPQr1AY+0MapBnJ3k1>Zdrw^3aUig*! z?xQe8C0LW;EDY(qe_P!Z#Q^jP3u$Z3hQpy^w7?jI;~XTz0ju$DQNc4LUyX}+S5zh> zGkB%~XU+L?3pw&j!i|x6C+RyP+_XYNm9`rtHpqxvoCdV_MXg847oHhYJqO+{t!xxdbsw4Ugn($Cwkm^+36&goy$vkaFs zrH6F29eMPXyoBha7X^b+N*a!>VZ<&Gf3eeE+Bgz7PB-6X7 z_%2M~{sTwC^iQVjH9#fVa3IO6E4b*S%M;#WhHa^L+=DP%arD_`eW5G0<9Tk=Ci?P@ z6tJXhej{ZWF=idj32x7dp{zmQY;;D2*11&-(~wifGXLmD6C-XR=K3c>S^_+x!3OuB z%D&!EOk;V4Sq6eQcE{UEDsPMtED*;qgcJU^UwLwjE-Ww54d73fQ`9Sv%^H>juEKmxN+*aD=0Q+ZFH1_J(*$~9&JyUJ6!>(Nj zi3Z6zWC%Yz0ZjX>thi~rH+lqv<9nkI3?Ghn7@!u3Ef){G(0Pvwnxc&(YeC=Kg2-7z zr>a^@b_QClXs?Obplq@Lq-l5>W);Y^JbCYk^n8G`8PzCH^rnY5Zk-AN6|7Pn=oF(H zxE#8LkI;;}K7I^UK55Z)c=zn7OX_XVgFlEGSO}~H^y|wd7piw*b1$kA!0*X*DQ~O` z*vFvc5Jy7(fFMRq>XA8Tq`E>EF35{?(_;yAdbO8rrmrlb&LceV%;U3haVV}Koh9C| zTZnR0a(*yN^Hp9u*h+eAdn)d}vPCo3k?GCz1w>OOeme(Mbo*A7)*nEmmUt?eN_vA; z=~2}K_}BtDXJM-y5fn^v>QQo+%*FdZQFNz^j&rYhmZHgDA-TH47#Wjn_@iH4?6R{J z%+C8LYIy>{3~A@|y4kN8YZZp72F8F@dOZWp>N0-DyVb4UQd_t^`P)zsCoygL_>>x| z2Hyu7;n(4G&?wCB4YVUIVg0K!CALjRsb}&4aLS|}0t`C}orYqhFe7N~h9XQ_bIW*f zGlDCIE`&wwyFX1U>}g#P0xRRn2q9%FPRfm{-M7;}6cS(V6;kn@6!$y06lO>8AE_!O z{|W{HEAbI0eD$z9tQvWth7y>qpTKQ0$EDsJkQxAaV2+gE28Al8W%t`Pbh zPl#%_S@a^6Y;lH6BfUfZNRKwS#x_keQ`;Rjg@qj zZRwQXZd-rWngbYC}r6X)VCJ-=D54A+81%(L*8?+&r7(wOxDSNn!t(U}!;5|sjq zc5yF5$V!;%C#T+T3*AD+A({T)#p$H_<$nDd#M)KOLbd*KoW~9E19BBd-UwBX1<0h9 z8lNI&7Z_r4bx;`%5&;ky+y7PD9F^;Qk{`J@z!jJKyJ|s@lY^y!r9p^75D)_TJ6S*T zLA7AA*m}Y|5~)-`cyB+lUE9CS_`iB;MM&0fX**f;$n($fQ1_Zo=u>|n~r$HvkOUK(gv_L&@DE0b4#ya{HN)8bNQMl9hCva zi~j0v&plRsp?_zR zA}uI4n;^_Ko5`N-HCw_1BMLd#OAmmIY#ol4M^UjLL-UAat+xA+zxrFqKc@V5Zqan_ z+LoVX-Ub2mT7Dk_ z<+_3?XWBEM84@J_F}FDe-hl@}x@v-s1AR{_YD!_fMgagH6s9uyi6pW3gdhauG>+H? zi<5^{dp*5-9v`|m*ceT&`Hqv77oBQ+Da!=?dDO&9jo;=JkzrQKx^o$RqAgzL{ zjK@n)JW~lzxB>(o(21ibI}i|r3e;17zTjdEl5c`Cn-KAlR7EPp84M@!8~CywES-`mxKJ@Dsf6B18_!XMIq$Q3rTDeIgJ3X zB1)voa#V{iY^ju>*Cdg&UCbx?d3UMArPRHZauE}c@Fdk;z85OcA&Th>ZN%}=VU%3b9={Q(@M4QaeuGE(BbZ{U z?WPDG+sjJSz1OYFpdImKYHUa@ELn%n&PR9&I7B$<-c3e|{tPH*u@hs)Ci>Z@5$M?lP(#d#QIz}~()P7mt`<2PT4oHH}R&#dIx4uq943D8gVbaa2&FygrSk3*whGr~Jn zR4QnS@83UZ_BUGw;?@T zo5jA#potERcBv+dd8V$xTh)COur`TQ^^Yb&cdBcesjHlA3O8SBeKrVj!-D3+_p6%P zP@e{|^-G-C(}g+=bAuAy8)wcS{$XB?I=|r=&=TvbqeyXiuG43RR>R72Ry7d6RS;n^ zO5J-QIc@)sz_l6%Lg5zA8cgNK^GK_b-Z+M{RLYk5=O|6c%!1u6YMm3jJg{TfS*L%2 zA<*7$@wgJ(M*gyTzz8+7{iRP_e~(CCbGB}FN-#`&1ntct@`5gB-u6oUp3#QDxyF8v zOjxr}pS{5RpK1l7+l(bC)0>M;%7L?@6t}S&a zx0gP8^sXi(g2_g8+8-1~hKO;9Nn%_S%9djd*;nCLadHpVx(S0tixw2{Q}vOPCWvZg zjYc6LQ~nIZ*b0m_uN~l{&2df2*ZmBU8dv`#o+^5p>D5l%9@(Y-g%`|$%nQ|SSRm0c zLZV)45DS8d#v(z6gj&6|ay@MP23leodS8-GWIMH8_YCScX#Xr)mbuvXqSHo*)cY9g z#Ea+NvHIA)@`L+)T|f$Etx;-vrE3;Gk^O@IN@1{lpg&XzU5Eh3!w;6l=Q$k|%7nj^ z|HGu}c59-Ilzu^w<93il$cRf@C(4Cr2S!!E&7#)GgUH@py?O;Vl&joXrep=2A|3Vn zH+e$Ctmdy3B^fh%12D$nQk^j|v=>_3JAdKPt2YVusbNW&CL?M*?`K1mK*!&-9Ecp~>V1w{EK(429OT>DJAV21fG z=XP=%m+0vV4LdIi#(~XpaUY$~fQ=xA#5?V%xGRr_|5WWV=uoG_Z&{fae)`2~u{6-p zG>E>8j({w7njU-5Lai|2HhDPntQ(X@yB z9l?NGoKB5N98fWrkdN3g8ox7Vic|gfTF~jIfXkm|9Yuu-p>v3d{5&hC+ZD%mh|_=* zD5v*u(SuLxzX~owH!mJQi%Z=ALvdjyt9U6baVY<88B>{HApAJ~>`buHVGQd%KUu(d z5#{NEKk6Vy08_8*E(?hqZe2L?P2$>!0~26N(rVzB9KbF&JQOIaU{SumX!TsYzR%wB z<5EgJXDJ=1L_SNCNZcBWBNeN+Y`)B%R(wEA?}Wi@mp(jcw9&^1EMSM58?68gwnXF` zzT0_7>)ep%6hid-*DZ42eU)tFcFz7@bo=<~CrLXpNDM}tv*-B(ZF`(9^RiM9W4xC%@ZHv=>w(&~$Wta%)Z;d!{J;e@z zX1Gkw^XrHOfYHR#hAU=G`v43E$Iq}*gwqm@-mPac0HOZ0 zVtfu7>CQYS_F@n6n#CGcC5R%4{+P4m7uVlg3axX}B(_kf((>W?EhIO&rQ{iUO$16X zv{Abj3ZApUrcar7Ck}B1%RvnR%uocMlKsRxV9Qqe^Y_5C$xQW@9QdCcF%W#!zj;!xWc+0#VQ*}u&rJ7)zc+{vpw+nV?{tdd&Xs`NV zKUp|dV98WbWl*_MoyzM0xv8tTNJChwifP!9WM^GD|Mkc75$F;j$K%Y8K@7?uJjq-w zz*|>EH5jH&oTKlIzueAN2926Uo1OryC|CmkyoQZABt#FtHz)QmQvSX35o`f z<^*5XXxexj+Q-a#2h4(?_*|!5Pjph@?Na8Z>K%AAjNr3T!7RN;7c)1SqAJfHY|xAV z1f;p%lSdE8I}E4~tRH(l*rK?OZ>mB4C{3e%E-bUng2ymerg8?M$rXC!D?3O}_mka? zm*Y~JMu+_F7O4T;#nFv)?Ru6 z92r|old*4ZB$*6M40B;V&2w->#>4DEu0;#vHSgXdEzm{+VS48 z7U1tVn#AnQ3z#gP26$!dmS5&JsXsrR>~rWA}%qd{92+j zu+wYAqrJYOA%WC9nZ>BKH&;9vMSW_59z5LtzS4Q@o5vcrWjg+28#&$*8SMYP z!l5=|p@x6YnmNq>23sQ(^du5K)TB&K8t{P`@T4J5cEFL@qwtsCmn~p>>*b=37y!kB zn6x{#KjM{S9O_otGQub*K)iIjtE2NfiV~zD2x{4r)IUD(Y8%r`n;#)ujIrl8Sa+L{ z>ixGoZJ1K@;wTUbRRFgnltN_U*^EOJS zRo4Y+S`cP}e-zNtdl^S5#%oN#HLjmq$W^(Y6=5tM#RBK-M14RO7X(8Gliy3+&9fO; zXn{60%0sWh1_g1Z2r0MuGwSGUE;l4TI*M!$5dm&v9pO7@KlW@j_QboeDd1k9!7S)jIwBza-V#1)(7ht|sjY}a19sO!T z2VEW7nB0!zP=Sx17-6S$r=A)MZikCjlQHE)%_Ka|OY4+jgGOw=I3CM`3ui^=o0p7u z?xujpg#dRVZCg|{%!^DvoR*~;QBH8ia6%4pOh<#t+e_u!8gjuk_Aic=|*H24Yq~Wup1dTRQs0nlZOy+30f16;f7EYh*^*i9hTZ`h`015%{i|4 z?$7qC3&kt#(jI#<76Biz=bl=k=&qyaH>foM#zA7}N`Ji~)-f-t&tR4^do)-5t?Hz_Q+X~S2bZx{t+MEjwy3kGfbv(ij^@;=?H_^FIIu*HP_7mpV)NS{MY-Rr7&rvWo@Wd~{Lt!8|66rq`GdGu% z@<(<7bYcZKCt%_RmTpAjx=TNvdh+ZiLkMN+hT;=tC?%vQQGc7WrCPIYZwYTW`;x|N zrlEz1yf95FiloUU^(onr3A3>+96;;6aL?($@!JwiQ2hO|^i)b4pCJ7-y&a~B#J`#FO!3uBp{5GG*Cni@K85&o0q~6#LtppE&cVY z3Bv{xQ-;i}LN-60B2*1suMd=Fi%Y|7@52axZ|b=Wiwk^5eg{9X4}(q%4D5N5_Gm)` zg~VyFCwfkIKW(@@ZGAlTra6CO$RA_b*yz#){B82N7AYpQ9)sLQfhOAOMUV7$0|d$=_y&jl>va$3u-H z_+H*|UXBPLe%N2Ukwu1*)kt!$Y>(IH3`YbEt; znb1uB*{UgwG{pQnh>h@vyCE!6B~!k}NxEai#iY{$!_w54s5!6jG9%pr=S~3Km^EEA z)sCnnau+ZY)(}IK#(3jGGADw8V7#v~<&y5cF=5_Ypkrs3&7{}%(4KM7) zuSHVqo~g#1kzNwXc39%hL8atpa1Wd#V^uL=W^&E)fvGivt)B!M)?)Y#Ze&zU6O_I?1wj)*M;b*dE zqlcwgX#eVuZj2GKgBu@QB(#LHMd`qk<08i$hG1@g1;zD*#(9PHjVWl*5!;ER{Q#A9 zyQ%fu<$U?dOW=&_#~{nrq{RRyD8upRi}c-m!n)DZw9P>WGs>o1vefI}ujt_`O@l#Z z%xnOt4&e}LlM1-0*dd?|EvrAO-$fX8i{aTP^2wsmSDd!Xc9DxJB=x1}6|yM~QQPbl z0xrJcQNtWHgt*MdGmtj%x6SWYd?uGnrx4{m{6A9bYx`m z$*UAs@9?3s;@Jl19%$!3TxPlCkawEk12FADYJClt0N@O@Pxxhj+Kk(1jK~laR0*KGAc7%C4nI^v2NShTc4#?!p{0@p0T#HSIRndH;#Ts0YECtlSR}~{Uck+keoJq6iH)(Zc~C!fBe2~4(Wd> zR<4I1zMeW$<0xww(@09!l?;oDiq zk8qjS9Lxv$<5m#j(?4VLDgLz;8b$B%XO|9i7^1M;V{aGC#JT)c+L=BgCfO5k>CTlI zOlf~DzcopV29Dajzt*OcYvaUH{UJPaD$;spv%>{y8goE+bDD$~HQbON>W*~JD`;`- zZEcCPSdlCvANe z=?|+e{6AW$f(H;BND>uy1MvQ`pri>SafK5bK!YAE>0URAW9RS8#LWUHBOc&BNQ9T+ zJpg~Eky!u!9WBk)!$Z?!^3M~o_VPERYnk1NmzVYaGH;1h+;st==-;jzF~2LTn+x*k zvywHZg7~=aiJe=OhS@U>1fYGvT1+jsAaiaM;) zay2xsMKhO+FIeK?|K{G4SJOEt*eX?!>K8jpsZWW8c!X|JR#v(1+Ey5NM^TB1n|_40 z@Db2gH}PNT+3YEyqXP8U@)`E|Xat<{K5K;eK7O0yV72m|b!o43!e-!P>iW>7-9HN7 zmmc7)JX0^lPzF#>$#D~nU^3f!~Q zQWly&oZEb1847&czU;dg?=dS>z3lJkADL1innNtE(f?~OxM`%A_PBp?Lj;zDDomdg zn+lVJBnzA5DamDVIk!-AoSMv~QchAOt&5fk#G=s!$FD}9rL0yDjwDkw<9>|UUuyVm z&o7y|6Ut5WI0!G$M?NiMUy%;s3ugPKJU_+B!Z$eMFm}A**6Z8jHg)_qVmzG-uG7bj zfb6twRQ2wVgd)WY00}ux=jqy@YH4ldI*;T^2iAk+@0u`r_Fu(hmc3}!u-Pb>BDIf{ zCNDDv_Ko`U@})TZvuE=#74~E4SUh)<>8kxZ=7`E?#|c zdDKEoHxbEq;VVpkk^b&~>-y`uO~mX=X0bmP!=F1G1YiluyeEg!D*8Fq-h=NyE-2S;^F6j=QMtUzN4oPedvc*q(BCpbg~*As!D@U z3(sz|;Pe1hn08P_cDQ(klZ6 z;P`q(5_V?*kJYBBrA1^yDgJD|)X1FV_*~sO>?8Sy~I9WdK5K8bc7aeNC zDb{Fe>y3N^{mrD1+GyH{F?@9}YQ2Om3t`nt zQ(}MS8M?6Vk>B=*j*yibz6QCdR=ALgTUcKx61){O@1WkPp-v$$4}e#KgK`HG~2@#A?`BF8em`ah6+8hH-DNA2>@02WWk9(fzhL_iz|~H~qEViQ(*{ zV;3tjb<%&r!whm6B`XtWmmrMWi=#ZO&`{h9`->HVxQ)^_oOS{W z!BzVRjdx5@pCXl#87ovlp<^QU;s<*d$)+|vI;Ai(!8Tjll^mi6!o~CpnlgZAK>6=V zm38^kT`D$_$v@UYeFyVhnsMZI1m`E&8<{V07>bBEI1=fg3cji*N?7pBzuamD`X|^^ zm!)2v?s|6T&H-_^y`KM&$!0!9tai9x&)5<(&sY6B`3D{$$KMAX3@&`SW;X0 zB-}obt^I;|#o_bR>eOv?P>=UC6CGTXIM+lSu?Uy+R9~O;q|c2+FafBP;E)B5M9HJgRIpF|GvRi*E+JTBI~T?T*X}r) zefUd*(+3n_YHZZS(g8)+7=pNV9QR^>Qs8t+iEpbJS!9;wio&9rn=19C0G#Ax zM-tWHp_YlJvXWsUqJUr^`OYFA4wkgL`cSOV;w4?tp>GT1jq}-qPoN zp&G}*;+#+Zh&vqDOp>gRL#^O7;s2yWqs+U4_+R4`{l9rEt-ud(kZ*JZm#0M{4K(OH zb<7kgkgbakPE=G&!#cNkvSgpU{KLkc6)dNU$}BQelv+t+gemD5;)F-0(%cjYUFcm{ zxaUt??ycI({X5Gkk@KIR$WCqy4!wkeO_j)?O7=lFL@zJDfz zrJJRDePaPzCAB)hPOL%05T5D*hq|L5-GG&s5sB97pCT23toUrTxRB{!lejfX_xg(y z;VQ+X91I;EUOB;=mTkswkW0~F$ zS%M}ATlKkIg??F?I|%gdYBhU(h$LqkhE!Xx$7kPS{2U4wLujF_4O+d8^ej{ zgSo(;vA)|(KT8R_n_aQ$YqDQaI9Stqi7u=+l~~*u^3-WsfA$=w=VX6H%gf!6X|O#X z*U6Wg#naq%yrf&|`*$O!?cS94GD zk}Gx%{UU!kx|HFb+{f(RA2h+t#A!32`fxL}QlXUM{QF3m&{=7+hz@aXMq*FirZk?W zoQ~ZCOx>S?o>3`+tC&N0x4R`%m)%O$b@BkW;6zE+aBzeYi47~78w$d~uypaV*p$kQ zJf34Q+pp~vg6)yeTT&qWbnR2|SifwK2gA7fzy#W(DyM^bdCjnee42Ws>5mM9W6_`j zC(|n5Fa&=MT$$@?p~)!IlLezYa}=Uw21^Fz-I#?_AOk(7Ttxm;#>RDD_9EloqhvrS z&7fpbd$q_e21Al+bcz|o{(^p}AG>jX0B}ZZRfzk$WLbNLC{y|lZ|&a(=bOE6Mxum{ zM=Nd+-I2A-N&2giWM2oAH`O&QecJn6%uYl0GWlpx&2*)BIfl3h&2E(>#ODt4oG}Dq z__73?sw2-TOWq@d&gmYKdh`a}-_6YQ5```}bEBEmWLj))O z?*eUM4tw0Cwrr+4Ml^9JkKW9e4|_^oal0*sS-u_Xovjo8RJ18x_m7v!j$eR@-{2(Y z?&K4ZR8^T{MGHL#C(+ZAs6&k}r07Xqo1WzaMLo9V;I<9a6jx2wH2qeU?kv25MJxoj zJKzX`Un|;_e&KY%R2jU~<5lm-`$EjIJLDP~11_5?&W#t3I{~+0Ze++pOh2B4c1Mde zSgj$ODQQm7gk&w{wwfE1_@V(g!C=2Hd%Gwj{{-_K4S|nZu+vk}@k(?&13iccsLkQo z_t8#Ah$HVB-MRyzpab*OHOp zl`$tEcUcF9_=3*qh8KTaW$znGztA7Obzb`QW5IQN+8XC=l%+$FVgZ|*XCU?G4w)}! zmEY+2!(!%R5;h`>W(ACqB|7`GTSp4{d)eEC8O)Mhsr$dQG}WVBk$aN1->sTSV7E)K zBqr;^#^bZJJX4E_{9gdPo8e?Ry>ZrE&qM)zF5z20DP0`)IIm_!vm&s2mzl z2;EPI{HgFH-Mp&fIL^6f74>19^>o^AOj`uyL0+Nb##Slvi9K4LQSs>f+$j?cn9Z__C zAkyZ9C;#uRi3cDYoTA>AT<|*pt{K70oZKG*S1F$r?KE=$4~W3!u53yUvh~(kMrClS zXC?Dmgv4iS`>~wBPJJFL_C8x2tEg*PCDX2=rHQ@z+Zs)Kkr;FYG`GnbUXqdipzvHE z1aZ>G6|e`}Q#)Kru0)(SZnUCN#dN2H zd1}r&xGsaAeEed9#?|0HzMGA7pl2=aehy_zsRV8RKV6+^I8woDd%4J8v9hs$x{ zl*V61wSumovRVWtetd1eJ%i^#z`_~~^B;aeuD`6LgHL66F0b^G5@om^&_3REtGmhz z%j^9{U`BH7-~P_>c_yu9sE+kk)|2`C)-ygYhR?g~gH`OK@JFAGg0O)ng-JzSZMjw< z2f&vA7@qAhrVyoz64A!JaTVa>jb5=I0cbRuTv;gMF@4bX3DVV#!VWZEo>PWHeMQtU!!7ptMzb{H ze`E4ZG!rr4A8>j2AK(A0Vh6mNY0|*1BbLhs4?>jmi6fRaQwed-Z?0d=eT@Hg zLS(%af5#q%h@txY2KaYmJBu>}ZESUv-G02~cJ-(ADz6u8rLVECbAR7+KV~a!DI83H zd!Z(Ekz%vjA-|%4-YpgfymMzxm_RjZg%ruo zT4^x)f*%Ufvg_n`&55cK;~QChP6~Fy_Z67HA`UtdW)@$Xk-2+|opk6A@y0~3Qb;V% z%+B@ArKl|Q^DJW&xuBZD#~SurH7XXf*uE0@|ccNd&MA%Ts*1 zg7TU!xY}~*AOY+tAnFR(Fu)e@^9V!Rm65$;G$-?6e%7w7p9WT098%-R?u#J+zLot@ z4H7R>G8;q~_^uxC_Z=-548YRA`r`CsPDL!^$v0Yy<^M=Jryxz5ZVR_<+qP}nwrxzi z-)Y;nZQHhO+db{>IrD$#DkHP%swyKhV(qn`H9~3h0Bd33H*DAP0S!ypZqPF^1^tZJ z{z;HN?$WJ5{0jQNzYOc|KbJ(Pr42~YhW5ohNdY*rEk=({8q+F}hy)&ziN(@q1;>jL zBN<9(k1N!p2D%uHF0NxFut`XwEMc@ZH-|95>U)PY@}C=bmV_*dakL}J5DUpNZi-y& z+{i0>H@c-g|DBO)HJ>7$VVtn)z3X}H`FuN-t>gcqLas?Lk@MJb5?u@BTn0Q}E(}S~ zXrNX`ysRv*iOn1v@fBDeSDvvR>+;o>kj ztRqEZOWN!fqp(`XQ3ppvC)c{AeyS6b_8pN1M*~0=$U;P31!~Px`Obrz;GNs(8RrJvONy<{Dk1x0z zJJzhQBt{J@&DP6cHugB!q?xi~O`yJYHUsTI zmgulx%I<*?vPSl(!tj;LL$K*k zH(*d31iyB9aYAzw49W&qDi0>f;b5kA31nz(%2W`QFJqaX0&hM`KP1gfdRw?7@}$XB z!^cUI%C!?X!QVQxbqEFSbuP0>_3MTCof6!e4LMAfGRd0;Lt+w0WK@b4EkGHRqX!h{ zrYxwwH&-fM67X7zP&Qpup&vAOaKH|S*pcbI{ksFg@tfw)paaK)5khkys0GSTnAtfC z{mVJkCXt|G-SYwt0O4dM8Hf{L*&^nOeQ271ECyc5Y&z5R0%hCq6~} z$XW$kcz!nnCTAl}NyB0#ikwyg_M};inG%*x38`EYJ%FXdj&A`g)-wJ(R=C`O^r{W` z8$1r{G0X4g`uD+}vw4`H5!*B8TTsmeaYGk3x0{&aar7ocO6?dlGbyV480<#{%^93y zF(ei<%{OYi?n?L9#HL_R-00#zRzbbwVnJ0zt}4f|KNBkT6&=Kb=$E(@aC03vU~p)7$XA@ zq5*`*4Y&u*=Ju>+x}q&Xxsjn;Dd)6Otudner9zi z<*LpeG}*vJ58#P4|qXF-ul1|u*;=-@oGPtmBnQW6VY9(s`5GMsO@!;s_PKo_? z3HbGokZ|vaAA-guf5W0JDwpV}1u8;7XJ=wD;NgcLIJW8S5w!c%O*zU0%~)0M)`!Al-+OFsmPW1zniB%fqF;klqxz`Y z2@srWa3e?B3ot|nhE|Q7VIjr+$D7F^n?wm5g8w?Ro0i72K3u^g)&&F^9~@eHd33YY z9LR!!orc0vq$sd~eR~hW{4?R3Di;~mz{^G1X?#-!|Cli(#0-sm|GHYpcab`ZA=zi3 z5*m>sJyOij{!PgIJa?A0%wL*Ur1fLJdJW$a>&Xj5p_IO=SwyTp@nn&@6L4vIfT79aPyo{LQ4DhIz1 z5g*+hII!(cLGHc5ROH&^^o=02r*x>MxMPx{JFMmNvzJ?AI8p!u_H8L1a`{6~bF@L* zxszth=`>%Vi`=E{jJKd-+6pf^vo93EzqFfTcr)A&V{rERu__UAQVyE1imol78AFmB z7T;pNFxW^M+O3#;Tz^e*`AqsD?M*wPT6pnBFPA^kOTnZYHr@O(JUQ^#6bD&CC*?HG zRAKSXYv9DU)L{V(wM=te@V@Db3}97Sn9r2nroOz06!qV=)+%EKB^MR_K}p$zM5OD1 zzhYv+?%A`7dBrU(#&1hXF;7lzH`nENZKP2I{qp^NxBA8~N>?1H@uZ~Do{d+|KYx9I z_z)J7O(;xu0%0n3o4y7LnJKRPK?RV@_v_YLogYPH;}`>cZmDVyO#%-IMQVq6z9r>@ z?*AQC$=?|aqrY8xGx%vfk0ZeByTz18IrP0XTVlJyRx5!NALYPyjcn|)U5jl^<)_KZ z2C?1|dkBZ;h8e#)3gUPfdf80xu^8evspE%Xf~x zs%phX&YuB{y}>%PuOG>s&EW}5Y0`dyseV)!C|`1(U{Nd4c4>07ZFmdTJS2T3+dEw8 zK%f_x!O?H8+_Qd>$DsYNY!?tC^H;N+!fQS{!4-9c^;uXx)D3|joo_FlBTTdDM4nx{ zPve})D_u{PG>&^G=>$2N-dZ!eMx?9X7FmPNo)7|>Z|A-mNZ0{+884L6=f-{Q4bN3y zAWL{oJIh(js2$bDTaV&bh4Fn=4^M?@N~+$IXxytdnI4{RkYA$8j(}sb2TO$~49JHz z0$K$WB@axSqKsyG>m7&3IVR+?xXLfs7ytuJHH8{`ewhkH;?H7#an)*hPiBLi22jAI z{|tZ;dU=nDUVyfIurEm0VoB6kiaK#ju6RV?{3qaV`NQ4&$)fc4AAVKiXu_1$86nxh zX)Mif*|y>N;S~7UCXQhs3-%nqNuTu>=8wqtp$-#tC?bwc-{&k&0>0nRBku-b5X931zqll&%fn$1$->@El+EIA;L zfEYJY)kaTI%H z{A%hpZ?Xt=;#(++B0e)B>4_a3E7h#8upWz!G;VQBX0rjzKvy9N2LECS2@wrBoS;4G z1PgI50DD!wtwsZ&JoAGuum9s&+0NI&_n}!kUTvpD{tyG9jlSXyQ)m9H8VXoDY$j!w zo;imjJKl;E5u|n4Q?HQsy`*&=VY`SG+YFUqG*+;A9(wKfm_|6^SWh_6>1u63)H3zEGm5Uk)#z>J0XC1L+&pzieqnAo+7zlr$M4kl;-h zjo^h7U5Y3tbY@(_{#h1et^{nbOP9Nw*tJOD;WejSG-4d{(2X$tDM@-rK8SbUqMe}%IPqxOV}m#%mq0)auvNwT2R9)$1-o(2o zpIS;qwy8m^tEBC99O}bYKd7ALbB~$d<=eGd>WML+U0aAl>{Uc8CB|oVWMt zbPe9+6&V{l2Th1)Jx`K64?gUC_<>x#Wk*SOSA<&A=j2q zo_M`Lznpsg1h-W546hm(q@Rf=xL@w5QJ;HxIp?O`;sOMovgc4n%D5`kiDO6%Rhe2^ zzPa=8pd(2&HN-=5JzsiJ^(ZlLVpZD^5!$(rt0PVLQCzh7s#6_N1dRKtQv_vTgSQT5 z63+e@K`67zjbb@QdwMNF8G29tcxAl36SZAGxolCj9aS%>(Tl*6a0eW@3j4!&d!12v z%+~Xc=>VJqBcW!D#JX3#yk4O^;#|O3!ol;J%t8>wc!*6`+`~%?-QE_M{wa&vg14R~ z(M1VT-&l-M(N1>3pNjVfvCIk}d|H4&*7{*8!W-;^tFgD31O%~NtUaK_*-m7CSEt}T zm^Z02X#cQ$Mcw}TG{>1I`vmvNoxujnPra4aSwP55x37=0VvyV<)68QB-b$o-h7p*V z#QQ8?A7`=m`*+dTfYdm=;i1ptR|In}rUF^r&{bKbI@5DT$JEo;?-N}Z13}n16v?G2 z{?@ny^7|!rg(on8b97#GupiPA<(g=o;@P`4 zEx06)SiGKkIKFHzK1M`ctf?vQV#b-{ws=+0U^*LYoTK*pu;A#NB$$I=Tv{LLVQin~ z@aGTp?J<(c_1M!Jr8MK;XA8fcB+*DkFF@oAhQ=B1o*$<@;ZdGs_5O!BKi8XjF2L4n zA&(?SaRDWm+p0UTFXj1prs!*v$(q+s=8S1h(*H8pd5*8%HGN0mgw3yvfsxr4QYT)o zzdjal^6zA56|Z@csYH^3Qr2~ZR#p|Huuh0Yt|$~>oQZJDF75aeH%UlQv)fQ=3P{i1 zRt99gL`$b61Q`pdos?W6yd&%2IWK#}$wWOa9wJW&($J4h0M|9sFtQu9k)ZtYEQ#vu zS+uD(3`7T~t?I;f%z8N~nG&FVwxGXrTL!k9s#LB}FSo;a+V-j}H^myGwQq@jTIycD zP5A{w+a;^kOQW^C%9W{j^&o@)3!v~U(?wx42E5G*bd82&a1p6ax|pk)#8nG9risCw zOERH8;tq?Q4ymxf*9_aF-sTpLvETwD#sB#ID1D+WohEt0s557Ij5)ldexY+diQJ*l ziBo;1v*vx(F|lI8udAo450QIQTmPqf(7oULr5*0dE9i>i#D&k%WyfM*4{*?_%9k>g zg1_1%x?#`Xm7M@YZ?!zJs$AxS&8sBLI@c|-vSiG<*OZyw>CL*p6#N~p z#VywqpWdZ;{ylc5d7W8E7Jx_H+5e#N$h#{ni@#TlGqz`yah-qCC_;P8?N*>CPJ03b ze(YVDvbIR$#lJEkuf}L7F8q$fKCWz&>{uFg9JgTOmA*Rux-{|#+pO`!s!!4;PlE%9ys+;|)oK%&V$*FH!G2%|y(zz>X zUwdXer0HIIJkelANg_W!ofsyiN{zi2=}G1UL{`V81}1D1Sz zviLV^w-$RE9fE4@H+ys>u;OY!sgqe&V-oFE9Fn$P9HbpOI{}esLIvc zV5S-9(XjFzn1qzo2owwg_d%7_)cR*!d&%@S&D($cFFMXXd!GdUxw5tZ_W@zRbjVfU zzx13(Hc!$teqA2WOYo^+SHpRz16DOcYqaXHSMZl2Ax$)f^WC??al8lfX9)O_p9#Ml}LB(N8yJ! zj&_UD9K54Rt#yqvhklEMZ3bRC&)(^h`#kzq-#_QN?J6eLT$ zMWG-mP;HkB@5;2*lAP&1*4C)HWEs{gtp15Y%y|*%(3UOMu*v4kTi0@pWvg2Y%7yI* z%XNlZa$@AZ(Z#Elv`5MUei~VFCjF8El)@g&>(v;E; z;laavf&ANfk9*0LA@oP4QmbCBF-lB^Mj~wo)eGG57gqAKC>Hd80Eb+7b;iJzV5RsL z8>ddQH8PnC;l{M(t4c$M=q78GW6=*d#c`-jK$q#-{9c)UNO4eLm9c!DWcCth4O-FU zboSKPhL-lq3q<)m8Xw7+l=Z)H=rGgMI0H?KrPjc;iDzY5g|Ve$8?SE`8*sb1u*>dm zD~f9~j2H~6Oo2`_1 zq@_mmUbFQV25E7XJ)zBRQktT12@qHHy-@aCdAFWv4iZVN0B3}E;k(jg>X|eqOrqgM z4yBUuA*BHdnN9v;5>3#L$NFREyHW&Q*rWYa_q zhC~>M&bMFgXC6AeQ`P-s<}Ot_x^cb51r7ArPbRRs&Dd_TEeugnjR(O#V5i6OYjzRF zw1@Rvo;_wEfQA@P%I^9ljrhxxuqf9g^cWSKq~+kiVxa`&EBDqmB=C1G+XB7`TQeiV zR_k?`$&W&+ntIPeEtM9hqcj|yfW>x7&1Ht1@;!d#Wo%1hO+^Q{E?VD|`-OvV9G?tp;6{sI%L-u)Hw z;|`uN6~VqZ!g~K#B@W7?wDcbO?XS4hnW9kS1Hbi=U_m*~7`N~3oK;qFTX$$LQ#CkL z6I?a(HkF8SKJU8mT{K35ekfP3`05!M{gmrV0E-=IyqP=N;K<&jOnPcjdXrbk$%)z9cUe|#I0unK5^+qGx8#2 zz_!bmzVG*Uat*&f4P>&sV2RswlITV}wPz?_;(S;19}e}54fP|K5l_c2kU5(-Zh!7t zz=B2HktD~ap{s%*CDEl?x6o+91T-xH895-S1}M=*KhFM7Nm&1$OB++Robv0T`OBcJ zXNX%Xio0_ryjr)!Osc7au35UM`B}Ru4zN_o+C!+s&e7|}Zc;5?whP$@J@DE`>w-XH zlVmbrI4|-Z^2^I^EzuYKD+JA@8lx%>aLFZq7KT1~lAu}8cj$<-JJ4ljkcSA;{PNr)d-6P5Z!6Q=t!t*8%X)a|;_92=XXN=WMV))*gWR-wHzU(G6FPTfSjd9) zm8e1mfj4qFmlXO*a3};$&jgc$nfG>NR&iao(jYk`%E75h=K~dJ{Jqs%UH|aGHL8)-1MOyS2B?OJsyeA_YbGMDpE+>=NFcyoI;N z>1>3G4QR2~EP{L{x2e@E1U0jGGV5H$aeigDq&Dr zQ3FwJ+& zndX7VK+XD)t06uUY=)Cfo!ke%uDpOmq^bpEB`iv6(CKTGgEZUi4ddfNXJi_z4;)ob z?R+qj2SYX*zi8z=DXChEEDW+Cy>w-0agE|A7MoRJ4}-(|go-rP#sr%a(5k%wV z&Jllj+6XuSoIfZX9|mK!bbd)7TuaHBvoa(`9C$*XUh}hH1;Q7cTJQR)c>h}Hfr$aS z64c7#D^f{mN3s#2=SEf1$(*Vj{vZjF6Qc{a=VbTske7L^EY&A1I1sgXaYSH7(lF1V zZ<7`Rq33WZuu`!HK$wRr1=uE}#&JMftnZ&(P17gWF;>$TA&$ZQnIz>blTrW@49Z&H9yhgLBpFw(57K1dbIQW4fn1X(IiFWEKmPzV8gAa|ak)HAsmcQ7stP|q0hEzBNL=4YdXEkyfS zF+K+CVB#~(qd7eeZqR-VKIYJVmK2ePk``4I^PfQ*C7NUR z`w9lb?iHv2$4_p-+a+O}Fq6SnPiz>aV!~d=l3VdgDuwAPMR9eR`)b_`lg~{oX0lf1(zbBrnj4+-q zOl^#`)XKn=`()B-jExviKVTYrAKa27KAg3cboG+}D6*R;<`GC-b?i=e;aV7n(}XDS zK5xAEV=T^r#eThV+3C<^H>SuvAP&fw;Yn67eY%4=Y(p$~!`~h12 zQHM|f0#pQP_s$Q+TtMMvBdjQbLWw9cW?gl_+P z)2T94UJaYG2!yXITYjYl-@#5_47g{N|5=P~m|e}-F)*^L+{7O$#wv2e##5Y=A{>jN z6NhQSor9ulwP3gfxTF?V`P7AJ#E)ij$I`gc2fnmp&9w6qS2-Ct}6 z$#O%mKtP>I2VUBMt^Xm3LjP*D=xEyV?|8Psb91ZEj=gM(C3^Kcfvbx*$NK+MhP>W;OneZ{Q>eFEmxv}%ZCJ32=zr_OZd>6~v@ z6+3JzX%9qOvKS393r&R9O+te&#?{Q9nLkOV-eLg9!{WK}WyUWLZ7bQ5u26*u9c*T1 z_s1)j1k5&b8&5@YnmtS{tsmQaLW2%8D*8G-9w#PcVQh6sQY`!tBpU=8EZR!zfB{f{ za<+Err#ZNM4JEx5n9!zuC#KmeI*%tRXP}jpswzymT7J{YpXdzA{J7K)j1tBF8B3DL zZXkec{`rT_{__t_`!E7veO1rg1tFzVeUTBjut*3ZOq}A$r%sWXn4v4|rA+7uMvy9n zL~2WHKLg$BeD2Wq%?frTUM^c}?K?3#L+Q2-?PR+e1Fn-XUThl8^}8JOyDZz-wcFh5 zYJCJ%J_Pf~bX(0A?Z4hGw(mY?J$j#Vo&@9O>in*f)*`H6&(Z-5xx5}$V@dR)-lxgN z=DMA_EJO4+^w_+D7N>4=%{6AbvpDG<(b)xE5Ezo~oEg~cEM?mwyY?3ZtFE;RyDS`u z(^sa_s%B<)vktqh=1|?Uv6DXsA`D^B9%_mXqx1C=a#KurOE?49)P_ixiHAA)D)oqEjQ6_v0UC9mTtMu&kf8&7uRiiigPD{$Cf(&DuOj0 zr*5{zPyO@Kq(|Ttu@wxKanV=^OPOjh-_$MbNz})ou6*9nq_XQo86WJ@JN~-b=Ln_8>Nz_ZS#QpRGt+bzH*-;{#x7PFqie+ z7p5e})fcDq)J2z=z~%nrFGFjbVu~0ICDHW3=HgtCW)?Z(%Cx$z!QuszcOCe&3!Al2 z`793RnB{Jj4QpQ2N#oKT>aY~aNxz_6B2&vPdJadbC4qp#H^<@o50}m>7WR?NO0$ZI z9OKTM+jxMFWX9mi7(@j)1Ji6~?HLU!KT0Y5a^-?|XH^B?R@T zn&a_U_XFAsGrNX@S~g1<=uz@~dCcZO=1??VC@PML{g}lbuN?j|_1S=dJgbT~o}}hs zP_uYZ&0+mWY1fupe(+6nn6<9-)Xluk97yX-!!lqSXq~!kL-=+4$Dy>O$sKO7M^1QY zhZGZfiNQu+?sef?E>5sqj$kHmf;kMv<>Gu)!^4!#7T009vBzq(m2aoHu#+93HBq7T z;Fs8IHvUlmxCB2hkDbm&xwFQcXUD_&sdeu|EYhFpf7v5_LCcVua9aunVe)qoGmyg# zIGlj&IrLKg=id@t7s916d&Gf(%X7^FFR9^bz-;*o1~Sa=`cKfJ0i}X+pBKN=?}!dP zg`ZMtP6xSuvHb=5HYH%ELaGxwqH{ zpY>Ic^}J!OwM!VmNM!$nUg$qN9DLtKuBvn1(x-P+tA*UHoOc727>5?^J;JFo_ac@) zU57%w^U2ME z@z^ZsB!AhyOscE8;~Ft$)NL)GcLteq4d32fw??L0QuWt_M9IJMgZ71Jm%2khx|QN+ zkm4zQ@OjyM+l=Rv(!k?%cYwnf7HWs^M+P^zo5o?7;E)V0v*zf}(;?ms0oUK)wKmZY)mSTGN4X@2=ZU!Gy73M(ftmHJHLFKQDcu`d% zeqiW{G`?}AtEP zKCnHuWzXZ_Hc>{cP@h~M$#q}kG{52%zmhATR3AbNGR~*6(%^Gs@UZ3i%7%PJ1mB^S zcdcrFDbD6lEJGZ4k6JT;eB_JbgIkkOqkz0I{q`d^kWl6a!%w4V?Y!;8%uU(-UA4Ti z{pv2+5CN^ba{ALpu1&qm`sMP@_L=-a)@-zC1*`f)uV5MU$xJj51%?S^ zoo@;kqY@4Zw0B!+hIvTT8KK*~9H@u54r>s{MX_|#z`Z$55bDJo#=hz~k)7CTbf>Gn z=!u;@JViT~(>P7UDdIOL;6kPDzOZNl16jLo5tHS4a%~T&AlicnCwZ5pZ;+WIB3tJE zv|J^!X0Kb|8njISx#zoB(Pv#!6=D}Uq(6Dg*ll##3kfDxdHdBXN*8dZOM0I{eLTO4 z=L}zF35GJX4Wee`#h=aCB+ZV0xcaZiLCH3bOFYTmEn0qf?uC#lOPC7>+nVeO1KQ@S zcZ5Z0gfk8hH03QrC@NnEKNi15bWP;FEKsGi0iUHN4L&2_auv%tIM}UFfgRyp5HWt()pn#0P9+xF2H!8zMqf`WJ*9YB zq~m+%xLtVjza4>CO4*%thB2k;Gv1Ani%8)IP6Pm^BAigXgOUHWcQDEgB??AtdsOx5 z+pXKfU4>+8ViRUJ;h()e88jRLEzSN7%O|=MovCW3@VxK@Z*xS$WLG=u_Nenb0wP@Y z6zs##uQ7oFvcSdh5?6kZ!%8l$Xuz^Rc!lv4q?e$mv(=#@x)s_VFF50vGuE_Nr{4zXB>y?7FOMC5^sBZr`mS*t_@%LYN9wl z+lsqD#V5JR63GEr9^&9*f)kFs zJ-A(>>!h~d0%9*wd+AY+&oryzurfV{QP{&-AtDs}#iq;dal?A9jE;huq2gExb3z+- zVQB@UHlVfsy1$)dF`dcZuc(GLnim09jrI9nJ6<#=03FVrkuINg2`RTPloS^^@KYD6 z1-C-Oj2OI0y9Tdx>=dNHhOYVvx!J#4EMhold-PGClLuLA~k2VDl6cPuV4lI5c(w9@7sllth~H@)0+v~XYqqC6&*fSX~S4Bii^0& z=M)D(5FoZsKxB&M$J_7lbS>$kF=@B|Z$#D|LHJQIr$aO51ta6s96Ug*Jk;|>9Yd$! zoF2W+)lFzY)J<>U$PHwbe9>BKLAeo~e%=Qy#qhvK&`)b2 z(U9#8bba`eGr9tr$SvM4`y`lLavOzPm`l<%-(R<1urb(AX0RE=R=#&QI)klkwrJ5%D5YHZ!~s zGwK?zKZeX|uO*Y|xLjO#6uzO%iXWsSE8#zLOWc! z&2L8sdT;bhUW495)_fGCcOLM-@DfGcb1xjf(ezYJxYOv<7YE$lBCrkbfBA{`I(GH- z(yHy1h=bg~fE$aIbB_3l`|p$R_p0b(+aL(~b<-Am9H@?s!T2*7{+*Vj?pCpV5&WJO z*GbW%PLj|(hbd!fQK5Y-kgDHV!-I$y6G>Y|&uo9+79v}}$s=l$>#F-_F{TjUn~-!M zBN>n)@(LkzI0Sg?f1s}uBZi`wRB}ywU7wqq-PwaS%3nitaXb{&Q=x!xvOPfiQmmkd zWpe2@y7?wbI;hF|hlqf@x+3@a4$wLdJ1PZBoRc9oRGgdM+vm*;5XBZcMZ+@4_{aPUS|`NsD4YP2JUM zZEvA&!QLB$K*%gHy~y-RVs-C zkN^usP)S1pZXjj)nugy#?&vpiE^DS|QlhiBOc?nC$9CK}Ze)ihI{p-m$pgYV^5L~B zQTU>)x*fvKCNK*9j$@Gyt@@I2LF8c7YvDJDCf%1h0zVyNg7E~R$`6JE1EQk~-c1xG zE@xT)TesWHs}ny!5_7F_AyGL9K?Q~mP?>Vs!(oWZR42kf?*iTV*h5>tnzpljZL8IR zb7}l8q%Ckfh{^e3k^3pQMk=gLu60`Ja8HdkzVbeAU*exs*ajmRVp}O}l)TqX!?G7e z{4-~g?Gq%~)IJJ7p1k*WSnL3jqECe1OU}5nirS66_-$3FzMT5t3X zg{jgP^5?%zb(vMa!S|1cOYk4W!vG2KKd{YFIbPCk3_74HL`fWJASs{fxpzY@$(}Q- zK5I4TKS~`mfiDoDOm;XycF6mi|K|+d=lh=@U?9_V)BDDaZAnEw43`Ls1677I-+uFi zG?^$Fbc*pPun65{D!fH=3Oyp$WZAY!{JhzaUtIgYCWXf@)AkTa@x4xGjp0c zs7@JB012~&;z=SMbCp8d=Ga{l0(iwx<@o(f!OwmyH-gBN6wewq7A_h)oKg)koFPft zNfdie%F63S?rGDQR(N=bPuK>G0t^ax$0P8`N_cvR8rOf(O9T7$9#5!B;#!XUpLZXu z5C(OESAmE*2+hV}!bg$4K%`cQHBk!>##tW>1RbC%am`*|5IbvoLh!BqpAi2OmdXqf zHp%|!N;d!LN_26809n^14YVJJBe7aL87U~>HZ)VK%d|rZp(~zwNH#VGuX!vfal&Vv z-c)h33DOB@xl*~m5ZZ22sVRK>8I9+)QMVtsAB>r~SMkGMZaQ;Xi|?~Xxnmx;cYwYx z^nNxRxGcq7I!sO#b%$!0vQ(OqXm6T4mTilvMlYj|*i|=MK%kT2df;bZGW@NrgeX>( zf7eBsjJv}pNuEuHPEs42>}a`ut-O9lZDNh)_CsBpeHKvPKnpcWh^bC2QtnB5a4qy) zSrZhafuAkk5{yiM|zdiecKh zuc2R;6^;@i07fmepeofAJdX*knDzBA{3tyVYu6z#z;Lsi&x_bzzLEpfXtH*NrY_G`= z^X!;eI#hV*mmjjEOlo{TxQwSdUv0P$!Qvijpv9plBI@FUU#RJ)8Vn1ZGA$ATqF&s= zvcTS>Z8pepd>k=sjPY^3fpCB@aW8$Oq%fW;R?GpYoT@ki@N#2LxgTk1dYZHNrk@lx z7=yYr0FT$I>z~I0nXpPp$t3)}D?2^<@KWH#E{irFy2`)5r{AyvWHYzn`5@h;GVj0@ zJ@1fbD9gX=vQNR7PG5i}jFE}9#!;ote)FHdW?VVe6v4dWEz(R?!HC4KeVde*DGr=F zRotamm=!I~=_{|m;mCI4#5{C3_gBXan1<>!K!8O|)&K?O_L`}=uKCJ-s&+!XTk?wi z%Bwa_&k>4}`a` zFCG!c^Cdj#Bc2z2PXBCW$G)<%9X6;oZiigwvMLXQ$0f+2bKDCKCGR*cG>+;UTQ2bj z(2r#Od&Ulv*{?U~hq`j8W&8aggxHo<6*$&cDG#k;GS?mLx0^7mda35tz zHTnFA6vB^rczV1Ai8I&XyJX?jiEcQ}n;PYCl~EUPIxF@V%#c7LW`44<>ezAiG>1ff zeOSeCd#PW2z5z+<4Y?Qc#tb&+uH++5^G@!BaaDeVN8x=3ZB{R=Z5e+zf&13+nz{l% z{{#>B^OaIK}1Xh z;}?)W)sfwuf~?Ov1!oiQ-@WVG>D#(JL4Ob-h*l`y&hBY*!EkULKFdt9+VGJ?E=r85 zl*~dE)e4&l8Fdq`I@T2BAme(u7_)}y$TNu^lWWK-M8UQ(ZuBcA(qHG3; z&7bO_w9Cp!REZ3VB`&kfYOCmrNQxu7pbLoFkf)9Jkas&36ZnTBL?~cDug+T3bw?o! z$U-GUnOTkujjaB8vxcenWsZ4UrH*vMmACDj!95aG?gE5-g<6v8X9%kXThF|rP(0eu za*9aK6%^Qu4oyr(1t4hqmPX~~L7tB(;C{DH&MWDzUG+6I(;TGeM)jR#hK~O13LRwk zRc2;#m|qsRADyxC<6XC8u+lvVXoH+-HNTQXImy0_oM&D=ngI3OP?c>&k8&P2iV%hg zq{#n%P=0$dYJ2o$clJWqpVH&Q;S5Hv`T0-)mU2aa$XL#RH`0~|_g zmmfHkP7#d=iuiU1lL&5T+egS~-01WrWiiA=({_yWBnY@x5eX}`?y?3Xdic;`1dn5T zxTwLw{;Qt1MSWowZ}r+U?8Q+R46Avz>o>^}4zhvZaa_*Jd(2A!dP8ah=_*lh!W#a~ zNUm{^sD#HbDq!m*EK}(GzVn4N2GeNpEp8Z<_tctC_id9X=Irqhb_{b^H;~}qwZI&F z3t^MPXp4BuDv9@1Kr3*u zZ|&i`IKW!_Rv5(CaTJBndmX9B{YL8HJ2}u)`_>#J_-m{T-xpj%|2|{xmnVF#+X3=* zY*5{hDkk6M{+!Ved>d}mD@q^#{3qo9ZYb-+75cj*gH%I+d=}E+qSCK>vj4p z81UxB7>Gz}5QU^Pv-AJ*EHMW3g`EwB^^}ps>1E2$#r*H_{O{u)J@@1m$?Pu=va`3n z?so1N_WbU8U+4Nb|AN$Gv|%%33+!xpvv3iSLv&=qIUrD|3^*|rn7cNTWHgpaH0mTS zbXS-J>ZVOG~>BOwxVSa1sk6ivguYJD`$YgKkB!awl#vZ1NenaIidf zIo;H>3%L>R^l(kGI`c9&1a9H-s~68yw>3t6~N-Bv<9hyv4@0XlT|13}n_wh4#^(`bgWSiUFD z?SO{pz~eEqAvU|UZ-MPN$ZoAzAm@B5l}5B&MB(X&#FQ{BiwixOTe9@pn>F;%(9zOZ zly7ELHP0wS+Ikfr4P>I383O6E%8Ps6HYh5VLs3+bL1$J`TkTm6$wnI&{gh;r(^g9_ zB1RO-zhYoFDSl^oIQ*3Sm`H4%TTjHtuLbN&=j+P%iuVlxfEi zjsZUV9XdHY8m9muB8q5Vz z(`L%J6y+JTwbc>-nW(k@1!b!V8X7{S8M4^jErN(9CY}WtZ%l(hygPSA0+WuRy2zYP z{I1rh;dEB2eq9TUxCz{Gyr5B`eQAc=V{W%c+@W5W-mHRf!`2j21`y@SR^7Oz6_2Pt zkOomwUO=FaWS0^zE_8fOUJ%bwuxpLG@_{*8@bC&b7t2Op`l< z@kNX+GMUc*Zm2{Mv|>~c3<+pti9iF4V#K8sFm1soxJDi@ z0hJgP6;T1hrbc}rAns8Ko;#S9v5&XknRCva_O>&b{J*(Da_#Ad?20`5$%Xl&Puge2 zx?l9eH%e}NIwyYKT%Sue)L;7I7JYB)tpVNP7pm4j0n6@>Y|3y<8rov)IM#WzE@P_p zpPF3p<9y7UBK}GHof5CwW07klGghQ%{IeT#5013G-@n^&IFHZTJJ6g~ zCL1d0jcUJO-+8y)#+Wl0=`qCJo^!~ia8$-;rOBE~#*_zRZ*s~5n>IEYEtin@n6TMCEC;3v*irJ77~dTlkH+Ea~ni&gW~z zEBWCpC22aJfc1md!}q~j@)~H{%|IZpVtGYMh}wWjmPAVGFG{e*)g0Ukf*24y3)BXV zL{F7d(CXNXPzVFQlu~e}UL~fsmSnqLDoUS5FIMR1VZnVc3TinGDcHznFA6zTs<73? z4WUqG_@f*^v&jR_Q>a63^$bI30RuiF&nnl+1=px4kSzi_XB+AxOARqt@H;ZXlCce# zxlDYVFRiA{;DaYx(}XclB2S^eT1Q#1;p=9y6{`}J_sm<1Th)5PG zzzBlA<6+TFhl2c=Jl_@yJ}518aXJd2YFCAVu-7TMwT$KZefT7 zs5NxjtWvoM1u)bqHBp$PBs0RBf))u;m?bp>hDT6vTw&Lr!dBTtgj5XtcKJWphk_H; zeH09+T|vQZQ8Efz6lS0!cG`T`QE*MzYzhh@C0zhrg|>NSMAtY9%Huc+TF>Ppkl@@zX1imQDFMlS23i7E;Qs+kyyrF{7O&UZxN+ z-QgiSOj1$l30gw2$s1etFkp1{tI8Eq=&i{Q(-jkZqNBkxHjo*)Mn|Eg=J}ZZ*M!@$ m8X&e#V;O~v<{(@8u;?|riGH1;*CyBcIM_}B>Hc%VBjPV`^lBFX diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties index e2847c82..d4081da4 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew index 1aa94a42..f5feea6d 100755 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew.bat b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew.bat index 7101f8e4..9b42019c 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew.bat +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 34753 zcmXuJV|<-$^ZlL1Y~1X)v28cD(bzT{XNNoH4jMPMZQHh;G`62!_wWC_Ki{06wbslW z-hNv;bUS>4$$AIV1w{GYSbDa9HY10D}fyEl=S$4U=kIo7=?lBvitGLsWgUt3{^aFT@HAUZCsI-`}|0=Lu@cG;zc@Palo^sRPZGG5llUR0<`~PGM!~n zkm6B^u;0*XF-c2rRb5+vPU03ZQ5KZdzzTpUoTLdSw^Mg7d&C_SBf8d z<*%@>RYEa%3xvhKQ2+fgWH0mDnV{(?DOFM#5cbZvWlTUnUQ)s@i>v1Y5?qfhhUDR06ltpPtiHl^K$(Pwy};( zt0}s?0BR`|nU@5F~DUSX9)ut`4x49n}R zR^l{2LOA=m`mDpSR`_FjyMVQ&w;`V{m`N`(x2+ddDsnd|wIx+%1gmXz?F%zVZNlam zr^+Gd{gTO(b$1`z|fZ_Ov=jMJULx1p0EN=aBKXm=pY z->4oBN;{|ieu&?4UQ8-lsl}lINU#I4sY)kLD*2_EY)1qQEuBuv?1OvD9OX)4ZFGko zNY1cj!@*^`YR&yqgQJ}!%k1aTRf>lFTs5qf4%{52h+a+UOB0A6OX-5?8ssn&$ArX*;bHjO311(M-=LEkLFKnxXu-2SVtV3^h+$LjIVBrkLr6yUK}j zU&BC4W51wuu{g|fxlHAA_xpUlM(Tz{M9z+h(bo_JaM+(CS>elq)VX9p*iR@+d-3>E zbEvk$uQDEip@A7~{OlEaM(3gOLO}N9({&{A5limEDf~kGp<)KcNgbqE_%hm}H?O%{ zOS1KYLw<%3S6!N5=K|3-IFXRV$Ok$X)FawLhObevqK3#X=F@7)9v5DLJ;;fwzp$DF zlpFb*+VP$QQ+_3pc5KsPS$h=_AvDZ{g@oe0;K~Tl*wx`)OIZR;rL-*2V1apFBtMYs zvytk?nV6Azw|vNb0dH_kb1+LGp31ui3H4A}bjX?4PKt{*Elfe~HyB!d+(E~M z6&4j%CIb|-3h*MDxaDThnd0Z(E70#f5#`{82a+R|Z8^Ze%O z)*=1lB*QAle%YE*F*`Q<>krEdo7`QU&<{*(vg@0Pequ9zJqu{zQJkgnbMMWgjN6Pc z@0Y!!A|?n4r=XpM+avc{#Rbx(lwds-Dm7na`I1%>brkR`$iyaD6@%P8gr=FwvaVM^ zz6#!Vq)aP|7g#eaub4k?tySlt&IXA;AZIQ{EFi1N^{NA`F;64EqSeLEDX1O;F$CKz znWu-Iy~J?GeQJK?Iq8drKHHkFUpe%oNIn-l4UbJ z;dB?+c~A@&AEKx~dw$lgsbR_q+0o6vsIW%6+(&fB2PU*n`I6)$q}OsZj>Sc|M13rL4ugI_j2sIyiPDco2SXuyXSOmq zoJv~;19Pa@b#GDFe1p7`wDc!vxP$x7xx>hi_0k(D2uv&)k+O{p1!i;xBt;%+P&>{U34C) zJ~t!_6~pG3W*nyY{c`&HtE4LNA3sr`(F5NghTF`xtZNmC@}C9A8zW40nFu-9S9R$5dWnHM(S%nBiI4g4tU~@X@>JDz;3qcDyF?y+m0;!M;g>TO>r(@L@pz>UJd5acWYqdC$#%aQ{<@A^FCac*B$Zn9`QC$)*jWh zAe%J4RP{VlYU=B{clOr%2E*3p^T84X=iVnW6R|*R)%nBppESXKd4_o+8PpKc9AJIY z#0lv1G#Ph78;`1G0;Q5S<7=ooRT|OZiKv3$S@3G8THj8*5+mkBX-hGq53>DQBTdIM z>ukeX#Dl13-}eBvatW>(DlWFxk(P>d+=Lj%wVXDo&BfM&28Pn>`002&W{~0R=$e&Z zw7nx}jDZhxY`N6@N^^DEWJ80q449^!!GEr97rK`6m!(3vj*H6wH6g#ORaeB{=(c*}S@<{$Fx*@K%MW_Zw z#t+V1JkJYe`fy@3$$8Dqg=ozpyD}4}4X2RaUmNoqgvdkbhk%E_Ig>;y>%d;C3k!Jm zbNh>w8UF!cDb3#MVi8@8WEM4!=ZI)w`XNMIBxQq0>+%HUAnof1CS2k9a4vCBRAj%7 z)F7lT{U&41X#KbXA9%`n&g|Iw2A5rp4UovgRo@UVJo7RZ56A*NzreW`$(f>;3HWTEHBX$@vb^bYcxCwwSgW!Pi2 zMKY#iEOJnvD>juOyCCErp0k&{^~3%7M^9;W2VD$(ADPkmcD9gbmSk^h8J)be%G8pl z%Zvqv54FfMAaAmc^d?98*nD}@ik3g!Whjv}WVHB{nr97fhNF^36qsCr)yiZY=P=-) zYqsZQVPb>w3xg^@L7isnr`qr%3N}2=QbG;V5+bF0cArs=b$jhPrWnpHvQFz%kmL;g z1$E&8ZKYQjT`3PCCdqkDf24w%T~jFWuW&M0Y4=|d%N;%{Ssy{Zq>9oYyShV)9KNqc zw~=w}*r2_8_IM@_MqtK9Dd}Lq_m^vfz_gu`Hzr3cfNmGAZPL9f^eE@B%b=>HWi33X=Rx!H9cTYw#9K7ac zhp?Q%h6sE!C)EK~To9ux>MVl`UIzv;ODnw1H}hvD8vHs8XCN}ps~E4IiMU#%j0U8c z1$WLNd?HHGx2C`ZHG^ODM!^x02_w}xvyRj_BivCn-zA*zQ^!Gd+>n=lB1Tr$b9S%9 z6?m4(aVBGT6}~($(te0|uwJ0ony-&J&O{-U$Tl17tIzSG1m)C}^cyvq0fIID($8?C z?&k3F`-fV^@d97$bO-Z{Ss8~+8n^@12jb7PUe*q!L4@J$JE!c3MQ5wZ5-k%<9uNHT z*m-U18hT^qn%d=n%j69h9`QH&EKH@WB1A@^lq*se;m^%}xi}}}*V8Ku{X%Xzj0~O7 zIT|nQDuj+DTx+(*q$w1o^bwD_qw9)Vk*j7OzOX$=aUhC%P*WncxP>Q^eJLh4ZvTQu zN^_IvA|46v77o%rx8Qe5-}prxxlKtw5utBK^@flecS{M@Kh-1^1^I^01>L5%m&J5M zbA_50igDI5Hctl_AG7L5I;hT_E~UM<=Ew)D!~BHqKLE1iUpRwR;l8TL8=Y9uE1swJ zj$T1)Gy&xd$;t?x2ohfm@976>1Ia!3<0Ao)%(Pp6~;Xk_G&p?N42y0NOYmVPvbiY zbIBCvHbVxRG5x}-CYKsKZt27tQ+d%82=6qBQv~J-VP}b)s%dto{%T7UL5rbqZu8eI z&#h`8%6YA++UAw8=)KQXSyI_1hg2t4;6qGMnNjZ0Jn3Y44IsZgNu}qwNFQ|5`<)xh zMIfaXx$F&%qRvGHMVRk{$5pTjrP}OCaH8gY?_O+!%&wtG$~K)4A*M=)2L#DOg$c&>Z8&>Ws2tC+2;2H`t8daf86AL7P}ho48-x}JzWxx(EGIresP z&Do4}moP~-9^of^^Ap3KWGwumBqAp6Ff^nYWl#g% zrR@6_WA+3!wt~oByHGFe-O*Nhyy#i{g7jb0yY#=vScipxF#ZbhuL(jyV?n^fgU=)| zz*pE5;Jj>dV5X{_;+zteA0rf^PJDnuKUaO=FQ$$4`4;~f>Y0AiK=hz^2loxVlKLju zH3k+5zp$P9#cmbW8@5az~ zpw}0}u6^&dP`*J@z6H496Br_qtR9P|B@C&zr3rSBjcoVbfy0V?i@vFF?z4>SeDFhz zBI!7|_fh4qA?#6l^eHobZa)u;I9X0|n{sQh<&r+(d4$?w5~>UGC+BKYK1KDlq1(?< zVxCk2@+Np2Vhob^<>QnwuiF!i2*7(t8AU%m+FFG^;$ECmp$|K-MV%?$uF=ja%_%YG z86(ck{qCk0T|98m3H;;NoVuSnm+s(^{gZ&PVpIdL@Qb0V@6R!6V7oG-!VdfOM+o&W zdjA2*J-bqk|11cgZmFgoi$kdZF0461#4T-(NuoYPv6jeqk9*c^#8vTH ze{yT(K(34T&O2%h{!C~h2%zOK$Y~p6#+iUTr?kwL042Uiv_4lS)CWMBG}yYQ6!^k}NaH$BgZ0B_Q?52e4LBdvQ$RnziXs9M4sATcVPn zlV#b9$TXcGeBnp(uHZ1NsL)ir+~RN}4~F7iQ2ujWzkd&({J-aL3V2(B5FCd~0q!Q_ z2SN{u50hI;Inw_ie+tQP3ste?b6zFsA4a|AdJ;xS5yJ%f3ynVgf;vbpmsjx4di2bG zbl!Y;%qH%Fh%yS;xg8nNe#uKadg*jTJdG;7ES6ShT7@ed5U4x0{8jTEKBX699ouyM zptA51(RYhsrINRTNKfq z%2|X$flIl%9zLF_}MNTtrZExbq(Uv*U zuD3dA#>ttySc|-|Gz;!UlT=GNLO4;1=#vWhW3(@^M~6!dFe&B=ZnAVr0hZcE4pfVr|J6m)hgWX?k=f`FiS)xuQafjM^d&~xzBtOTvIF! z&zN&MqNc6g>q|fxfqZq@OOhKq@{nILm636s&QU*FGP(`^^LGI>F4^)wf6Ku95BD5W zN&7mQpL=;9J?$6GHd{Gg?_+74w3HNkvf z4?;<(9|Um-AoRPJ=+pL*r^BJA`NhTO2bBNUa^@!&-}gLk?0#L{T!p~%AIO3CKlZgq zu-#dgjFPFO+J!^bNyA0$MOnn0tj5M+*MLx!^p$Ypc;@Z!1&?7(jhx~~bO&h{s_%c) zBH;PI3eY{Mv00DzDWg^TFhk;% zSb2x*qR#Rq6^hn1*|QZ8w{A_Q-Per>OOd}ZJ%vd|oU!wUGbuIm&I9HS~ z0`7C}eqZ>ie%Tft$29x?DnOqcB33rbnVzXFg{${~McUkN9yewe@+_}@iH9u<65=rQ zvu+hqx=W5jSE$#8Vx@Z~?{NV(a3a=$=8_(J|aQ1@SHf(3v6!3Mgi=qX|fV+n}b=$u+xeJT5sODCh# z%0BRq*$GPRVxmLBs_GBBy0_~6ejonZ$RzO*`tikpBOt+Y_rF$n*+}76Z=SHiXK}&f za=G%lceHc~v1r8X!_T+o&_1WL&X1i{;BacLQ*~N+2^+H?zvm4)(+PB>$luQSGxik~ z1z1NmK39DPdNEHQQ&PL{=F}wuD3s5vE*GbtO;P{ksC+uFOoR?5w4Xnr=3l!GR*JE} zT*ai#Z-RFy7tpf-Bp;t#vKb<;Ky{VLU5~~G_FN_D)nPZ~7pKma*u7Sc3D|@tJ~ShS zXm6tIrlIC)az&H(jU!xMr|oCyt=VP51KDKA2I96y&8h#sbrPsF0#rVJ1O^_(9EmXj zG-UQX_oSZVOl1#5QI?#@BH8V&hYh{(mYDNM_@WSzQ-_IJ0f#aN(%5pi60l7lwC|-k zYo<~FC+rZ1%;G*~p`7}gcn}P|xf7f_Zp7zi*I(XQ4BF_|&m2@;wm)%E`dDBUJ^^sit=I^+MB za4Hg6C>k0VuhSg5uhL0oFxb?P{a?fiWYE6{{{IP&X-}7ePeR>c;wHK8hP%t79VAhT zBOOS1H$RNtT4n=&zI#IZqdfI)Upze2yX{Hp>gL3}+ZnjN7c$AMrbHag9)IUxQCZIw z$s&mt$b!iY-KE9PPX%^u9MJX^ZYc&PK0=+a=T=m>)znD0G~PRR@hL?>YQ@5x?dK}w zOVq1SVG-s|6n`7gu@PF-7LF4Ae57ZFO^U(Q3=k?1ft5D_GuQBI01zqqpumN?Lv|{> zJDj3zFUXl0N5{h9!siL7p2f`yy?e(P;upfH!k#~^Q!iPl7lHUkx6DYywA;cV!X+PN zPWl137E3CAge1}{Z_SsyJ%%ltA5}{u8+-0}ILM_EU1M#(V6B25q9hSzw~Bd)n$=+sc_oinJ+t9) zcg7##ez&>%OmNNIn!L~%8Oi-5oG>&i7v@AcC8O`QG|b<3L>G*$P1dJVlN3CU=S>yo zMN;yC{4eY;slO2`zy=J#U(mt(4Aek;a;v90Hh1&MR5q8#kC*p7Du2&$Rv$rb59N>I zpDhhkkU9qQ6?PrPIynX|0z_>_hEF*R)Qlli9^}+5ePn&B=!^Plk7T}1>E7|wryN69 zo)eDPl5R#ulWASD4YfXjTb15KFu8>G<1@<8G5GK#8{Ij_opI>*xgIU9MQT7!+nOri z=@*mX@=!Oc@S#d7z(wdR3*m^J;_u|6G`gJ2+wMxVITuDUk|F~bZ{a6K%`%#kp_=>O zL!|%0>LdAt+iVX~%hv^|6p#tyyM~kW6!bA`t{l9s-+65RKC4Olt>U{VL?7gr)-qz! zbd8z+8i3z?Eead|nq9-z^9<}i;sPYJ6g{J$yf^L|GN1Jsk7dA*gWEvto|;#0{f&qKP8-5&U`3v17UoT(fq zq3}-DC=Y$UyHwiN8-WU%Xt{5plMz4{~A%(N}R zK)Z$Rx8*@?g>I>1u#LEZ&IygKgRFa|g5rnx7TExzfX4E=t>K+k5Eh5y>p6PV5=s;u zM9@lN+#e@PXJdTpKnxi)4B-Fhp@Fjuh3mhTKLq|BO%MLW#s)_-V*qt9C9(X5pt<_% zrPOTcPdOJbAW2}b(BCYhG-=|#3)_jwhHj8(E&mZ>}}rn^ZDvT|LPg+vnH z@wdRUiav~9mU0X&oZ!7#Ez`@()ALis6JwGOX6QjQ z#$^sk%%8}r|9ZKqObS6|I%!3!1h36c+VxqM8pNv|u$x=dlla7ghfIHvf>V62aU z#w_G=*s67q<$o1)$_utN3P-?${T9kA#p5j9(_K33}7Ci_l}Eag-SVCY;F zAvGwP!5O5^vpD*7d@+t|qO|76(X_K9aS3jpj~6z^b=QDL?nT{X_w`p{`s(zq8Qzn_4BW${2v$-#z^$ z@<;A|S^XN%hMF;T!kziatx2FYn6t0Q{RV{E$L#e!Ti#pVGeH%@Pj;k#dV-m^^nnS- zky`9goDP^&zcRp5g7Qt_)6YiLtr*wwhZ}I#vuASE%|2WFN6gt0LhBc;-b2GM{ksA$|h*QDev6OXYCWA-=fY;KS|g}8|R+Q z$GAWWbapmp#a(*#dpd&v1ZC8W#SA(CC@tVu6iAdE)i(AKCfG6D)rJmUO7-YVle2Pt zFy4@d+!uT~j7l{~YEst@(x`G`cYf<(>;aqUVp+3_M;%Gkp^^pqj%kATA}W}tm~M}p*ZKhm0f`-H=$X1jC>)^@wp=`>ljUcxli*FcOr&6#rs&>ZIFuw z+f1{Xhqm#vn~SyqAX6!LR%Ew3nw|V8BWP^s>8)7(jEf)2tOypS8Q9dgP>}b9kiY`_ z4sjPZD@75hL2>kJSXh_~JCOg5ljOavq$~f->`es-DBMHM7%5|d+%tKJK?xvNnSixZ zwrhPw%nd{NH;4vpm9{8yx-_9lreb7IOKFF1P0@R#y%t>L1YQBXp?1(&;PfLPk!h@PD23s@(M}V2 zu7Xr+vL&BoLZ?9{brAqW2GV$$%~I{OYhH@Pcmhn)%q(7e*|kCC@vA~lWz!9 z#!3@A*(0|%JQ*snp;`Ryv*3Fks`Lc;6pS~url3qAQTfa2t*1-%rZn%>{{&( zh7z~44+D1&naQajqQ$l~&>gkrhkvvOq2rw-`Q{J$iC0u+=RsmVVE@hHT%J%@=+iwC z2?y_(N|B)UTs-Y!?HTs^6;o$71IV>p+5S|wJeA=d+L^rBFKmJ#jqE9hId@l?%QsRn z)-RS|ch91MRaB%UniYw?GkXzwfN=ZG#kPWY8-t+)O7{=N#v^9_-vOn8?lGamzaXShqF)_i<_n#~-R3sXc0lYl5naZoz+c*x|YK=<=CX7PLC7 zYhe{_n24AQINyWrZFhU=Tg41Q zSV|ENA}Od*2rpMKF_$zYoHFig0XAw?xYnbmbH?p!~(dPBp zSP_cjXeA7@Tf696aBHpfm3N;85sXX^vw!8=fKzD+^$d89XNTblh<;FGa<=Pru{ki& zX?qJsDdJstPW@q}<$Y8cf%uK?N(o!@b?DNlB@kP!jM~KLi%T)Wxc*g#CG*u&EQ~d# z-D#jb=Dc5%D6%W|cUPq_>ropeDC?XYB`LCtsKeq+0CK zp%vXMvrI^wG9E@NV}7n~@KT3(mHt_n+ffO^ppumt6mA%uGCjaL75QE1MuGl~dO@U+ z|DnzF#=&u;jlpxWZ%=|zK?=$Y^p5(>`)HB{`j|QoC7p&H1mc!PxQi3HWK#8e8yB{m zFV40UC#@*vpe}D3!_p#4=P}@(`Ph${XJGd zre=Pg)B*cJ2lzo#>qTVt1p4N8@vHrZ)CqfmJ|~MTw%MrciKSe|TlKMgfw=LX!D>FN z7tr{N$ms;FkDS`}PMiBC6ybm$8P8{kteGF-US{p#M2yW1H~$C#dU z!OFsOsTHe2JNu&`BNyDeTsI?d-FiKn)uWZ#-?tyf&5X=Z?rf=!6OQJg`X8%r9{ax* zeG#H{AI)-gqGzSDU$bYLbq28ClzKehhL!B6?TnX~^2c0!9XiE*|h^C_rVW-2Fzv~b64L@)dVylfa8Eo6uyYzS7I&QX@FF0iF$67sZU>39X zPP;-Xvyb_ty(~v9)rO=D5So-EGz}?gV{-0bmEit8WD>FjcH8H*DmNP*}BuwFN@H4R6exG)B7h2-Z07xeb)>>1ttSs>VT04 z>DtpGa2pmc8*Cl3K(QuZC>Lbc%#%}}VURdLubgefpxhVd<9`)v0+<;T`mbU^{U2au z7E%QM2UW>J25M>H2QE<;Qvx?C4areBIt}IInDOw~eKQmsnxN|H(pOeG0na2Kh*>hE z;Z>9$)O++W9G1J};1L0rNrA_4pU>+9I)9XMW*Fw* z{_ax;jj^o6crW$C=#^G|$Um~gh9vmBubi+4Et>gDy2AMNjvgnics6gv`JvvX?CJDX|)tvskx#sajOaEV$=!x0PDaWf1n z*L-iE084|KZ=eCp`Bs}~7JH(-NdRgLo}|TTf-i!q(Eq^spt|y5?>}Ah{!dp6VJTo7 zj`Vh`V>MaT&#$Dl82w+!75?4w?D{v?51rq0*VUD!*6@74A@PC2Vf^m24fRAVw)W)< zMv9f2o4VV?_#?4F*B9)Q6C8dB|_NkF( zBXZ)EtxGD+pUYV@fzGm(!v<02HcU+jC#`_+Af6H7Y$RNi`kiBBm}fEx zhCfMYXb?H5|2BPEtoGXd<*EsV3b`-3DLgh2?WNI8>1wA`pB?p-Y$Ys_IUStAS$~5r z|D&_~!m)|@k~W{;)^>{VgeUfU7hkxwV^?f$k3BKeA^&mEPh{O4t=oxL5x7H5ilnaO0j#`IYm zQS5p*(>4s?oKC$5)Z$D%iD79LLvv^_iU-oDO{;1(ak2v+X|}eSjn!$SkIu&;BU_7kmc| z4~5mFD1FF%`rF(htmEvPBGXcwHppb0(cL@f*v=<*-Jd!L1-!E<#@nz?PpA?~V88zE zQ?)7aCHFijEvKQ! z?m8C8x}b520(rYywU+^%>moPIQC+xmC`4`?1XQI&U1fjny>jfohoZV=beBi8bq2)h zS1Nwk^iN2QlC1b?RHb;i$63NeT}QQL_^GT1?>`TJh5Es;*evyxu6W z)zVz__cn>y3H2mFPpoBqPk>2uOLPQD-OybMGtkUy0YN4XXlFIVEdtjAda`#59n+3k zMqWS!t~S`OG=wlnx>Y8J6NV3GY8jKtXpMa%BV{YDl?nItD_0Idgo!jrq7U zR(tN|fMUA{>JxNV*?>YEkKg#dZvve(AHjWHc}X*D4}bI4^9&K$bhZlZFMHPebR{0` z-F1@gFx3#aGUY%0omtW;fwbwHeJ6VK=7+Q=N7QC>ZQSmW@WB4%djlma?Cc%zmUCTf zwxL`P>H@sCYu+IxI*ed@6_P^-FvJ1M>g4ZQXfom%N&S3OHb!6dxqW9zDDb0!KeCcsU4RnMcCFA%0 z@q+S0$Q*a`{G4H6%kpe}8RM4>{!A1~#ZR^j+sXQ73*KMkXZg?r1=Y~*FcfU-(LeyM zk!{O!d0Dir;}~{_HY4H4jc)&)cR4D`J??u@aMJbMOLV)La`(iQ6fr|cCZ`=qzEu%T zD?`4lE>^50T<*1$jIE7BkRkGDEjR`An}wkV&CQfIIho%qd^u*nB_poJ%3`RIAnQ~= zaq?_qq&)?_(E@MX#S}sv*)H8D9XMpWGcfARfh>Pfc@|Euu0l11#VESBjxKnas$rXT zB!O!^D7SVuh^u{9t81B*qk>vds`Q5z{*S&mT0=vz1evI$wnyZ;n>#@&ZEm3*tLsTl zOIPa$3h5!`X*Ie2L5OT%_T`}^q?eP?2&h#yE{~S+&%%;xe9kLB_Lq7#H6RlsL%S5~ zx*(G@9OKe1MrC4H0h^vyTAoskW(3*?Ugc{pFYf%V90V8c>05yGkPGsVv84b*V{>K< zgLkKDu`o_6wq^6cw0>6RXu5{X^vI_2pS&!EN%yc!DT6-9ERyC(*(5xT&Q)ST1{C3Ypt6HoF`8 zqv|ls^lKDV=!JOc$S@8UU^?iE^IqAs8-O#dfmt%#p8lY$ zDa#j#PwNN1Ov4AI5E-vg$1iroPWJ+wy(5tJSi`{VX;*lGmD?ML97s|ImR9WPPnc^& zpCKvd4>(ZY!Jit|>A#Be^-)tq#-!3%a~;9n?ZkrJbMIsff5SQ;lm2g;@rr+Pbog(Z zfe!QkpM`->B(T7tGCV-O4SSN6#(;wQ7?PZpUvq2h0U}_15;&6dd`5=Fk&7|&w2f3V zb56JHpp%MD&CGcbUk-I zcJBEuy>6OJ2|Y3UyK#>>?r-;G4MJf<$+-Tusfj3zI5rgb6;}f)7S0D7m$ZJ9J7rOD z4Weo`cGf0P88>tdlMJ13oh`S-Q^TOFs*)NAlBU2`3yBJlPhXT+vdiy~Fo^*&XG)>< z5U2#&ARK7xE^u?HF(}NV+yBmwJdVz}&lxm~id9>u4`A`=^I8qNA+!!;E1!<`5M5U? zM%ZMwrY^za!fOPcsv zNe|~SJ9Y|6HxISe*2P5r`OSFPs(gJAF3GibbZ5h5IYi1OqZ3>&5|unE4?^Oz#h*(~ zvpiN)sXu{?*2!ySSudk($!Y{>;`fOw>ycGy?s!6;mfix%GjuE~N60Q!#z`bSR`_$_ z{G3OyOAEDi01;(2FTR?f1ATgNp1xX)VV*c?5H4zQ@s6xRZ?yQwk9 zL{Il9+?y-zxMxl5qev$wfv=z+U$A5ntGSY{r(8}#tiStr z^9b1g(#p<7t%ViJ-Cg}Vj1QS2D?jK7&EzV?h`+K@3mP;u-|c{|ht=crR7$0L?YXjJ8uV57+qRXB-hJ>Zi!-_kwY#e2n;Z+vr za7f49jiyb#c0~E-n4L=%t~6_|ATy|QJu=7x=Ds>LXwt|RTThd+sg^^GXhe2ROUEvt zYOq3oJ#Z=R2gNrVWjPMswr>FI!+l@D#hFqYycU1X1a8(<9#d*>si7|pzujnfYwm#C zzf^d<-J6WlToDGy+v6FtTL>7eIM6W%KFygfu$IKa4QGv!dmu|#yR^)oX*3-M)`G*D zRB?*!^*r|Y`Um@VE%H^C|ZipnZ%iqR6Kt=I5YumUk$PdA+(D4G&R_@7UYNuKopV|K8&N3$rEI$ zzxOj6MGpXOGNOc1kpd(wYguW~=_Rv0`*%^jj#9mF0Laf8u-6qyDNLH)VFq>8qEM7~ z2X{oQ5-viYn`p;KqfW2yKI)Meh9IN!qyEmYi5l4vbOR;zF_BLKBDmeggb?ToV0nTz z-|+C1#Y%;9T#tN>A2HXE!jcYiy_Ux(&-iYF#OihR{oZtkK7Cl}-hg#zQ{q%GB((ka zV4s?{>A^1snOky-2kD|dcV}MCgPjGK{PR>Q27}HXI83Y&SV>5l7i2-YNwBcmR9uZBv zY(?BhO_rmw=v4>Yf5aECOmutQZ_>BQzwP(9m%u3Bp5?Ia7bayAmCymJ1grRz@^2rn z>v6XFPyzPCZkEanFo!$A0|cp@b~AK%SUUVrCde26Lfb6|YPJxV66D4C5esGHZl8-O2a zcB&GUgIeR&%6V|rzkec`&W{tka=q!14+>ev*cbGFbHMUScPjuxtsi4Q@-NQvALdZy zA(>;*&}iw zyBo3jLgOmrl3<)<^zwp`Io;%q*!pm#%5SNY=hp!7d^SP%xVkN`$1AE0L*G9vIfs(V zYdP|Dsmscv|8DSwmz~C#*t|Q{E0}oaci3aJS;y|BB@NBQ_cUN~K9aibwbDN_1c#I9 zb3{9eNe%z$%A5giN?E{i*^X=%$X6og%3mPErps8Lo&JQ?{o?+|6yvn!!3tUOZDdtC zpQt8;zOX4kn24q>hj`3RQ{j^A%TL236f<4(K3cB`BR&2o z*44!ReO;5XvTT(ozh@|>M0q`m>2V%>9)EPQ6iKQ!`)CaeH1iFuI{Vusprls>vJieXx5!-U3}X&K%FbW zq^Yr5dL7%CBpy(n1#wkX1rqO|#Z?~ymE{z-uud@4exB+Rf_)zeKGEO?XFJ^Eieum# z>2}_{eI&e~bca%R(N#T4c26Cr>zjcBjHtTYv$_~CfML+ZvBo$zX{Ts84&}~o^1-L< zG9hvbw62k2H(|1MUjc>Nj*6o1@~7^fedv$WvQpz029fKo|B;oQf<0k#1PBOPjQ?ga z@PPyX%%~xQsb;E9jj)CSkPhmHF6b6TDJ&odM{3{!8!e-DgP7P{Cf8jqTig%V9;Xbx zl$%IzZ=6`wJxE;2*!&2na5&XaG+3yZj@4D9vvi9*qUR6Yr8E7WBu0n!z~8A(XI0eD3kD(gV7Y&)WCO z4d%;0_W3PqG{_K*-?Wjx^kSitMGt<*Bs5AM+EC<$CAM&Z&VSGQ9jlTd!&xPYY8bv~ zel0i|>1ILw{{V_Wb-%jDWFEtpEOkAbR1PJ9$*pm0373CSEMN*(1oA0ctM=KOhO2+L zYMsOh`8iw@C_0q9R3Z11oCqvcE;?DcNR@CMHwu`+EEgUPBd`UG|I+^S%qec-*2w5Q zcWPG8N2}ouqa-{J6_}~~v-kq;jg*TeXvpVr3HJrE&-t;liwtu7!31aLyYWdw0Y%;) zGFrw2pMWj-FPM7u5!2=JC(NDUcKI$ZXV5?3!FymV%kVmZ%nwjY2MDcD`jpuL006QA zli@}jlWSNvf2COqd>m!9KWFwavy<&Bo0Kl4Wl3ARX|f3|khWV=npfMjo3u0yW&5B^ zb|=Zw-JP&I+cv0p1uCG|3tkm1a=nURe4rq`*qB%GQMYwPaSWuNfK$rL>_?LeS`I zYFZsza~WVW>x%gOxnvRx*+DI|8n1eKAd%MfOd>si)x&xwi?gu4uHlk~b)mR^xaN%t zF_YS3f8;VTeRCqIGc7kV1C0Y2EuPdHk7Tr=AwAQ$#d_UizjbMev`kK>`PXTOwZ^2D z9%$Urcby(HWpXn)Q`l!(7~B_`-0v|36B}x;VwyL(+LqL^S(#KO-+*rJ%orw!fW>yh zrco2DwP|GaST2(=ha0EEZ19qo=BQLbbD5T&e;rn)`AlY7yEtL0B7+0ZSiPda4nN~5m zfA#Bg@G++9U}U;kH`MO+Qay!Ks-p(j%H||tGzyxHJ2i6Z)>qJ43K#WK*pcaSCRz9rhJS8)X|qkVTTAI)+G?-CUhe%3*J+vM z3T=l2Gz?`71c#Z>vkG;AuZ%vF)I?Bave3%9GUt}zq?{3V&`zQGE16cF8xc#K9>L^p z+u?0-go3_WdI?oXJm@Ps6m_FK9%;;epp{ieh5BGOn|LS(TA@KB1^r67<@Qp!Vz2yF573JoDBug@iP zQ=tr2+7*HcE3(5`Q%{A2p%psJe>B%3lQR>^#z-QI>~|DG_2_261`HHDVmM&*2h2e| zuG(OXl?228C|G32{9e%Onc=sVwIVZ=g2{K5s0>v2}V& zCZi1_2LA=x)v|&YrWGaHEe3L=lw}aSiEdWu&2-C5U0O~MpQ2Hj-U8)Ke^S`0Wd|Xy zOt&Gc+g8oC4%@84Q6i;~UD^(7ILW`xAcSq1{tW_H3V};43Qpy=%}6HgWDX*C z(mPbTgZ`b#A1n`J`|P_^x}DxFYEfhc*9DOGsB|m6m#OKsf?;{9-fv{=aPG1$)qI2n`vZ(R8tkySy+d9 zK1lag&7%F z>R(e|_M^wtOmO}n{57Qw_vv`gm^%s{UN#wnolnujDm_G>W|Bf7e}zsmgR@Nt zZ2eh!Qb2zWnb$~{NW1qOOTcT2Y7?BIUmW`dIxST86w{i29$%&}BAXT16@Jl@frJ+a z&w-axF1}39sPrZJe+sAtugKOG^x537N}*?=(nLD0AKlRpFN5+rz4Uc@PUz|z!k0T| zQ|Gq?$bX?pHPS7GG|tpo&U5}*Zofm%3vR!Q0%370n6-F)0oiLg>VhceaHsY}R>WW2 zOFytn+z*ke3mBmT0^!HS{?Ov5rHI*)$%ugasY*W+rL!Vtf22(`qS@{Gu$O)=8mc?! zf0)jjE=p@Ik&KJ_`%4rb1i-IUdQr3{Zqa|IQA0yz#h--?B>gS@PLTLt6F=3=v*e6s_6w`a%Y2= zWmZ&nvqvZtioX0@ykkZ-m~1cDi>knLm|k~oI5N*eLWoQ&$b|xXCok~ue6B1u&ZPh{ zSE*bray2(AeBLZMQN#*kfT&{(5Tr1M2FFltdRtjYf77#;{gPbHOBtiZ9gNYUs+?A3 z#)#p@AuY)y3dz(8Dk?cLCoks}DlcP97juU)dKR8D(GN~9{-WS|ImophC>G;}QVazz zTZ6^z91{5<+mRYFhrQeg|Kn=LOySHXZqU8F1`dXWOJ?NViPE%&FB1@$8!ntuI?)ge zXh|#Je>;xG^n$h4F)g-P4WJMPQn{p=fQtw0)}uk;u*&O2z+G5?iW_=1kTy(!AJzj} zde{a9WHY+*SqJ7`={VTi)3NK|)*W3P zUT#5a$D6oyqH%5zjdO$5ICHx_V;1Z)4A(rTe-r?vZ{{r`HnxK7^fMLS1{;H{o<8j5 zhz*F@WkKQmDI*Q%Kf$Mo!EpQ)=HV^lsj9KSz->ROVIrXAI0!Q?WUosf8t z6CR*rl382^sU3q@($L~EC(AoyIjS&2(el|I$a*8oAtqGQsf7-UuhBCOFw(^b&bol)FWsp15Sra3v%&#w< zU?v<+GY3UMPW4%i_QshmHO;}S6W^rrjf`>Xz*!kSi!sV>mhe(I=_Zxmz&E1>i6=yB z*_X4M#ktdNg7_G}MVRGQ7^zX=+mQ}1xtg7JN9E(QI&?4}=tP2#z2<7N%zf9rxzynL~!MgNpRvXaU69c*^ zX2(c?$=h&o~Fvv06*{JdsM!gF$KALcW(}@Q&Alo`@3h!H3j^@5rFMp8l z6-q!cb?1iS$oZfU+}A2<)&2Zoe?fDkSnbf=4>qd%guV7zM1p=amds@nhpkK7mRJlbf9%rI&?4ft zd8+RvAYdk~CGE?#q!Bv=bv1U(iVppMjz8~#Q+|Qzg4qLZ`D&RlZDh_GOr@SyE+h)n z%I=lThPD;HsPfbNCEF{kD;(61l99D=ufxyqS5%Vut1xOqGImJeufdwBLvf7pUVhHb z`8`+K+G9f9n`J&Yz^XE0;ErC#SR#-@%O3X5^A_t2Kyaba-4~$hvC_ z#EaAd{YEAr)E*E92q=tkV;;C}>B}0)oT=NEeZjg^LHx}pic<&Fy$hApNZFROZbBJ@g_Jp>@Gn*Ve}$;Vs!-LSmQL#^ z6Bh-iT+7Dn)vRT+0ti(1YyOQu{Vmgyvx3Tuxk5HG!x2a+(#>q7#Xji%f&ZxT@A*$m z8~z`DDl?{&1=gKHThhqtSBmSpx#kQc$Dh6W76k!dHlhS6V2(e^e}!#3(W?oQfEJB+-dx zZOV?gj++sK_7-?qEM1^V=Sxex)M5X+P{^{c^h3!k*jCU>7pYQ}gsEf>>V^n1+ji40 ztL#-AxLjHx42bchIx9Z51CG4Iboc%m0DAfvd3@b}vv4%oRoYZpZ*dW?+yTcdu zQlxreAz&6Vf6+BCQ8v!rg{Yz$`Hf$tB*WdxSPHMMkJ{&p0(lyXx|^X_VUQBdh9)?_2P1TViiYqy+91$zg%3%OjzWyY= zX^f7I)2-34bDVCEhECAi^YqS9x@(kD(Bto;VDKfgIo-)s_q)d2mr4O;DTUTgjOe4f51kd6T9`xa6_AUP*N{jz%! zZ0E!Dqq}JlfPZ2EyGN*EoPHJ^rT;z^0vaI03Z(WcdHTh1suHxs?;>yWLj~Gle~*Cj zSWq|nUE}m()bBZ1`Rh^oO`d+Ar$33kry+En{&JjrML}&gUj3pUFE58(t|p~g@k3p& z-uvoFzpGktUMnQ6RxDA&ibYl_A!{@9au^_fB@6;1XHLORS}C(Hi&J8=@>Kw66&QJD z@w>_I1XJuBW3_vn?f~bbTv3_JfAicE?921QNo!MQiLHISD9?+dP0BsAK+yB?l009u zXXMOteoGX;?5I|RG_v#Bf~l?TPy3zGkT`N>WlZRa=k7Vdbz-66IQ979fX!i7Wen@l zu-oEcweu$76ZXrc&JWRf!tLRg2JqNG{;`-H@L`KHfgY-Lve@vsPT7B0@716|Z$Z-Z{!WV;qGHV!`h!S>b)r zZpc`9J))^79ey;7@-=zZjys+j=U6maKhDddqZ}XQffIbFYn)R657nRGEG#j`M-Gni z4deWVXcr=HoNok4SKTPTe>pVDw*WrceS&Wj^l1|q_VHWu{Pt**e2;MKxqf%Gt#e^J zAKy{jQz4T)LUa6XN40EOCKLskF@9&B?+PnEe(xB+KN|M<@$&ZP{jM;DemSl!tAG2{Iisge|}6`>*BENm!G2E z!s_XsaU zit2`a&pfn!ggt)wG<~NoFFD~p(1PRvhIRZaPhi})MXmEme-%O?Aw+GxB}7gAxHKo) zH7d=m&r6ljuG2KX{&D9ANUe9Q=^7yych#S!-Q!YKbbka8)p==Am-8`N5_Qz~j7dxL zQeaeCHYTma$)Fy}ORKS45sf%}(j`4U=~Aq(!-|ZRRXvQijeGJ^%cq3itmW;FI)JsU z8k4pNmCazDf4ff=bqwS9q)y8?KhH}MpVTd^>?u+Cs!&l|6KH<*pikOqr$wK%YZ7(> zz%vWLb^+m&cCQ+h_MDo+aXmPW7CD|K$-d&cg$&GVPEi#)hPjGYx|SBxatca)&Ig?* z6~uiQKE)tF7l+ci4Jve{^rQo}1mB?m;{w?j6>1xBD9F z+2p#YP3U>vfnMicQVHdhK1yDCfacJHG?$*GdGs93XO$LkB~?nF zAfNOoe^p7Rs9JiG7CM&Dd5!=ra;zY~qn6HhG|^&58(rYoNlP4qwA7KN3mvymz;PR0 z%5d!IoDF1vxVxNS5wG&fEt`JYIGi> zi=Fq;YUc>8aXv_wIKNAmI$xs8oUc$5M((w)UFEdS6{7X7iz)2tqz$eebh#@<&91|= z(KSq0xZX>fTn|!v{~LlTjaOXR{3kxDZfD5rHpl>gbmAU@|wOa$t%grx`7}nA|ePPsN0Y)k&2=Mc4?uE@gW0-f>S_2 zbO;VnKt&W3k$KKdvZh@&*WWKa@7#~`b#Kuyw9kqdj%CMuQ9ESPc-)MbM#7}YUL)ZP_L{+siDWcU?e8%n3A4Vs zFYJpNeLjn2bT>CI3NCJi7EH$DX3S}9p>0NY#8jZt#!W_KUc?R> zk@Ky-w6=+Da+_s0GJldlF|P?(31@{B7bweeajQGYky;y%9NZK$oyN7RTWNn&2`?k9 zJytjwmk||M(3Z!M&NOYwT}t~sPOp`iw~(CAw<+U2uUl%xEN7WOyk@N3`M9ikM-q9| zHZC|6CJ8jAUAst!H<<<&6(6Zvbpj!BrzUo!>VHN3A3vo$EF5-6b1Q~ajX zENB~lhUA@|>x6=N0u#cfv&w(qgG`^+5=HoNur`2lvR~b&PjumO|P8X;=d`c+z1YJlY7&H@Dz-Rts$ zX0IYE9kSIlqGZ7utSx^+2hOEC-eXviWZXQ9;$Va+WlHlU%y|f~w(|)o@(5J0o|3MQ z2O@+B<@r*H4*65)(r^JTq+<*b06XMGclsEElst5dEfFJ;AQfYhRt}O0CVKdGh4Tk3 z-(^-{kukZb*3oM$ZffpGMs;jtk2ZjAsn%mND4R~OS73JDbj^Q440{oS&4<@VUYMIn zc0xxy?FE@$J_^n)b|gY+Oj;8Pk^)6$w9nbnMms3RSr6q(9wP_)v01|=P}UbkXoS_1 z#FCl?>&9cjCHOS!yEJqiGd`83Nj00{X6dHFN84%)I^*MZ=*Ihw5FxD0Y zSJHV{j!9v(DT#k7##q~$87Dig!k3EiMO;k|9XhYz8cGVPukGe$N5@yNtQgngIs(U- z9QZ2c^1uxg$A}#co1|!ZzB|+=CrR6lxT%N&|8??u1*Z?CRaGbp6;&#}$uQEzu(M6T zdss;dZl=hPN*%ZG@^9f*ig-F9Wi2cjmjWEC+i?dU`nP`xymRwO$9K3IY`|SvRL^9J zg6|TlJNEL9me$rRD1MJ|>27?VB1%1i)w5-V-5-nCMyMszfCx0@xjILKpFhA4*}fl9 zHYZ~jTYYU@{12DS2OXo0_u+ot_~UfZNaN>@w4Es$Ye>i&qhgqtxJf9xi6El-@U zNPeQ>aXcYVxOUA--x3v13e=7+%#m@}QuMTjN3n--=-{@rNtyYdYS@LJ(G?*np*HIL zbUeo)+l8N#+F-;^(8w>i8Q6til8Y^NG7_qa*-n2|4}(k<-HF~R0v*cP7bxlTWNJ1s z6#Rz!NCYesAbm(}4qp%-;B%AF-LyS5Q6@Q|V&Y2ar$uWn(?UstqXy;5$ZOCC_?L$F@o#dk--?Co{)CGEP^73Kb_^>`G8sAN) zM@iNKQLBj>QAcHjIw0!1l6{UYd;|bA+CcC#3IGYysWLa4!KA}CsEV#c)JpJcF~NX9 zmrX2WwItXv+s%I2>x#v)y%5xDSB`&bU!9COR@6LwbI|OQ&5mf&L^GGZnOXEOLshxO zs;Y;ikp^M(l-^>J z(o0NIdbt5`(fTq>p%?cG;%aHXhv=-@!20#xf*q)++kt8IJ5cG{ff?Sy9hfzQIroA8 zN>Git>3xOUNhe8nUspSV`GL0DK}<_w!3gRCwOvD~m+Zn6jxTMde<_?egr$S1OySh6 zXsS!0Wh)wJPX+xd11YQ=Mq7X2tU;U;Xx|ObfO}%y{pchi>ryaM2zAy50_$ltt(ew6 zh#CF@+U74D#H@hdQ=dX_=OChf#oerWnu~l=x>~Mog;wwL7Nl^Iw=e}~8;XZ%co+bp)3O{Mryc`*3ryyIC*S%Zu;8Y_D3bFAn%8NTYv?y_%Q4zR-Dv zE(Q*~>ec+JSA76q7D#_wFR&HI@z>V`9-)xr*ME%7~<$Ykd?U8 zuZ~EqUe&AlGDqP{uUvnavy#q%0y2VKf%UxO(ZC2ECkuzLyY#6cJTru6Q`qZQQ+VF1 z`jr8+bHIwcJg}=iko8FEDt(bW8pbOr>?{5KLASE=YFFv&(&IM|P6@wK(5#jhxh@Pe z7u_QKd{x@L_-HM=1`rX8`BDds3pf+|$)DBqpXrDP>JcOxubC$Dy60 z;8(mfG^6yXE(+N*UWMW?A~?H-#B7S@URtmlHC|7dnB!Lqc0vjGi`-tNgQ8uO67%US zUuhq}WcpRIpksgNqrx{V>QkbTfi6_2l0TU zk5SXdbPt}D^kwXm^fm04^i66Xn0`pLmnhX(P0|TezLiFcQ{E0~v*cmmAR2|PETl7Ls>OakCexUmie z^yDw3ccuqd5(wV_6?YM+egsV{M=^n{F2a}~qL}DfhDok9nC!X$C9WV!U15~DF2xl0 zYLvS#K!rPqsqS7(b8m##ZA(3F3H0v&0Z>Z^2u=x*A;aYh0093Lli@}jlP*>llBWoh z26`qTwXW8By76umJat{FC`H8^K@=20LGUu&PPftQfn-}R#FI^W9e-k8;IZGoXxzI^ z8QfCba(CUJ?bh5NiBhFyrjpo;k`}RUNRzb0n;mJrphLl}?MBw!ZA)#b=BA++$<$N1 zM{{SV9&BziYZ^cE?XK1=*pBq-+)^B>n8>I&WVJ`e@>#4mHnuhzUW)=S^{Fuzz4!va$`vL}5lw zRMxJqUof@)jOp4lW}kooS{PUqJ^@fm2M9!-I|6F~008Hc5mp_OwRhju-BAmfjCGV5h+8q93HYw5uy}QM_|d8m%xHt3D{+J7m{e#O4`V2j<#tM zr-_uta^2Q+TPKZL38bS$>J__n)1+zBq-Wa3ZrY|-n%;+_{BHn|APLH8qfZ}ZXXee! zoA>_rzc+m4JDRw#Hi1R(`_BX|7?J@w}DM zF>dQQU2}9yj%!XlJ+7xuIfcB_n#gK7M~}5mjK%ZXMBLy#M!UMUrMK^dti7wUK3mA; zFyM@9@onhp=9ppXx^0+a7(K1q4$i{(u8tiYyW$!Bbn6oV5`vU}5vyRQ_4|#SE@+)) zk9CgOS|+D=p0Txw3El1-FdbLR<^1FowCbdGTInq0Mc>(;G; z#%f-$?9kmw=}g1wDm#OQM0@K7K=BR+dhUV`*uu!cl&ah;|OXFw^!{Y2X_bQ zcDjSDpb83BAM2-9I7B~dIIbfN_E3;EQ=3AY=q^DmQncV2xz0W-mjm8_VaHElK@EC- z!ktWFouH=5iBgisaA1U@3bj)VqB)H4VK|{N+2-(JHfiJCYX>+!y8B2Fm({k0cWxASSs+u_ov64=P?sTYo z&rYDDXH?fxvxb>b^|M;q%}uJ?X5}V30@O1vluQ19_ER5Rk+tl+2Akd;UJQt1HEy_A zDoA_jeuet!0YO{7M+Et4K+vY}8zNGM)1X58C@IM67?0@^Gy_2zq62KcgNW)S%~!UX z1LIg~{{L&cVH^pxv&RS87h5Dqhv+b?!UT{rMg#O##tHOouVIW{%W|QnHnAUyjkuZ( zR@l6M%}>V^I?kADpKlXW%QH2&OfWTY{0N_PLeRc9Mi3vb*?iSmEU7hC;l7%nHAo*u zcCtc$edXLFXlD(Sys;Aj`;iBG;@fw21qcpYFGU6DtN zH*Xmdk{4fK0AKi6FGJC#f0@j_)KD&L`tcGuKP_k_ zu+uZ@Sh<3$bA}GmGrYql`YBOYe}rLwZKP!xrdrur0ib3zAR%*So7rZjP$|`v$!nA9 zxOQ4sM|Is)T`iB$29KOE-0_Y!v(GZKhMia4am~e#u5PJbJTk5!5Jn35E$W1AVWB&z zA{r<8tP)wo%Vg0}o(EZ}Ts5eMgW$E9nUDxFyhPP(s8$YB7)%~lUan?sD~~9DckP11 zEa%9&uY)hvUwxUwb}pf|IT$VPqb9AAiAuw>G+8N86Ovlm%$~Fhhg1!#<%uJPW4P+L z>rOa{&N2gbFd3Fh-nnA8lL@IrHd6K33HFYag|7^pP;EZ&_CU5|tx*P)T5w<-hNeoB7VAth{E$^ zzh&!tb9x@TA^<6 zWYl=|`BSI?aM#~0G0T^KK!+74^cJ#Nj`srvw<<6EzM$Kx-86sp4;1hc2-blI9c0tmCMY}Qn=5b(4Vqv{|sKKb)cXA9B?~> z#9fzsZ29S1Tr62*LHahw(?8R{AQudS8<=zg^lz2qD}8im+_uhWqYUr=fMT#sIo${8 zzZfe2N&j7)tPfNL^8Z2}6)v8;x|<$fDzHr5?L0g@AOmYTwm%3~HQmw+c~!W5LEVM> z2|z;BF)jd7U&jQ0%D8~=0et;cR2&d~)H=6#Rr*B(V9$6xY#V}Z4=>PWem5wViJ&4B zv3xeU=0-BSSJgLq4Ssb;S7t=xC1%@8T#c5w$= z0*}ik;4@vwq3Am7=yuN-b_|MEpaRpI;Cvp9%i(}%s}RtlP5ojEwsLfL7&QhevV-Ns zj0eq<1@D5yAlgMl5n&O9X|Vqp%RY4oNyRFF7sWtO#6?E~bm~N|z&YikXC=I0E*8Z$ zv7PtWfjy*uGFqlA5fnR1Q=q1`;U!~U>|&X_;mk34hKqYAO9h_TjRFso_sn|qdUDA33j5IN=@U7M#9u zTvV5J{l0zdjRWGKB8J3Uz+|(f(HYHAjk#NQ1jL9!uha9;i4YYO5J$mewtTo9vVtPT zxqXvBInY?m4YD)~h~q$Ax!_EwZpqbZI3OP3;=4xaULDboazx{;=E*zl0g)CIxiwU0 zS+taYYlIHHMHZAe8xkWHvSjw;0&`NOTN%Xcr-ivm9Bz1h6ny%66)ZjF=M6S}>=v4~EuG0F; z50<8 zuJ7@5d0V_2pQVkF7Vq{{!dIm33#3Ft_}G2)yjM)!d^I{4d6C{M=mM$U&yqhi=!uOq z^+sms!NF^^FO?LLY1%(UAAuAQ;Js8WHnK=;BI0?Gj@F^p*@W>;sZ=u3l$xf8pzH;I z3P)vOmA?n#aMPBi8^%0|sj#w@`5rIzhQ!tSbr|=tr zz3XA)gH(s7qlZqzSnr3GpT_7Etp6(f@@<&&Cgd6@O_{P$>oL!s`$Ftx@?LJr&QNaX z8kwntH#$vkYg|R22_$?WFI((Ps;mBgX=;jxe4dv2B0W9@Ytx5X>gz7C*}oPKd5d(e zNI!)2=dpg8p7eD2T72>A&r(Oc#kZr8Zl0T=_oWh8{A0N9vXFPx)*^lID7MGYhmW53 z!69FY@je$)Lq+<@3s5PVD$*r5``M(QjgmT^@OmO6-sp%gHc}rSY5JLvw`8Gz=TflG z&)tw(+<*mIXdUgu%{CxCbK8#JowN2@0SO=M^#R!H6?`{v`CUe5FJ?SwyCTwGaWuck zZrbd*cS97n*}$HSL^o`QV`u2{Me=!GI9~_dUxVbO7s|jzu~fEkS2;SKy+&74sr^v1 zSfo!g?rt#d&g0|P1t9ae)DZ7~4AaMp^qVvE1qqxlUZ9nHsoy&~b@Pi;bSxIXMqg&h zucX*B)AZGlZ<_wNNMB2M8@&ts^)Xsm@z<+UH@_KAm7Vk&{!iU}$6y2}y>=s3q`$h% zKQ|De3gWd_T4=Rw*ODsRR%(-Nn7U+pH|>$_UfL(yBps0LFddieaXJBi>k?^{mF+lL zvMtd2WXr!S_d)uoY)gJo;16IEvvuH(Z&YlEF~4MtgVERw{mtdnP$YGQLX5QNiKcH( z)87Fhz);ga;3ro8{wMqZN=5qDvS|E7)4xm6|Cyb+fwKtysRw&ATYU!+B2TOXK$*G3 zl~^PtLwPV-6rR$Fz;;o8z>*(s7WJjAq^m9+Eguv+(JTTuX-2FlipGi#>xbCfU@qZd zcZ!5pBz#h2ErNo*n((t*0g$hCrXHnm|i`@X6!d0j(RK8a`Hw z2l5S1eVl@8los!kPhF(7@ijcCcL%PBB!<=~MKK)m$2=`T0Eu_#R=NXIH=h{{`4iqL za>{Mu8oi!s7Kf(A;TzGAKje#F5l5QETXFpg?7)M8D4Qw*a~?Z-8SK4tke9LDVAp2x zFf0l}5RJ{^1U}<`@`|I)B2%(-WLk{fsNVS{3NYNyg}nR)ue=tyK_MEWlVVgDvV8=; z&C^-g=a&0t>2a|ceQr0P|8{y#_POQ$^YjVX=a&1Qq|36;E%!Nkxz8>4U!u>;KDXTe zI(~qWgw0KJDS&EAzCZPW_^!Tj4^T{T!k9N#2;RO7iBy{i;&QUo$Tz+nfE#GOwP=o zzrTJ1Sc55We021t`blp}YoGj;%5y1uf!uNG{2Uc(N@c!)lX% zwI3y3q;Kp>H=-52V;i3A7>>%(TwkwPYfo4kR?qm|#C16kwWU$vA^EoB6NQd%bM%nH zh`l&oU46V-HClA2e;$PpNH>BcwCIK7lE8cr+NK@KmP_V`PLn)Sf8Dbz3|Fu5lW zrRhrFHeWUO$ciK|;QNMYU4B z-{xxq=2gh0MJ_>CzIO%I2C`dQ0}U%zLwzhCD9eXj_~Pck%ya+e`Xnf;1j}62O+JMJ z**YJ(mx~=JE+{p9z;naHl6M^@O>uaJ(zL_pbbfg95AEkMI{PQrP_-wu~We zK)#DjC~RTz1jWl>>J%&u_A8uVgllhIG3F|Oh{3HPY0BVyFRviH@lP^{le^7F7aAk6IX=QUpX>4UkVQyq>WpXZK zY+-YARa6B40RR910F6{zR~uCn{!U3VaS~cep_D2%4T>QoM5x6GZPijL*Z>u~X{ou@5sm(uh3RbluVf(&O%!e89(-`|RxlHTyT__; zTIpHtPB288^%``Bpy}I=`(B1HzbS#S^Q*EAx4u+7Zxc(*~e=?kj zw+4xz6K8dtK^H?;L)FMr!#N6j)wE6jdOhsj2+pHdM-MJA^fYHUW4l#<(U*c(G`yvv zwG>!)eOpH#E;0lxhZh*mH;kJ6>$aB=Q(^iUP8ycui3r|Rf%`B(*o|DLxmTuAG{kib zs-%KzVslaWt>u!4${j*dfuna=Gjlf8N|iUv73NnM-UT zTEjavytj?P-0dxp@$d_Lz%ZM9fsYs-W1K#&G34fI__TAfhMC7ZuT%8h5w2l2Hy)_r zi(hyCO7sSXNctryYRD}=-T5Q&9N#|6K1C===&!c1lG_H)C006(Efi~5tzm6w3-&8Y zvWvL*6I}EnT7O5;Fpr0ndOrs0=ZE;E{$`LQJ%u*f!o+r*z$5x55|i`<+WrAhO9u#D zCi-vo0{{T_29x1N9Fs0q7n3fjBa{1*7=NHvK$Ity1jV$1fsl}GyS*M<@0z z#ZpC_6H8jHE-TcOH8ok&$_(dqrZ8$S3|6U;ELB;oX0k3MSuir|u0ks{}^drwUb? zS;`g~H3HuEa^1?rJxd$F6)!aX?5$j5TEiqjb_k4}Q$;RQlWnyn+Se6~9ueqYl~vhX zBhVX*9|$l4qkizhP29?h{QB1J_Q`%>JAd+W@71;s#s%=hjREL`2?B#osgsbDB!AYG z(uHDIYsWX`g8{Bj5Ez!O>a7Bd#Nuwn95&p5ney!kDT`TjrM^Rv6itT)*ytD*B$M}o?(MSMt8&$+u?_rKX*`?w+8~YR^5P4}7sOkF9+NYb8VulQ0kaac(Zu25@$r*cl~zffb;YL~{E<68 z<={D2eA>YuyW`Uiz6>ia_{?WJyb4dc@CbIt!Pnra3m$dwXRz*u+l|G0iQgXR{R2=- z2MAKixJd5;002-1li@}jlN6RWfBSb6MHK#qJ`zHBG%at?7=^ZJ((sU43aGSzR{EkT zV2Xg-WRfo3?8eC}; zyEAv@pMP)u1z-biGn_klvcL6sU`UFOa5WKV3&fLwP#~_QGqNI?vZjX9e_Ddmyv`La z8Jre}B_kXk=J63Dn>GS%Nl7tyD3D2o(^4iZ3mZc%E$ibOHj%F0n#U)zib4~{uoPZT zL$0P|m2+KIQ#3oub%T7-d~5T@=GJh6j|NV-!5BPIEvv`*E?MCW0ZmUuQo58-cw|hM zG8wK%_B(RtIFDydO?RP^e__!PX;g|RlA4P24jtif(}ij>mC-fQG-YluEa|d!vZky= z`ljZ$Ff1r&IZhWinz9xVW74ROYid$XF*J6~9#4m@lhthw1!$|R%I2dC^$n%=%E!^T zkD;QWai13pu*d@!Y6y9c-dw2lpbj-&crkx2s<6ZhH|C13WnOqNe@}d^VDJ{l;le5k zl8?)VY1pm@y|@qed$1aQ;y}@)L?Jvc0$AuFD-SZv*SVC~K`>q0t1Aq34UJs|`lF_( z@D?xDV66bu6ClOSK1t`Q>F~QK56Cm(MI(a3aT7ypQO-6;vTAZ&m6Uwuwr6=LD-tLF zL&h0PIO1GPDmNp0`#UM72-bPfjP(o)4PIiAp{Ai!ThwhM z9u`&DL*e7r45@} zqS>??T@1^nnVwqpqQ|k{%dq*LC>flElRbiyesX2Z>T19VbuXQiV{#@+&4oMF+fTiO zA{>-6PSIjcOoKFS6iq+l;13qz9r6xO;T=vS2R}50ccv2#o=Q|h+CAJH)AW%6InA}K zX&=!}FH#s5e>yTlWkaW!*oqO68SU{JVB)Hl0vvZTX1MRnmt>R(Ase@{zh`Mq(VYx=EF{=B@5S3GzL zuQCMxe}@eW>)Mz!MD4@r)31AQ0&md9FQ^oyd75EqanI>gGg*_2aw+Y?TZJByZ%K~L zw>>z6cc`nDyCqzBkH{8`(LOG~i!9q#KEQ__ypNCak(H{r@CidzT+zgq{Y+dopW-Yv zxkPDIf8F?;VQslqQT}{=AzXgRu)Rm~k4j3G`^RK+*gwLL+Ew%$86KCDGEewrwQRkK zgM7We7EEjx?0!pEky^5+-T02dWqasNie}bXHlT~RB#Qb2@myH#q`M>~u8JQS+!;wX zTcPnxhZi`CBl_pfLH{4ET$WLFuXh)Q9ytAdPIvte-?;e^N zQ68*e(OB**X1A^2oz%(Va*uqu%H5Yy<@XMSmp|nFb#AlQ zsc)+~=7@#8TPO7J_%5xQ=ZmKvT=9Ok+Nne)@pl4~9{T_KK4GfVuecoVUB`;Q{oQ%u z&XHZYMO=Ztmo%+onJwR@T@tIm_@ha?_Wt{MN1i@NWSn(meYls++0ENq9&1LkRrhYV z{`to2%Ns*m)^6KaU36ow$vUN-z8fyMs2sVa^?p%R<&PiG4n+L4PHUk?_ zYAA{tCSL>^0=}^wD8CJO;es)WytgpW5ar4K!qSr;%oC6SUs4S;B$l0l!3IU4fEZZe zo_QuR$d`KBqA1!Z309;(-&6*E2P4o*RFfDLfr`Rq5SQ37Frb=pP#J8>0cBN?n^?hj zrcDl5Aj-t64wYb=JYj(rE97ph{XhvhO}NDW1*+2EiOO z4$y7(DDrD`!3LdKXfA`epaMNirx^ehDFH9w;Rm@-8hrdb(4>dJFhdReC6lWcIkA8a zQJ;Kpkrr|-33R{{paW1X=y09f zxFkjf`G`If6hpK;fePd%%epIqlMM3tF^VV(t9^h9WhXE50*4a|=vb1;e9Od`EW?1} zqLb$@W1H*^JXRi*?huRVfd|o`7*ZAiRcs*R2VY;qz@UVp=ua+4(WK=XGVrw_!06XS zQDapFQ3G0$14-TbLRAJn z@&U9MH5I(>1uM#0p(BInZ$q+qTV#)0mCT#`fFa|NR1Ytyy=Uvu8j1-1{Z4 zkp-}NJ4D4hh2N9%atw@f2yzUx)4yk$RGAmqb`EcUGmObhDNNDH(0_+L1DdBE6zkHo zV^NeI6w`)aQDCAMW8S#lxPJepEC>C=p+QhU_}jN{Lf?{Z`0$gEktC6tTWVSiA(#l= zRM#)&E9;Xikm%7N-rx;e*L7}(utaO;O8kBwCO&l}l^_uT@{Va6N#oo($OM$au!Y&p@yJyo@jf@8M)KKaWSMRh@yur@yCYMu zDh9N136xmvLgmWXPe-ce3+Wt*D2|pk8LXMPep+OoAW{WECoWwKlmW3jFXF1FHm`Z;Zg|SH9tZ5)(OS(F5xcr zegE$V%Q0N}k$(U7%{l3sk07a@nJ@`C4li7iKrZKUXhv<~iT zG$^C7*h`Z>gh38Ys=ch z@$Zk7MNAGeIXYY5F?-3B*l9=Sen!w z_=?PxTZ9|swIGv;yPCv9w*^cJP-=`cBl3#l=7&B!lJ>Wg_ZLUvoyV#)H2HeEohGpJ=nA#p;TkA9L92`s2s0R_7^+6P;* z6S;-?^@m7e>Qzf79;-d`{dQ6<{8f^1ty}|burp2H^la8-T@|({B_t$Sv3Dgcq#2Dl zOQGqvaq?H^RFitL&Py4!0dg@@hr2)E7{>{Ud-#my(h_Zg`l>A6$=ni$o~T-)yLWn> z4CvPI;H`=X?d`l@+Lb|FqhL6V(e_4x#zgy8m~@Z%PelKTCGT&us3X|7Z%yF; zrh_i2j}9{_5{(S704CQ~^6SSlLoKm`iA`jtx~+Wt&`|MrvPc@hZ+EXw`oGhhO?t`L zKFE0kM49>Ina|$@lW!dLz(kWqHq9@8Z@66wxE)Vl2?+&!*Om<2UD(~7yoD~Bt`Q({ zFdMGN9Vs+{3|M&ZK7g9P2iKeJMa|tQAU;M!Qm~WK_BELVAjPCWJ&870vlA>FD=fsA zts?!M2OaX7XuO1MTl)|?gz#<9j}rifB&@iuocsY`cQ_jS7iD(u%xx1YJ;NAjJZ z7%U>JYN@b)3-d@wxvZl}Ou9wc1zx$?Xwl5W)ruBaYT+d)<4tLMmz(@DX<#Zb<0K=5 zK@fwtIY%D^7^}}fT7xdwOlaZ7;tWnDm9URoKXzXjfPou#@0w7&ti0^e=FHLRu))|C z*mo}?2J!e99@7KN8C93J{)YGM?vYt4`c1L{StjK1UpuY7J3pCcLrW^0&9wEmfZVxMPPJ8I*WF6c?Q;rG$B}*p4tiDv{2!2gzf_RX9 zr?Q+SAz9Zof|(HtVE^9eEU3}kOqukh<2pY!PdlUysr z{}wVH2}P0;CNqE->uNh5sQRAo18X~(S02mSQ2yIF%kq~j!N)Pf4;+))AxNn?I>#01fKm*8a+>6WBB(q0pv6I!S@ay3V za;XwmXT8+)sdFfxdRx>YEU2zhfG`I+{-Vlgg`6iaC0YR`!&r4ys>^3|`>_wQ)jT|0 zrkEi?>HDek6lqur3Cjv(0{hySZBcjTryN`-d6r&W)=Pw<$1-(oK5xaiHm!cHm zUbZP+9srr?V=0sHi6g*d97Mrd`*dFN< z)9|asZq8ZtB6mvADwn=tDyyMUPxq!vET9g$1m1N4b^&eV2UaM!$An`~{e4RehP zWS~6}1N75RGZSX4D!gX#y2YE+eM0vs_&Q!tLdq2DRs^#{H5i1FGKh1{jx58RXQd{5 z1LWi#^m&wRs4k(l0v;L|&uH*XPM*8qQKwn&7u`^+r0O!vi7`DT=(moC!*rQjWnR3D zEKj`W!|S=1{Qa`7udX&=J(7c9%q^n#!9aly)gdBE6WGHgo6))FU)0y=pz{-)#?zAv z^<3nqJXwA+Gh8j~OiSyX1ssHat}0CtK)aXs06KQ*3&osOn1?&me)JY@e~^phlU*}! zv}ETuiUg%zDLvK}puZE!JMWyx7xDwxly%{8@DOk39T)iGfS0vz*nS0)a$f-#V4qJC zjbpA~&b@{#p=?R{*2EM6GT@y_HrJhTYK)eN5)vYd%NNxzoLAnODogPQRM`d zn_l88#8QHU(qJ#lcXLj9C4erI?H#SmZ`Rx;jjg%A^=riFzX>8Tyl!Iv|MtxQ`hOEN zi6alN@j|me4=~JRb>J;zu+uUB0p^g&-dNru(Ogq5Jx^LuBcflL(RSKzPB|^FTN(7$ zd$rd~+#aGV3tkUn z#MqqWh4;4+4-hAtsX;gxjy^A_IJ;d5tiNl}Dd9U4;GF4fMNu>nn zQeWSFgyd7OTl_l(v(rm{TFID(Y`n@|#TEn{8yQys4DG3Jo^^nn7)3$JqDee6e33FcHdGkrSG-!^vzQMv@cV%l1Z z!APhm4KN1&I0w;S&~l(e`ezlxLn~pVb}?bt#RlIr~pzde8;*e0RUfF%8PgEV(8N;1i$ChR5vi({;9kE^!PB&VsM1!_G4O?A97`AUxN;B5ppB-w7f z9e3pirC0WdNrP>7;|7j6)*gIT*UT@eIr>ZL(nH$X&OEwG9s)Fyi-MsjMRkX^Fe2v& zGAJ3Z)~MAUKh@k?kYhp_IcT`)h@yZG(c~^Fz8eF$|G=Iw^OG@qt&$Wl5=i{&0xmM; z{DixdVN>cI_aMYt9DR0KU+6;RaGu+|iMFyM2`njF*hpDHh*?KU=v%<%uzb0b(13 zaKJVBl_$sO!0-Uw{7C^hwGE_|p%iq1jcnPhOX6rLxO2X&JtKBHVG9bJ{mwE(`z(Kh6`Z4%?*}x7A3< zA_YJ3ZKX{PaA0;-eXo9<6<(CiGu1jf?An=taEOdun&88eaUa0Kf|Is;ql-T@u{ZWW z|KV_l4r&$Oa`wOtUGTV|F4{P<67bC}h@3NUtg5wOqo>h~_L__h$|em!oPnceQie>+ zlk<*9&j&b}QjT#)Z+dv+)G6ar!YI~(PSJaSE1_F>@GUs&6UR{HQ|8@=ch8U1bqf9>IZU9s9k7yasNo1HChdfrc7%N+n_Kr^q~!*Z{2urjWU08*yn zq};IDeLMX_KJn#VJ{9*#VZW18er^=+k+M?auRsv6QZF$OQB^Q7OYI_%W`i}>y|U+3 zYLNp9w~8tO$67|Bu;MT#Q0A`^rZ;R^_+^U=D}X30h4?%-)#ZRJseK?Uug{`SIHr_Ox{k&ro-R2jgh0~&C7P7Tv z{`_6<=a_~1!Taj?wtw7}{9cdEly`giA9?JRM{(&Va8WlQ8Vb_h`EjGdgu<@JZv&Vv z0RX?}11E?twwr+L>@V5rl_~SNp~%KP)_pO$K3#Iv1iyav_<2zMtsT1Jx?Ut*c~Ay2yG^y5#N!{>h>l5 zL4)~{^`Q4qY7!xE;g1+ivVH3tNR!K5Yy9smdV&z!4*xxw>4=kifezZltNPEy@YT3DT1jEXG~|5wM`!*Mtp`esI{Tp}u2js?Hf_Eujcu zpC}V`fbN!RLRe;4P*5cP$S4a?21pav=KvQ3HD{S=C1V5tJ$Zu;=N+31+gqy+9iSut z$f+?uIl>l(-mnVu#gXHr78jI<;Uj&rhk1ZOOkauHg5sa?zo_Vz=Wldi8Rz|;6Y~KE zTH@?PTn}I20nD|Llj)QDsI}$Xad0jP96%T&$7k2)^*F?;vztM3n|by}eiAZ_l?LR| zZjmYJMj}=sxhRq%su-gpJrFZa7uQciJqRYBbqwv|BRY34oYH-r{7vkOyY&1P*)kk+ zW>L?=Ti!c_vPvVC2b>!=1t%8BDHIKID4M0c3_(jF%AXv%P3Ag<3d7O^O~vUXdgXot z>O@*qErPZFvK+?^@q@AzN8a#Nj|E617V4kErWfdrHcRDZ7y5N7^9f z2AcWCZf@z-5C0iDo?PCRDF>zEC4V)y=Uz)l+z~)J3%{T$aqVxz7pFA)tZzE1Tj>Fifwj}Y;wUN> zWMCGNtl54a@>g#Q$#vR)=N47xu7e3Z1ZN&2$H{wN4fI>TQTl)9-`7Tt^_~Obajznk7c`A9tIl=NWtupsmL5Jkax`q@obg zZR7{=LSZP8ok$RgO$tCj&R~mfFgto!cGT0k=kcP6fsIq=n(a7RdeN%HmoiV%okvZ+ z)c9Rq3@*z$`um%3%*^^Q2++v8NPE2W#xs_1hs#6Y0v*|Vvjc-rfVyhWcbre<6M$6l zTisMFVwh+X{z#Q><5^lxzBUDwN$4Y*G1mL-jPW-rMqmXsr3e*zZkbX}0Soh?oTA8> zhhe=$ds?Yt0g)oc-T*R~!i}*a3`}4GK%j=nW+jH1#GG(-Lq4aF#Xa`uo<_Hiq&G-aHQ95?G-QpuCT?AiY%2&PHn;gx^dmWBLZ zf}o<30w_44u^oPlHK4^xCWC?x8D@uNOF}*17f_G59f_nCeefrJD9Si-Z?M(@IsQS z!jK*oL}f{TN5A>Qs!)iM*cPCgVwEF&NW9m#ZR5SNFm~5@7{lWxRnMa2!bHGBWhe%T z-)Wm7%b;Xi+DvHhla|5NBAn&iZ9Mo9$AC-MS?{-J{sJXent9nu}KK7#ojde*P%iAUQD0lIlM3RlT5|a&@!m1 zrw+*Y-mgv#bwc8QwwbYsyai@SY2ohvd_mDTLS=g{%;^9_9 zU8)CmRGe-VS|`P$XnF$r7p@eyoo`=dSpyW>TNCqmG6t$rpnGh_6|4tb{~R1#^K@(P z$&IRMMqF}GZ~l+(LOqLW6#wJ9{z(a91W5?|NdHm0L~^JkGa4d5+v3tZn5Kw?R&uNR zKW@iv>=!>oMJf(o+M9lQ>CRVgl(G3ZJoYs!v{OZ?jH>Yd{gZlsvvnwLS)SGR__u)7 zrGW20it4ZoM8P=gc~!-A4gy zlSov4YvA{!x}=%7$l9cE@ut>igAg{%sXu(bs;Lb0s1e$}#E3kdslqTeDA2sI=k?LpXD#OqqX<;-vH(*zJ<$IsVH78@jDk`WF~H&HWa)3z1FaFUtq?P*a;!zppBQ!_Q-ps-;XtHMQuT<|D?eH9HZ1>0nHH-Dxi%kFdS0I}8I6_h!ohe{S z7Muk+cXiFSMfXdIP@lhf-s1)-G7?%sgql{9-+S^>v2D&?wQ)TtTrk{eSLS*L{8@Rg zcv*-VTe>&ng>svm&FPA%?pr+~96TWr;k2Ds>`XA8dO_0#ghJUF1g|69xLQF9-Z?Uj zqcW*d{1~RvMtml$(WCEALL!(EMWIYN=CEBAUKIz|P_3H~ShPq%0Uu>Q8A*bOM%GvqJQBsvK=iG^ShLze zUYZ=2q_|LN9R>yBoukBRwfeE3AJG6zVkAhY zKesN2jo(1ajKlBCQi-gmHtU{21Nt4GMJv)5`(CtK@R7P7<6XG%TsxK@+gElGNe2@rOf7(W*baezroR$RQz~(r)j!vk-MiD~d9e0%7mBzw3_PX}}4T<9oQs!Kc+q(IRA>8N$pavA?AGX>cx-B_&V<;wDcm4 z;!_T)cnvQRL(NUKg?WYqg+O$(U%eE(3UfR%p6&HFoHyXXY|z+@gvN{9{m)+c5nUmZ zHD>|;dK#@;J322&v>N@^6gdn;mkVJ%I)Tu0htt}H({aGbTd{V*C@dZxLbRY$d?A!$ zA798#X`l@9wDm$WrqP>`cvM7w`-v1WCw`eN^x1=~`Er2hY1bRRi1Sf*ZS~5~_ zXl=q8y94feP;x4g7`5s;WeJTjwRTz8g8BNCF5A`T&CI_AabGlYeLq)JF#vtTQ_BD=7l$<5^5U(e z-$bVYI>qHka{Yacnv(!n{*)o5%y&+>B_%%Rn#s$v)_;LL{ws9y0c z2}x;NIXis$O|g&fr216Gl@8M4q$0TO4;%3Z|cpTUY+!{z`yc{6{_G1r1b{$#o zHJZReEqThGCW1WFia8dftuACk^F zs!Zyxxda0(9GOye^-#t5glwDK^)YUS&tQlBWgwS01O7l%dk{{)f9=|t!LB+q5QODcn%uv z$vh|WVhi$`!yHk;k0Or#n77~))7x7Pt#i~MGMBH?^xwd*JXyXw59&eYIjg zxeq*yji3OEWd+;157nEKh8oH^X4+=L7F-F%EO09feDlaZcNuka!Z!4Ys%wcKTcPno zACbwXWTo9GTHj@cw;!>b+@J~P<1n!?g_fnn%?eLs!%j?wzv_RXl^*DLFx&XSI2M!( z7#)SbiP@J_P)lylaFK0^tnW^E%e)>}aZWIyoMf1MRIfd^4YqG-0$r$gRJqzs6^<8J zFjiFQS8i0N@_0aQ>L@Hx6V$3;7<4AtT2(H5{q}qWI!DNIJMp0tfiehAGXE6duB)Kv zk5DDf({;sPZf7fj#!RD4P5_qVECD=#C0}(#94<)yf!W;c=J9-mQnL2m;xp6SS6M3M z&zQ3$BZ{XpU9=aCNp3`=LOC5`$#y=+_91C0)2H_j1yspDMxY1gQkP(H@&=EV1YeeD zns{uQ$INs~LG2#&*>O3(mu^H{$#^IVI-@efQBS^d!D3SF|*9mJ>msh-Bm2}upZ zLq2!&)BvvH=tkNOT?<9-1=aRBslCEkC8qH7McjNIO2~M6235V&$?H}jq}g!xj4j5g z*f%%gOnOGLS5)XIvq|pccNi%^z%M^hZ!3cJSOLLSj?T8&{eikXv6vC9c<)$q@OSLZ z6CKDeiSHLBSFTT0Zh?2BYrUYf@k_H0u>mY@RJi4vT{Zm}$f6GqctMF*De{sVdx8uq z>sQMD+@8-nipJrcI^{^SK<#>D0-0K4cbxq`hlXR%1|`SUvdH0xOAJ4u*60kZ^ct~f zudirGAQg9JF^bL26?aBazp8)-H`l+XbRGNVvBYheOuXvh3OzO<#akeO{eNpX+)gBz zl+ED)@Ex25UtK1hEtV);6c&)T^qjY$Vso*ahn%FCguaG6fNURbu?4rR(D&KBh3vkU zsQ#M%j+#_*Wcn!d<@aR+*xq`%s3QVEF(V}Hj_;3pB^iafRkn^Y2=Egv-|lK_H$_o^ z)CEATdlGub2VU*t8fgoo1WPe?eEREdlM-A2{yZ&(w9&y5(eCopJ>Xcu%$b_o0?#1t zxTRmOedd9)*WxpJk872&b~YbSgZN6&OTSX$^WfmOIcx3R$Mwp0W+)!BG=i9IX8CF4 z#vIYYo$}6cv`icF%ktRC2aPUmbp`>67xHJE*sIDn+d=gjQB$_INe(4ZA`nX#`G^ZZ zi_n5!C1qE<5{ljzn9*L*$!F8j+|R7-+CItP)P#5yV$n`zjL5Y1rVoI`J3tbUGVp{w zB$Y@qYo~Dhx+o2>z>mixn`57ys13^CfPT>a z$nPWS;ob}^G)J8tXMf~K63a?;9ow(q zk+?1Dn*#yE2A}pNN2>5QJDSea?GOww_29hzOF<%Z521Ck;s&ROnm*y$`2DRuyaXh96 zC-$oLH!o?i+)aLu3x2Ldn)WC_^p6+m0a#57Rl=O$jFE&Kq?pbI<+qp0w>6}KYshOD zj@-7KLfL5ji}~kZK-qzY)YFad2x=>hK@Spexc2S(3tg)DS=zREmXY?fGJ+`|R^b49 zkij114syx<60{~3!v&$hAG0VIIwHB*5O3j2l5Y z+8hzH>adPU9@(2;lz%~F)F5J#|0(i*#R;4|t6vxeYblPQX=^0iA9u(rLes!+csIN| zCvnoxiv;QB981*JJ+(y9zqyo5quOGHu6@_YFHjHuRJ&+n zu|u0p?+oTZ+W7-HOOIXZTFgXzxXAGpGmr3tkY{Lg#?}HD;)-X1Y3(Oe0~5*D|8l&l zE7VV+s|wvNEZ2EOCH?0D!H9f6&hn>OhB49KX3*w;)t3@1*rxN1vlE(j>!gT z86e?wpo77Gj%Bm#KPO+0T<{F*38*MBZXxmAdBgiJ1>HGGb?`xa`?mZ4U8xqYD8N?D zZmIQbNer>Dgk_P4nl=c%TU!|&B5vJ0vv!l*f{P}675avOUs_}U`nq7qW*{rgq&M%w z(y|XA*!vCNSZ&9HwZlQEO8^I+24)kD>!eG8OL{+Ho>k3eZ`elqH{LusLj!mGG8_~- zyaS=$Q!!IZNhx1sw{|Q)$K;Q=LBR5jNL)|p$5U^f-BbvHblq@#qBMoLBn3*78EdK) z%l4MghLbNz%w`&Di0}*Jl!9=YY*N3XEvXPI>*4{l?hDtvHY}eF{v`Qd*R2QZ*2Z9o zz_TKJIipGP+dAJkbaTW=u;GS99-Y9NOZ^$Pk`Fku12wHbf0GfcXjT4n2&gwbdU zHGDdANVMFiLc&@m<%D%p3!23y$*?3v z?BwnW(h?m%>U^UNdzMk`rqR%%3+5-FSdp=cw3!!Kab61!aLa9Q%$R&4?vkB-NI%Byx8)tRaRljp4?bcwQJC-e_NW+Bw~QW74dzK-<k_E`SC9BMzC?(lFRcIEI> zRf53kwlh`w;b*dEqlblQ=)fP>9`sSt1Hg?B4kBv8*^*S?$#Idx4t+3}zr4bFLgRw` z`o=Ug=!o@1!fue#s>8%;{&Jyw^(AoDYs!3(1C-(L^F``zAz|I{X~z1XlL>iK zHd*rZ?^pE5m4^Nh6Gk?u4*n2olM=Y8(8;d_Eu%N4*G&+0i|*Mk{K+ieU!1nf3b@Ec z5tRH=@Cw-!gQ#us3IP|}@Tg&m8b(;*&^r{8{GH-~h;6slSM1o<}*gns%H62wRLFfieIGcZle>q|R|m%g({jqhcW-vs?V zjK>OKFFwhqUKm^l;5zFlPyRnztt7lz@ZSGpx$WxVT}za#s+*7P3IL@RqZWiWD@RC3 z6~mod+|+**6TGs-bSpI(!#_A`o`oC2$iSPFCK1o^r=llIjtNtX>AK+f&GOI4^r45& z6&h&IyCr*hN+$ATt$n(p+r zIF>eY9$<>cAbh*(_~0+|T7r2&zugK#d_3t8 z%r^K(a#%EDb)~G%BK=|1g#HI!m2m+ANzr1q0AWJ%!1KX@*lt6fU*;6lVZ<)5qJyZ= zLnS@yhH-3sU70vp;G{%@TnCA8(mV&?&(z}U-@l`#*?4$pcuf6%BGOv*bBQ$E*%n5>`u=7&J^I*DA4^8Y z15k)X_|nw<^=?eA&-GkGG!u=|uS9(+H`zLy`o~7^2d~w!McPjA*1{I?xDO$~QJ983 zZ0WbfyDXmOiF&OxoK(l|eNj=TWm>Mf#quat!%ks;Igua;4U)&DTtGDDZb-KLMNPA@a>hul zBgH8V+18V+wtqC^UJ_YOPTx~tKpCM}&6B)MKxHejdj+l0k7o6@=hyluV+3bh&&kEB zFAleAh{+}b*)ANQ!sHi8)4*HzUzcr~x>n8*3>$27?0c|Llth!t&+kD$8+9zO8*LyE zI#WvQ12a?$;{!a)G$pv-$RD9xgu(;dBd{=?4fUkO35=kOJNCY$}#|6RJ` zU=Ln1&tr4t@2eeJAYfywY>5D?KY%qTH`It}eC*IBY{h^(I=aw@0XPM6B+yA0i@~9a z6bPm8>^2Klw+h1+%Jo@(R7Jk3{T%Q4{o!@BPjVwXxf?f@&D#HR*tA7K;=nHS^)0Ce9kx7>lZiDiiQR zRt_1;I}C7sCNO1qBx|GV?Xii-?Zm>JW|qHX*wvMS(vyi?Da>AK2#1y76S8#Z#; z!N|lBFjLx|+C-paZh4VA8)5uy@Y~$|O0ujYy*Cbam$K z<%3W5&po1|5!K)*cE>FqX4Y`o^R0yA>z02s_46mKNgZ9|QA!#%<58)X^C!#$Pw2k& zo*fH?sOij}tEpCf>ME3fibcD$MBKc5Y`l=zhhx0bmlfK0{0C2}QbqOp^&rLT!?9|Yw0m8Xr;`5C%9G+@^BD;!p3viwt0@T+q|@Sw=KDcBXGOvul0`f zXCIxrn31Vd{*xZ2kSpj1|LeM&GmZ^^1IFO?L$zqVU$05q1m^0n+#0}`M(9&O-R6jf zgcGQmlx_Q1a;*x8OfzP|=CD*&Jpan>@dPg!={Va2A)G#Jr4jjt;y##PED%KP6gJ^B zlbG->T1Tin;|hA@sT53@q4M&bld%`BY~940T6Aa>LQMGEtnF8_2p;ekGcTx00PaDh zzpGVN1LpP zf<1LxXk}uUpX|U}k@c{BrC%bD5;7!{Fc_wWNJ)9Os}|>q(}GvUV%LhshB!k=VI-Ns z?*@xopBQsD$L9hPO}GKGq&eJkfM5IEIufa+@6-ZfwX%%|Bz{qOYH7}V9}g&;Dj$-E)#5WVymB=H~drr&<9qEBv+5G6AP!Wl2jGaRj+fw@K6Ze{CWF=wGHiz-=2|s0 z&&GM@;N5G=7>7eh<^f?+1^2AtW*C?*j>&`2$tBc#c_eP zJN6bIzS7|ILHQpw)@q{ZfTC-30UTTQd(q!1usS3}x77^H(krq>VNos3m3oo@j(n)X zgk{LaH5EBRV(h7Vf6)afT|r_08rmn!BZ9LZklm4~bDt<>TcB9Wi4&Tn!Iin@*w4Cf ztJhoyVwI8M*2(7Ng!kwMT)$Co%SUL*BHtay%YKC~asTy$do6hjmh#!2fWfI+2`=Wo z(&v4_8i%3coKL=pJ8YLs;;fHD&EPem|Exy6%)5f<-{chie`TH`&jV=Mw3lmi0GFdd zBni~-I(5htE|95<4^C82O~X7lf3jeky8O+`mK7|kg2E&`T$EZ#ZHOV^5aNhSs@&2X z30>%2Sh(j;RPL?P$JLbOn8@*1_Hx*^?YHf_ebamHe|3XJ_!FWZH`|2UZ%0^Z;dA0U z1@FJ6#KO(Oy}q%4wGu$3W-HpDZU9I5fKAmofTqvF!+=O*`OnFUK$g5Vnw&_qFiBkM zrF#R#iLjNTlJ*An53d~H%`4UuH%O&uFr?{Xvd$a@`cYN5$H2TF6n1eVwzK?`vk zd1~G6o3%iHep?x86Ka{08*Z-fzNTNl6nz^))75~4T0QC~V9b-9%@Wn@UVBbUCUt&EIhP2;KWI$zQ)^!$5}(splE)r)`wC4UYqcmRKVaD)@jm6;wnnCWv4-zsbN z#8E{L;<(#*pWBhDhPEWDDYF;^>?7W@=~fC7H(IohLqi^#(^lV7#53QnO{Ij?<>z=KW+vy0Yd-3tb^WnVFERZNeMtc5k5;7=qsQ)+ih8YtTfPQFWTY)Gx9M3VV}w zZxXj`Kfv12u%`XfK$L1h%Vrn_x00U+v%YwTK>5f56xFHOe%8V=@?k1&%UcYR0V&Sr zN$Ibw3F0d@b-f~gS=yA5-rUFRK3D2sCZe=iP<^;5YN=pKasGXzbm*KEX+)`0nexufj=0-xVO6{)0aJp)qpxVx8OtxmvC_S67da7>Kk%`p|EtZ zve=Z$j6CjRQJb&rRs8MI&|4B9+)V9L@%VsDuLu2v+TbMWqY8(;T6xWgxm=oBq={>W z{;^0h6rQ&4o~gh2B(|7 zZ-ycS4o9nQ5IvE#Oi6lwB1yjvC~m52TKl#3Ihh=X?WFTjqgrT7adQlC;9J}(iHXkb z7dT?@Me$_tIaEfUm6yFo37pbBBzO~2oB_}k**(5xrkU;(!~EW41`=*Ox(l|Xl)3|1 zJ?(P(xD-J$Q7jN}ak(5=L<3)?T2Pe@p5-7usFC=J5-J71}_(i=o<={3ARODC9R@4KQmF~#kQfnTdy6n^2f!IT+1R1;P2Nc)0Ju{&hy>VwXk%1(_Jk2?XkVQ!>If{dMT}}EfmxzsDd&UvRf?;iU8hd>|n5_%f4=k$lt--N5kM_=4^E2v^?US&p;1C zd@3_IR$1?G-e%`i1@rPxrVKMDGLO7LkfHoO3N1sUYZYe6X(H-d$ih_@H$m3z^%>Z_ z=S)&6)AmjDH^c3c?ME@ z?v(y=Qf@-S8xb`d7q=E(GA&?;EYaSl**cQX-^<=E%wUq}PTl{dsi79_g4CO|{chPp z46|K=DLz#fHW8nt>6uzg2=IU5*$gMm>5H@KekKg)cNVL?i?pRt)-L6*)D?q6ueF`X zbR4(jO)2!vt>rI_SpbRlmi9%#UP*O~&vKGnO~0}bkXDix+WdrbnRDhGm7#qg;-io( zKR!Lk$+H-ZQ+~wRA7E-s!N8TtrTC0Ig4u+(kxlfy#*;M`wZsG*1L$cb-N%B3!pA{^ zN9E9fLg)cnq)+)Lsg^(54ig+pmQf!@Sx=_}Ml?lG9%L2TZmgBUpIBq%85NIC&t1~d zfLZlT$p{8R`g_%LMJnj_IXXxG>e5sBLg-?+L(|^kI#-tCKk=pVc=OFt^&y&*Kg^!7 zOng=3`GwmZaplMe07=|J!6|C($puXTur2UjW@P>lIEwi!sHd5OxIlPLcO?@tkd3$Y z3JSerJqxMV5+ojLyX#5<8`XKN==)r8tb&e3m2`))rUurZCM#5}B_hxf(9Ak(WLaA3 zgWPkG0K`ETSHKo*M`eF0u^MsSxY3468SA~oK8Qj>68wn>kn|-pz}cv$2~OkaVh!i) zV#Buo*A_Zy<2XZZ1SZOqOYxPm;NMW4Qzrae#8j1Kf(+(YbrcgyU9S%^lmn~nALdMU zsX(YYHTg#}Nn-|ef?MOSum>_bq34d;N}bhEe2OdkSXNsAv-MsL<&)(Mzq z>#!u+Lwc(KKT`KSynDzJ2#BFmko8R`+c#5Pz`P_o9o`jqy8n2KX(?Wje!) zq8IXUP?Yox<2WjUM>r_J*^TwI?i}<^x?{Fz7xhC>B1XBt>?Rr^Z`h5~{oP1pNt8l< zTtgh7!Z32@++bRmvR|g17IR7BeIef=R-EblHRE=9g}ln-rd`$_kOS(3cwEO{W~krJ zL&y^T;tuYdpZrRz=fh@%X&+SWCwN>8os>NTS*VJwe);7eaDQgd zRhYgqh~E7Fr_Iq_pn6M~Z{Ijj|2zLqdf=l<%G3Ullp{n3m~=#AK^G{MDU(54L(W9P z=5$y*rS_Lrsh};WtQP(eKe4vok-`1IZ*B#K@sG_Q)n8W9!llwbmsfg8iqKyVY8~&o z)m`O<<@J5THzmII?|5haJd;v2P{VvH>&<+A>z!B-#p7A=!7TQX|E75j1K>>njLh{Kk&Dnq32WipxbXAxM6cS70=AW8&C;FKaH6qQQ%|DD&ge}%MV4Kd zjz<3->FyJkhJHDKi{^i@Fx3>Uti=n*uanDHM?jB-U$d+NX9HyuqZ0Kc- zhg63F`yb^Q&8^K-L#_&ODmubE0w36NPG36u*DkjJ8qj#wExQE_vvP+D;#ibk_q~hk zTwGwmn_M2@(;(gWgn~3*E&I>7$7}Wc3fk2HPTj0kQKkGZryqoAk+yY&uV687hKQ2Z zu1{zDf#twm-!PT9s+~3bEt9)e&gNMWFN!|xaXrxX3F6g_{0=m3o@0i6eMQtU{Vmq{ zMvD}}e}9p0q8W(*|8AEa{`cj%`cJH+nKGy(XH5pQcT){&n0175ncyLal72CS(iY03 zdQDt_;~e%dw2|decE|CS+tu&3tGqt2)&9o*uKj(_{g|z^0&Fv1#qFUr|8c7PCD7_uPr&N1!T|e2PR@trQqtfvdcf%sSa! zOQMSS#70)Xqr9!qeFX-vh@F<0iP@KWbpGCaCms4jtT7R+6cW=jvuk~GIcm$$*SBox zuLs|hr_2%VLad4Z`{~yY}>YN+h*fz zW81c!#mDhC2lP0-=jS$&U<&SUiV@E$E`hRu(cIV=Ob@H)72LpgV$@z7JTJ=LiX=@WD8sNWe7bchr{LA#n)>iH zCE08?K{UlMX4!q+_0;wDd?ZuL_fCmi9d9h_zU3&g62h?vJewS~!o%%9SZ7m`1&3^nDsC6Tl5aM6a%| zp2;jffUOtsC;Ph85gl|!k+)Yp|@W}io%w#-Y!C6 zvDz}H$75>-hEX9GoLRPZR&$q4pbKv;wFz)p=c6~OR(v0ILh%)-NLi-3)CCGS$RAXJ z{hDo?XiIe>%*3og{)P8m|C>QScXh`4@<-_sF4RgoXud=xNt3(BA8T7yEU?6e^-GOb zi{RFFIM^f^G9$l5qE(F8Jx4`;vsUD-$;wP4RL<%GC0d+i5aSJG=G?$KGHM5*zLslU-kkAWYC#i?>cGKp`qoW6>0p|MXm*tyB3&su4qYLvQ8GW4MzLV{k}YSjI#XNJ zx$_OcRB|ThQK7}LboHdj2fE#*95|^oShz0 zUj~7(!j;H@OR(FUs-Ar_urguHkIa*{$V-Mdo2DC(;v%^!*b=_iV65ilAWq@j3K-*S z9@yCX4&iwsy-xY_k?Dm3!iyC-RE8qaiyA|G{G0HwBn_Is5*T|I7|vyBU|n~PWSRu< zRDw`CSy-+Y*uT5W28Y;|;kEgz4btI*`ftBI`>i2DV*r>r%4ewQ2{Y6srIrD^NRY+R zI6pkjX`x@=RIip~A`Nxy_b$4lBkY?juI1%%0@D1>^%F7V9q4_w(Y{ z?v9gLsDL5s1IKe<^%zlo2N##CsKPgB1iRY*}dJGDE@Wm{Y(`NO9{4VJie>74v`YYmhLn?6kCPv2e4Gfm}xvoz=HO5&t1gyiJ zE6zxq+I+hC1m_5`)6~(t7f``N zGr(klF%;|iq~|Q1$UL9}imOO5{cF&88B8^ewYybd+Llfx39jYwTES}1z7{x+WXkZ z02AWJEWML}a0R^~I3jdVF4~(&WNrzuxehlS=v67shiuYxL|Hm8UVuDx!5YH*06V9+ zCEsJJ&8U`iq|1wp`uAytlK=a!9m|IVOF7+wFZuis$cYF6Fl@7E9{^p?3A?!@x12*ESxn?hXp>1@TqD zsQ4>1%DiHM_5lLG=O$r&{}zTQX&wNTpX z+JRB9TD0B;225}P10UvfS_(Y*I_zT}^$l$a>8E?uqNf~Xkh=Hx5Etv2@{^sCXKDxOxlw) zrE0-U#;uN$D#ZT6%xwV?(lL``6Q04t6IcsF7k!QK{>M>Ifhv(bl&$y(j@3URhFbG6 zMEVAn4V_@2#Qa7Z$)J9V;M)g%IkB0P#If9-!z0%E2O90}S$Vp5vR3cPfP)`}z>+7+ zvx0wk^~3xtEih3kG^~b~jkHz&pbYvnrH_vu82b2mK9}b#xgSmZhn`Y!NS0(@AzkYi z0n@ve^(Z97fw}7;3&Ny#JXCYxHGJmL?q*&;mMBJZvz^`gkL`uu)s^LJo6EmjI;txz z-fCjl5jpak_USfxxBp3Z!)<-mS#3)>Ot6pG0X8`*0L-uXmOFOj9~(kH&(f){e?PyJ6~4O&|2G%7Ahz9soiNlIV3j$hrJ*0xgW8P2Ma5Q#G9KehKj zVmka|Jk6D`i`1h`pjBe2vM8?;4$G*cx=q>1{}!6R-sE`9Gm0ti{zOE)bF*j1wmSm7 z@d8(tZIRV8gw&eQrkvo4PK;`^lFQ3lY>sA62Kww;lHFzV2JUBQ0ylHUO_|cD-$UlP zN?IANz(lp=AGN0+$%B4s{f_2IciW4`+3CfqK*&zs{f$+4VGhj@oM=D)9Q}^LN?hM+ z$>{C!bAr=*+!twQ(gD@nlP7Ai?2b+nCe7gYkRtHRuDs^lu=@lm+2_qw@82`ezEu<$QR@(vUtZ5RAGBQti_j%D=I zkAfn+mc(SUq@-3e9X^)^Y6Y-&pI_I@&-BBzMFHyfit4RdxMh5^7rThJp}|=MLZpX~ zCX!caD_~F=VoI-+fNY*`r{?nPFd{4a2=KO{qBSrMG9VbC73%Svm%{c+%NJ*~@pfX}#=4~BswMhvx0_C3svZUZe^m=Dhj21i(yJ>|Z#85=oo3K)5Y zwQpVBmpz`r<)6@?c?VZ{t;$zA<2b~kQl#n7U~gIT5~#jSd{45oKi7st&o_mm+g!R~ zc_)iT`()nCCqm|{Vm^Y`xO0RnYzyr%x45kxfY?9TTsT3PWYvy1zHpnwIhIqr7%y%Z z^-9zZbTGNHVsZ&jQ@bj(0-HW002;4m-s_3kfZX&)ipdkBp4R$@%6HHOT*s}&OeWN} zDx-}%vGansp32+%f>cEnuW>Z4W$O%gk7uZN5hVxUfb`Zv{vHGBwgsO?9!1d|)4DLd zk-JbWy>p7hD`XJ?=7laF6+vuw^jeXef;H9F^VEcUY-(^>7T^X2$N|UoE=Pt zpZ?80_|2Rx8#wH-ddK|q9$T!l_!c63I$*jtNeXA8Xc~bB`c4ove5*EWN-VLPh|ez) zc1=M>{VJptjwTiG99+u;;7bh`5p$7FlE#R3Y9ynfT`?Q8XPRU9*CIwRkS^0k$GbEU zx3Ni~Vh?5u>LW??{7-2S!&BE!6h#fjCham* zT+?$yM|2V2x#vB=Y=w_=L$^c6SRdPC(tAc?^PY_Cq`?L$;2&B*%J$3d@ z9!t>_!9u)BKQq!UD_Yv3deNif3A)%lo%ZWjsM64aPYPdY-EzbKB>Excrrb3Pc7*AW z{$?v?t;$rVWq{5NL|y!XmTF1L_c6pd9J45n=6CwNW~tJfZ&MV>RuQ+HvdNPqOqK8) zf}()Ogh+B|OUptz?IWbitS$AUC_1B2AEvLPfEa^szL=PhnhZ|B4t0!~s2jjumTRe2 z2b88h@#OSAJt|sx+jw6!YDTMU70GU+A+^w#ykKh09#lermAyt1HmRu-IMRcS2w?#l z`yI7%IiE8cmm${E7}50*X$B*C>xY4-UiV2rHP!;e^ziN0>tdxE?r0`M{T0!_9jj1O z3A1N_bDd!3+2xS}MeS^G4pqCqm+PCJVcp|~MmUlmhk5aD0|a8+$-*JrFv2rorTF&r zGuXe20!$Ua8kS+VU0XOXs|6YmUM!&Z_0}OKb@}l`*@`v^IX5#3K(VJ|G>UE(_yQzKt!`Cw|JktqhR- ztIl=LN};gishw0>9PgN;uD*0se%pFyyhW*Zhh%3AgQ&99&9shtS~jtef^1!lSX)8U z?J&@Tr?y)$&FdCDyUnX-_5~k1_c_`Zm`&m;$uHG@k6aNcimNtf-!^_StMVdae zbY2H!AXmOc&~R1ZqSM4z5Pehc+9loMl;((?+aMwGjIs|0SD3Z)YwBbI0;0Y8%YzU&pjs+Ch^Wvc+1**vPi=RJB>>yMICwB=P#ya7%UoR!hxs}#QVX2 zPrFPowqP&te4%kKgZJoeaMa)f=fW!^tjyMfl>pA-J}6$^2JQxd`Ss%0AF=STgWRWL+V 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 W(m*lz*HoBlEiM*bU{am~Dx&}eeNGnu diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties index e2847c82..d4081da4 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew index 1aa94a42..23d15a93 100755 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew.bat b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew.bat index 7101f8e4..5eed7ee8 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew.bat +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.jar b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.jar index 7967f30dd1d25fe1b79a4a6e50e2aaa0e425c02c..eebc3c18b4e0bce4a2a9e66be24c4a410f17a1fa 100644 GIT binary patch delta 5797 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 delta 5783 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 Y0nj}fSlKkVQAz{)dkB23nN#xr0ccu%S^xk5 diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties index 9548abd8..ec95f42f 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/.mvn/wrapper/maven-wrapper.properties @@ -1,20 +1,4 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -wrapperVersion=3.3.2 +wrapperVersion=3.3.4 distributionType=bin -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw index 5e9618ca..1ddd97b9 100755 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.2 +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Required ENV vars: # ------------------ @@ -201,6 +201,14 @@ MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} export MAVEN_PROJECTBASEDIR log "$MAVEN_PROJECTBASEDIR" +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. @@ -212,15 +220,13 @@ else log "Couldn't find $wrapperJarPath, downloading it ..." if [ -n "$MVNW_REPOURL" ]; then - wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" else - wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" fi while IFS="=" read -r key value; do - # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) - safeValue=$(echo "$value" | tr -d '\r') case "$key" in wrapperUrl) - wrapperUrl="$safeValue" + wrapperUrl=$(trim "${value-}") break ;; esac @@ -235,17 +241,17 @@ else log "Found wget ... using wget" [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget ${QUIET:+"$QUIET"} "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget ${QUIET:+"$QUIET"} --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl >/dev/null; then log "Found curl ... using curl" [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + curl ${QUIET:+"$QUIET"} -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" else - curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" + curl ${QUIET:+"$QUIET"} --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi else log "Falling back to using Java to download" @@ -276,7 +282,7 @@ fi wrapperSha256Sum="" while IFS="=" read -r key value; do case "$key" in wrapperSha256Sum) - wrapperSha256Sum=$value + wrapperSha256Sum=$(trim "${value-}") break ;; esac @@ -284,7 +290,7 @@ done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" if [ -n "$wrapperSha256Sum" ]; then wrapperSha256Result=false if command -v sha256sum >/dev/null; then - if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c - >/dev/null 2>&1; then wrapperSha256Result=true fi elif command -v shasum >/dev/null; then diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd index 1204076a..c453424c 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/mvnw.cmd @@ -18,7 +18,7 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM Apache Maven Wrapper startup batch script, version 3.3.4 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @@ -119,7 +119,7 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B @@ -133,7 +133,7 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar" + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 556df472..dc372688 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -7,7 +7,7 @@ plugins { id 'maven-publish' id 'signing' - id 'org.jreleaser' version '1.19.0' + id 'org.jreleaser' version '1.20.0' id 'jacoco' id 'pmd' } @@ -35,9 +35,9 @@ dependencies { because('CVE-2025-48924') } } - implementation platform('com.google.protobuf:protobuf-bom:4.31.1') - implementation platform('io.grpc:grpc-bom:1.74.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.52.0') + implementation platform('com.google.protobuf:protobuf-bom:4.32.1') + implementation platform('io.grpc:grpc-bom:1.75.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.54.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.81' @@ -53,14 +53,14 @@ dependencies { testImplementation 'io.grpc:grpc-inprocess' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'io.opentelemetry.proto:opentelemetry-proto:1.7.0-alpha' + implementation 'io.opentelemetry.proto:opentelemetry-proto:1.8.0-alpha' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' - implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.34.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.18.1-alpha' + implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.37.0' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.20.0-alpha' } sourceSets { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68d..d4081da4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 1b964dc7111be7bfef2d8755fc7bed6a47883e28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:31:56 +0100 Subject: [PATCH 093/178] Bump kotlin and gson dependencies (#455) - Updates `org.jetbrains.kotlin.jvm` from 2.2.0 to 2.2.20 - Updates `com.google.code.gson:gson` from 2.13.1 to 2.13.2 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 572156e5..b06caf6a 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -6,7 +6,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id("com.gradleup.shadow") version "9.1.0" - id("org.jetbrains.kotlin.jvm") version "2.2.0" + id("org.jetbrains.kotlin.jvm") version "2.2.20" } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index aaafd27b..59288e8d 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -21,7 +21,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'commons-logging:commons-logging:1.3.5' - implementation 'com.google.code.gson:gson:2.13.1' + implementation 'com.google.code.gson:gson:2.13.2' } shadowJar { From 153010912bd7dd3f668591c4d48644f3a17bf37c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:03:48 +0100 Subject: [PATCH 094/178] Bump the bouncy castle dependency (#456) - Updates `org.bouncycastle:bcpkix-jdk18on` from 1.81 to 1.82 - Updates `org.bouncycastle:bcprov-jdk18on` from 1.81 to 1.82 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index dc372688..b306f5fd 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -40,8 +40,8 @@ dependencies { implementation platform('io.opentelemetry:opentelemetry-bom:1.54.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.81' - implementation 'org.bouncycastle:bcprov-jdk18on:1.81' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.82' + implementation 'org.bouncycastle:bcprov-jdk18on:1.82' implementation 'io.github.classgraph:classgraph:4.8.181' implementation 'com.github.erosb:everit-json-schema:1.14.6' implementation 'org.json:json:20250517' From eadf73e602e3b8d79d99f45b4836f03e77d9b6a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 09:46:38 +0100 Subject: [PATCH 095/178] Bump assertj and opentelemtry (#457) - Updates `org.assertj:assertj-core` from 3.27.4 to 3.27.5 - Updates `io.opentelemetry:opentelemetry-bom` from 1.54.0 to 1.54.1 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 35bdc14b..a44d5a83 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ subprojects { testImplementation platform('org.junit:junit-bom:5.13.4') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.assertj:assertj-core:3.27.4' + testImplementation 'org.assertj:assertj-core:3.27.5' testImplementation 'org.mockito:mockito-core:5.19.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 2f4c5e97..cdcf3a7a 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.4' + testImplementation 'org.assertj:assertj-core:3.27.5' testImplementation 'org.mockito:mockito-core:5.19.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index bfebe01c..5c8fb1d8 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.4' + testImplementation 'org.assertj:assertj-core:3.27.5' testImplementation 'org.mockito:mockito-core:5.19.0' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index ad54d1d7..a2c119e6 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.4' + testImplementation 'org.assertj:assertj-core:3.27.5' testImplementation 'org.mockito:mockito-core:5.19.0' } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index b306f5fd..d0fd3530 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -37,7 +37,7 @@ dependencies { } implementation platform('com.google.protobuf:protobuf-bom:4.32.1') implementation platform('io.grpc:grpc-bom:1.75.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.54.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.54.1') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.82' From d001cb43f773fafe3d13d00cbb8df370a58ee8a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:20:38 +0100 Subject: [PATCH 096/178] Bump mockito-core and maven-compiler (#458) - Updates `org.mockito:mockito-core` from 5.19.0 to 5.20.0 - Updates `org.apache.maven.plugins:maven-compiler-plugin` from 3.14.0 to 3.14.1 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/fabric-contract-example-maven/pom.xml | 4 ++-- examples/ledger-api/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index a44d5a83..d781a908 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ subprojects { testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.5' - testImplementation 'org.mockito:mockito-core:5.19.0' + testImplementation 'org.mockito:mockito-core:5.20.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' testImplementation 'org.hamcrest:hamcrest-library:3.0' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index cdcf3a7a..f2ecc0df 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.5' - testImplementation 'org.mockito:mockito-core:5.19.0' + testImplementation 'org.mockito:mockito-core:5.20.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 5c8fb1d8..78e35c6f 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.5' - testImplementation 'org.mockito:mockito-core:5.19.0' + testImplementation 'org.mockito:mockito-core:5.20.0' } shadowJar { diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index bd4938f4..e1ba3027 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -88,7 +88,7 @@ org.mockito mockito-core - 5.19.0 + 5.20.0 @@ -109,7 +109,7 @@ maven-compiler-plugin - 3.14.0 + 3.14.1 ${java.version} diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index a2c119e6..3d737c37 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.5' - testImplementation 'org.mockito:mockito-core:5.19.0' + testImplementation 'org.mockito:mockito-core:5.20.0' } shadowJar { diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 538f171c..f606e5ca 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -43,7 +43,7 @@ maven-compiler-plugin - 3.14.0 + 3.14.1 ${java.version} diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 2baa856f..62ba7b8e 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -47,7 +47,7 @@ maven-compiler-plugin - 3.14.0 + 3.14.1 ${java.version} From a4d55117a0a53aac1509f8dc474bb0d050c9fd21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 09:51:33 +0100 Subject: [PATCH 097/178] Bump assertj and opentelemetry-grpc-1.6 (#459) - Updates `org.assertj:assertj-core` from 3.27.5 to 3.27.6 - Updates `io.opentelemetry.instrumentation:opentelemetry-grpc-1.6` from 2.20.0-alpha to 2.20.1-alpha Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index d781a908..ef1e5325 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ subprojects { testImplementation platform('org.junit:junit-bom:5.13.4') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.assertj:assertj-core:3.27.5' + testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index f2ecc0df..107c0024 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.5' + testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 78e35c6f..deb5ab72 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.5' + testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 3d737c37..d346b2ea 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -16,7 +16,7 @@ dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' - testImplementation 'org.assertj:assertj-core:3.27.5' + testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index d0fd3530..62ef8d5d 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -60,7 +60,7 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.37.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.20.0-alpha' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.20.1-alpha' } sourceSets { From 175c81d6b0eaf585992e4d9ac0a486f5046d6c11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:50:42 +0100 Subject: [PATCH 098/178] Bump Gradle versions and shadow plugins (#460) - Updates `com.github.ben-manes.versions` from 0.52.0 to 0.53.0 - Updates `com.gradleup.shadow` from 9.1.0 to 9.2.1 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index ef1e5325..598f1e5a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ */ plugins { - id "com.github.ben-manes.versions" version "0.52.0" + id "com.github.ben-manes.versions" version "0.53.0" id "com.diffplug.spotless" version "7.2.1" } diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 107c0024..cfc15dba 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index b06caf6a..ade7ec84 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "9.1.0" + id("com.gradleup.shadow") version "9.2.1" id("org.jetbrains.kotlin.jvm") version "2.2.20" } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index deb5ab72..1a3753fd 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index d346b2ea..bc79455f 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 17d13b56..c2486537 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 051f2401..a181162a 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 59288e8d..68b3d3dc 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.1.0' + id 'com.gradleup.shadow' version '9.2.1' id 'java' } From 77c7b30cc84d87b62bf959e9d3b39e01336fbdf1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 09:43:07 +0100 Subject: [PATCH 099/178] Bump commons-lang3 and spotless (#461) - Updates `com.diffplug.spotless` from 7.2.1 to 8.0.0 - Updates `org.apache.commons:commons-lang3` from 3.18.0 to 3.19.0 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 598f1e5a..08184e23 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "com.github.ben-manes.versions" version "0.53.0" - id "com.diffplug.spotless" version "7.2.1" + id "com.diffplug.spotless" version "8.0.0" } version = '2.5.7' diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 62ef8d5d..378c310b 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -31,7 +31,7 @@ tasks.withType(Test).configureEach { dependencies { constraints { - pmd('org.apache.commons:commons-lang3:3.18.0') { + pmd('org.apache.commons:commons-lang3:3.19.0') { because('CVE-2025-48924') } } From 50c35d69d96b44030e00eceddb80a551f3ea7b6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Sep 2025 17:23:57 +0100 Subject: [PATCH 100/178] Bump eclipse-temurin in fabric-contract-example-as-service (#462) Bumps eclipse-temurin from 21-jre to 25-jre. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-as-service/Dockerfile b/examples/fabric-contract-example-as-service/Dockerfile index 39ff1e6c..519bfe15 100644 --- a/examples/fabric-contract-example-as-service/Dockerfile +++ b/examples/fabric-contract-example-as-service/Dockerfile @@ -15,7 +15,7 @@ RUN gradle build shadowJar # the second stage of our build just needs the compiled files -FROM eclipse-temurin:21-jre +FROM eclipse-temurin:25-jre # copy only the artifacts we need from the first stage and discard the rest COPY --from=gradle_build /home/gradle/build/libs/chaincode.jar /chaincode.jar From 859e246cc48c89436e3f472e6b052d6f2e5b24c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 12:35:22 +0100 Subject: [PATCH 101/178] Bump com.gradleup.shadow from 9.2.1 to 9.2.2 (#463) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index cfc15dba..b6b737b0 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index ade7ec84..11f7b3c8 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "9.2.1" + id("com.gradleup.shadow") version "9.2.2" id("org.jetbrains.kotlin.jvm") version "2.2.20" } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 1a3753fd..38e7c1e2 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index bc79455f..f03b683f 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index c2486537..30704f82 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index a181162a..556033ad 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 68b3d3dc..01df1e7e 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.1' + id 'com.gradleup.shadow' version '9.2.2' id 'java' } From 32442c8b95279ccd8a7a0e69cccc6a3cc9bf97bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:02:33 +0100 Subject: [PATCH 102/178] Bump docker/login-action from 3.5.0 to 3.6.0 (#464) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e4c1b63b..5c73b6f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -82,13 +82,13 @@ jobs: - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -137,7 +137,7 @@ jobs: pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} From 0bb82871581e68871cb71fd62d22e455a7232bae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:03:21 +0100 Subject: [PATCH 103/178] Bump gradle/actions from 4.4.3 to 4.4.4 (#465) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c73b6f1..0db7247b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Publish to Maven Central run: | ./gradlew publishAllPublicationsToStagingRepository @@ -76,7 +76,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 4946d9f2..ffc34f41 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -28,6 +28,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 64dd9c2d..fbfa9fba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 61a35b9e471d80257f5413c604f02ae2124368fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 10:35:56 +0100 Subject: [PATCH 104/178] Bump gradle/actions from 4.4.4 to 5.0.0 (#467) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0db7247b..3ab50ff6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Publish to Maven Central run: | ./gradlew publishAllPublicationsToStagingRepository @@ -76,7 +76,7 @@ jobs: with: distribution: "temurin" java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index ffc34f41..97534225 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -28,6 +28,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fbfa9fba..7f406c11 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 21 - - uses: gradle/actions/setup-gradle@748248ddd2a24f49513d8f472f81c3a07d4d50e1 # v4.4.4 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 6016715cb476d7facc781b41519d316aa3988441 Mon Sep 17 00:00:00 2001 From: Jessica G Date: Thu, 2 Oct 2025 05:25:39 -0700 Subject: [PATCH 105/178] fix: examples/fabric-contract-example-maven/pom.xml to reduce vulnerabilities (#469) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JAVA-CHQOSLOGBACK-13169722 Signed-off-by: snyk-bot --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index e1ba3027..5d5c9d73 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.6 - 1.5.18 + 1.5.19 2.0.17 From 658983f8e48ff3372eaab6cf7f045c1319834103 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Fri, 3 Oct 2025 17:12:27 +0100 Subject: [PATCH 106/178] Update versions following v2.5.7 release (#468) Signed-off-by: Mark S. Lewis --- RELEASING.md | 4 ++-- build.gradle | 3 +-- examples/fabric-contract-example-as-service/build.gradle | 2 +- .../fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/fabric-contract-example-maven/pom.xml | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 13 files changed, 14 insertions(+), 15 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index c0366a4c..b4a5308e 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -27,7 +27,7 @@ See previous releases for examples of the title and description. ## After releasing - Update the version number in `build.gradle` to the next version. -- Update version numbers in `fabric-chaincode-docker/build.gradle` to match the next version. +- Update image version numbers in `fabric-chaincode-docker/build.gradle` to match the next version. - Update the `fabric-chaincode-shim` dependency version in all `build.gradle` and `pom.xml` files within `fabric-chaincode-integration-test/src/contracts` to match the next version. -- Update the `fabric-chaincode-shim` dependency version in all `build.gradle`, `build.gradle.kts` and `pom.xml` files within `examples` to mast the last _released_ version. +- Update the `fabric-chaincode-shim` dependency version in all `build.gradle`, `build.gradle.kts` and `pom.xml` files within `examples` to match the last _released_ version. - Check that `COMPATIBILITY.md` is correct and update if required. diff --git a/build.gradle b/build.gradle index 08184e23..3ca79b2d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,8 +9,7 @@ plugins { id "com.diffplug.spotless" version "8.0.0" } -version = '2.5.7' - +version = '2.5.8' // If the nightly property is set, then this is the scheduled main // build - and we should publish this to artifactory diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index b6b737b0..84809d6e 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.6' diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 11f7b3c8..b977b98b 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -14,7 +14,7 @@ plugins { version = "0.0.1" dependencies { - implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6") + implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7") implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 38e7c1e2..8ccefd8b 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.6' diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 5d5c9d73..1b198b95 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.6 + 2.5.7 1.5.19 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index f03b683f..b87a56bf 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.6' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' testImplementation 'org.assertj:assertj-core:3.27.6' diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 97f95226..3f0ae0a2 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -59,5 +59,5 @@ tasks.register('copyAllDeps', Copy) { tasks.register('buildImage', DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.7', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.8', 'hyperledger/fabric-javaenv:amd64-latest'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index 30704f82..f176b86b 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index f606e5ca..b6962bc2 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.7 + 2.5.8 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 556033ad..053c3dd5 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 01df1e7e..4fb54344 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'commons-logging:commons-logging:1.3.5' implementation 'com.google.code.gson:gson:2.13.2' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 62ba7b8e..1b494496 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.7 + 2.5.8 From a92703055f1e9615acca6e5567f302417efb5dea Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 6 Oct 2025 17:30:52 +0100 Subject: [PATCH 107/178] Update Junit from 5.13.4 to 6.0.0 (#472) Requires a minimum of Java 17 for compilation. The release target remains Java 11. This change also enabled Java compiler linting and fails on linting errors. To address lint failures in the existing codebase, the bahviour of the org.hyperledger.fabric.Logger constructor has changed to avoid a potential 'this' escape. Any subclasses must now ensure that the parent logger is set explicitly after construction by calling setParent(Logger). No changes are required for code obtaining logger instances using the static Logger.getLogger(String) method. Signed-off-by: Mark S. Lewis --- build.gradle | 12 +++------- .../build.gradle | 3 ++- .../build.gradle | 4 +++- .../fabric-contract-example-maven/pom.xml | 22 ++++++++++------- examples/ledger-api/build.gradle | 4 +++- .../java/org/hyperledger/fabric/Logger.java | 14 +++++++---- .../routing/impl/SerializerRegistryImpl.java | 24 ++++++++++++------- .../shim/impl/QueryResultsIteratorImpl.java | 2 +- .../shim/ledger/QueryResultsIterator.java | 5 +++- .../QueryResultsIteratorWithMetadata.java | 3 +++ 10 files changed, 57 insertions(+), 36 deletions(-) diff --git a/build.gradle b/build.gradle index 3ca79b2d..c46c886b 100644 --- a/build.gradle +++ b/build.gradle @@ -46,22 +46,16 @@ subprojects { group = 'org.hyperledger.fabric-chaincode-java' version = rootProject.version - java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - compileJava { - if (javaCompiler.get().metadata.languageVersion.canCompileOrRun(10)) { - options.release = 11 - } + options.release = 11 + options.compilerArgs += ['-Werror', '-Xlint:all'] } dependencies { implementation 'commons-cli:commons-cli:1.10.0' implementation 'commons-logging:commons-logging:1.3.5' - testImplementation platform('org.junit:junit-bom:5.13.4') + testImplementation platform('org.junit:junit-bom:6.0.0') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.6' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 84809d6e..4c2aaeba 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -15,7 +15,8 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' + testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 8ccefd8b..eb1923b0 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -15,9 +15,11 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' + testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } shadowJar { diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 1b198b95..dda0979e 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -18,10 +18,6 @@ 1.5.19 2.0.17 - - 5.13.4 - 1.13.1 - @@ -31,7 +27,19 @@ - + + + + org.junit + junit-bom + 6.0.0 + pom + import + + + + + @@ -69,19 +77,16 @@ org.junit.jupiter junit-jupiter-api - ${junit.jupiter.version} compile org.junit.jupiter junit-jupiter-params - ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-engine - ${junit.jupiter.version} test @@ -102,7 +107,6 @@ src - maven-surefire-plugin 3.5.4 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index b87a56bf..07863155 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -15,9 +15,11 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' - testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4' + testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } shadowJar { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java index 35720635..4e8a6e4a 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/Logger.java @@ -14,11 +14,15 @@ /** Logger class to use throughout the Contract Implementation. */ public class Logger extends java.util.logging.Logger { + /** + * Subclasses must ensure that a parent logger is set appropriately, for example: + * + *

      SdO`o?U^bCPz6Ehh!k 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


      Xdyd*p!l1Y@nCA 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 19a6bdeb..c61a118f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a..739907df 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/.

      {@code logger.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric"))} + * + * @param name A name for the logger. + */ protected Logger(final String name) { super(name, null); - - // ensure that the parent logger is set - super.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric")); } /** @@ -26,7 +30,9 @@ protected Logger(final String name) { * @return Logger */ public static Logger getLogger(final String name) { - return new Logger(name); + Logger result = new Logger(name); + result.setParent(java.util.logging.Logger.getLogger("org.hyperledger.fabric")); + return result; } /** @param msgSupplier */ diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java index 99a41e03..ecd406e8 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/routing/impl/SerializerRegistryImpl.java @@ -8,6 +8,7 @@ import io.github.classgraph.ClassGraph; import io.github.classgraph.ClassInfo; import io.github.classgraph.ScanResult; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -41,15 +42,20 @@ public SerializerInterface getSerializer(final String name, final Serializer.TAR return contents.get(key); } - private SerializerInterface add( - final String name, final Serializer.TARGET target, final Class clazz) + private void add(final String name, final Serializer.TARGET target, final Class clazz) throws InstantiationException, IllegalAccessException { LOGGER.debug(() -> "Adding new Class " + clazz.getCanonicalName() + " for " + target); final String key = name + ":" + target; - final SerializerInterface newObj = clazz.newInstance(); - this.contents.put(key, newObj); - - return newObj; + try { + final SerializerInterface newObj = + (SerializerInterface) clazz.getDeclaredConstructor().newInstance(); + this.contents.put(key, newObj); + } catch (InvocationTargetException | NoSuchMethodException e) { + InstantiationException wrapper = new InstantiationException( + "Exception constructing " + clazz.getCanonicalName() + ": " + e.getMessage()); + wrapper.addSuppressed(e); + throw wrapper; + } } /** @@ -67,10 +73,10 @@ public void findAndSetContents() throws InstantiationException, IllegalAccessExc final Set seenClass = new HashSet<>(); try (ScanResult scanResult = classGraph.scan()) { - for (final ClassInfo classInfo : - scanResult.getClassesWithAnnotation(this.ANNOTATION_CLASS.getCanonicalName())) { + for (final ClassInfo classInfo : scanResult.getClassesWithAnnotation(ANNOTATION_CLASS.getCanonicalName())) { LOGGER.debug(() -> "Found class with contract annotation: " + classInfo.getName()); - final Class cls = (Class) classInfo.loadClass(); + + final Class cls = classInfo.loadClass(); LOGGER.debug("Loaded class"); final String className = cls.getCanonicalName(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java index 89350204..fdddfb75 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/QueryResultsIteratorImpl.java @@ -107,7 +107,7 @@ public T next() { } @Override - public void close() throws Exception { + public void close() { final ByteString requestPayload = QueryStateClose.newBuilder() .setId(currentQueryResponse.getId()) diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIterator.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIterator.java index e31dfcb6..f37b6cab 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIterator.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIterator.java @@ -12,4 +12,7 @@ * * @param the type of elements returned by the iterator */ -public interface QueryResultsIterator extends Iterable, AutoCloseable {} +public interface QueryResultsIterator extends Iterable, AutoCloseable { + @Override + void close(); +} diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java index b5c45cfa..9bed89aa 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ledger/QueryResultsIteratorWithMetadata.java @@ -18,4 +18,7 @@ public interface QueryResultsIteratorWithMetadata extends Iterable, AutoCloseable { /** @return Query Metadata */ QueryResponseMetadata getMetadata(); + + @Override + void close(); } From 6d84e994a826d446f500dad4a6f8950ab37a5c4a Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 7 Oct 2025 15:56:39 +0100 Subject: [PATCH 108/178] Use Java 25 and Gradle 9 (#471) - Docker image includes Java 25 and Gradle 9. - Java 25 is used to compile and test. - Java 11 remains the minimum supported version. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 6 ++--- .github/workflows/scan.yml | 4 ++-- .github/workflows/test.yml | 6 ++--- build.gradle | 2 +- fabric-chaincode-docker/Dockerfile | 28 +++++++++++------------ fabric-chaincode-docker/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 4 ---- gradle/wrapper/gradle-wrapper.jar | Bin 43764 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 +--- gradlew.bat | 3 +-- 11 files changed, 27 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ab50ff6..9ac5a160 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" - java-version: 21 + java-version: 25 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Publish to GitHub Packages run: | @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" - java-version: 21 + java-version: 25 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Publish to Maven Central run: | @@ -75,7 +75,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" - java-version: 21 + java-version: 25 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 97534225..0f30399c 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin - java-version: 21 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + java-version: 25 + - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f406c11..2238ffe2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin - java-version: 21 + java-version: 25 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -36,7 +36,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin - java-version: 21 + java-version: 25 - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: "lts/*" @@ -72,7 +72,7 @@ jobs: - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: temurin - java-version: 21 + java-version: 25 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage diff --git a/build.gradle b/build.gradle index c46c886b..b873e3ac 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ subprojects { spotless { java { removeUnusedImports() - palantirJavaFormat('2.67.0').formatJavadoc(true) + palantirJavaFormat().formatJavadoc(true) formatAnnotations() } } diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 894b6494..75415c38 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -1,34 +1,34 @@ -ARG JAVA_IMAGE=eclipse-temurin:21-jdk +ARG JAVA_IMAGE=eclipse-temurin:25-jdk FROM ${JAVA_IMAGE} AS builder -ENV DEBIAN_FRONTEND=noninteractive -# Build tools RUN apt-get update \ - && apt-get -y install zip unzip \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* + && apt-get install -y curl zip unzip RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] RUN source /root/.sdkman/bin/sdkman-init.sh \ - && sdk install gradle 8.14.3 \ + && sdk install gradle 9.1.0 \ && sdk install maven 3.9.11 FROM ${JAVA_IMAGE} AS dependencies -COPY --from=builder /root/.sdkman/candidates/gradle/current /usr/bin/gradle -COPY --from=builder /root/.sdkman/candidates/maven/current /usr/bin/maven +COPY --from=builder /root/.sdkman/candidates/gradle/current /opt/gradle +COPY --from=builder /root/.sdkman/candidates/maven/current /opt/maven SHELL ["/bin/bash", "-c"] -ENV PATH="/usr/bin/maven/bin:/usr/bin/maven/:/usr/bin/gradle:/usr/bin/gradle/bin:${PATH}" +ENV PATH="/opt/maven/bin:/opt/gradle/bin:${PATH}" # Coping libs, scripts and sources -ADD build/distributions/ /root/ +COPY build/distributions/ /root/ #Creating folders structure -RUN mkdir -p /root/chaincode-java/chaincode/src /root/chaincode-java/chaincode/build/out +RUN mkdir -p \ + /root/chaincode-java/chaincode/src \ + /root/chaincode-java/chaincode/build/out \ + /root/chaincode-java/shim-src/fabric-chaincode-integration-test \ + /root/chaincode-java/shim-src/fabric-chaincode-docker #Making scripts runnable RUN chmod +x /root/chaincode-java/start /root/chaincode-java/build.sh @@ -51,7 +51,7 @@ WORKDIR /root/chaincode-java #Gradle doesn't run without settings.gradle file, so create one RUN touch settings.gradle \ && gradle wrapper \ - && ./gradlew --version \ + && ./gradlew wrapper \ && mvn -N wrapper:wrapper # Creating final javaenv image which will include all required @@ -59,7 +59,7 @@ RUN touch settings.gradle \ FROM ${JAVA_IMAGE} RUN apt-get update \ - && apt-get -y install zip unzip \ + && apt-get install -y zip unzip \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /chaincode/input \ diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 3f0ae0a2..3669c2c1 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -59,5 +59,5 @@ tasks.register('copyAllDeps', Copy) { tasks.register('buildImage', DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:amd64-2.5.8', 'hyperledger/fabric-javaenv:amd64-latest'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:2.5.8'] } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 378c310b..de6302a0 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -78,10 +78,6 @@ sourceSets { } -jacoco { - toolVersion = "0.8.12" -} - jacocoTestReport { afterEvaluate { classDirectories.from = files(classDirectories.files.collect { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baabb587c669f562ae36f953de2481846..8bdaf60c75ab801e22807dde59e12a8735a34077 100644 GIT binary patch delta 37256 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 delta 35551 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d4081da4..2e111328 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a93..adff685a 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index 5eed7ee8..e509b2dd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From a0852136270cab008069780304a56732de1f99ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 11:03:46 +0100 Subject: [PATCH 109/178] Bump actions/setup-node from 5.0.0 to 6.0.0 (#474) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2238ffe2..e1bb344b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 From 2e0dd6f468e61256b550942ffe6bb91dff3d00a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 17:11:13 +0100 Subject: [PATCH 110/178] Bump gRPC and OpenTelemetry dependencies (#475) - Updates `io.grpc:grpc-bom` from 1.75.0 to 1.76.0 - Updates `io.opentelemetry:opentelemetry-bom` from 1.54.1 to 1.55.0 - Updates `io.github.classgraph:classgraph` from 4.8.181 to 4.8.184 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- fabric-chaincode-shim/build.gradle | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index b977b98b..6295ba37 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.junit.jupiter:junit-jupiter:5.13.4") + testImplementation("org.junit.jupiter:junit-jupiter:6.0.0") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index de6302a0..81366e15 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -36,13 +36,13 @@ dependencies { } } implementation platform('com.google.protobuf:protobuf-bom:4.32.1') - implementation platform('io.grpc:grpc-bom:1.75.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.54.1') + implementation platform('io.grpc:grpc-bom:1.76.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.55.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.82' implementation 'org.bouncycastle:bcprov-jdk18on:1.82' - implementation 'io.github.classgraph:classgraph:4.8.181' + implementation 'io.github.classgraph:classgraph:4.8.184' implementation 'com.github.erosb:everit-json-schema:1.14.6' implementation 'org.json:json:20250517' implementation 'com.google.protobuf:protobuf-java-util' From b67164effcbd9b8968a80243d6cd23ec6e7103b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:49:33 +0100 Subject: [PATCH 111/178] Bump com.google.protobuf:protobuf-bom from 4.32.1 to 4.33.0 (#477) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 81366e15..f7bf964e 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -35,7 +35,7 @@ dependencies { because('CVE-2025-48924') } } - implementation platform('com.google.protobuf:protobuf-bom:4.32.1') + implementation platform('com.google.protobuf:protobuf-bom:4.33.0') implementation platform('io.grpc:grpc-bom:1.76.0') implementation platform('io.opentelemetry:opentelemetry-bom:1.55.0') From 7d6c6be5abc4fc208117c1025280b9bd09e84502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:30:21 +0000 Subject: [PATCH 112/178] Bump ch.qos.logback:logback-classic from 1.5.19 to 1.5.20 (#478) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index dda0979e..86f02804 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.19 + 1.5.20 2.0.17 From 27ff01866d81a84f1d294062f1846e249b333bd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 09:56:40 +0100 Subject: [PATCH 113/178] Bump opentelemetry-grpc-1.6 to 2.21.0-alpha (#479) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- fabric-chaincode-shim/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index f7bf964e..33b9f2f9 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -60,7 +60,7 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.37.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.20.1-alpha' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.21.0-alpha' } sourceSets { From 8c81b7bfd35c7e49fd69e578f0fd231f2b0835b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 12:31:27 +0100 Subject: [PATCH 114/178] Bump org.jetbrains.kotlin.jvm from 2.2.20 to 2.2.21 (#480) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 6295ba37..67ef2e41 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -6,7 +6,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id("com.gradleup.shadow") version "9.2.2" - id("org.jetbrains.kotlin.jvm") version "2.2.20" + id("org.jetbrains.kotlin.jvm") version "2.2.21" } From 7a21bdaef7fbf1664dd8086d6f0bcfd4c98c8548 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:48:56 +0000 Subject: [PATCH 115/178] Bump actions/upload-artifact from 4.6.2 to 5.0.0 (#482) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ac5a160..c4f0292c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -110,7 +110,7 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: digest-${{ matrix.arch.platform }} path: ${{ runner.temp }}/digests/* From 43fb4c4c69139b47019cfa33d262077267c611b4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 11:00:45 +0000 Subject: [PATCH 116/178] Bump actions/download-artifact from 5.0.0 to 6.0.0 (#481) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4f0292c..4d92a6c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -131,7 +131,7 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: path: ${{ runner.temp }}/digests pattern: digest-* From 08a5b746b2d20da80e261ab50edcf8d8bc1608a8 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Tue, 28 Oct 2025 18:20:12 +0000 Subject: [PATCH 117/178] Use lighter weight Maven Central publishing plugin (#473) JReleaser is a large plugin intended to manage the whole project release lifecycle. It was only being used to publish to the new Maven Central Publisher API. Some transitive dependencies conflict with those of Spotless 8.x. This change switches to the GradleUp nmcp (New Maven Central Publishing) plugin. It provides only the required publishing capability and is much lighter weight. Signed-off-by: Mark S. Lewis --- .github/workflows/release.yml | 7 ++--- build.gradle | 14 ++++++++++ fabric-chaincode-shim/build.gradle | 44 +++++++----------------------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4d92a6c2..811867fc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,13 +48,12 @@ jobs: - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Publish to Maven Central run: | - ./gradlew publishAllPublicationsToStagingRepository - ./gradlew jreleaserDeploy --stacktrace + ./gradlew publishAggregationToCentralPortal env: ORG_GRADLE_PROJECT_signingKey: ${{ secrets.OSSRH_GPG_SECRET_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} - JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.MAVENCENTRAL_USERNAME }} - JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.MAVENCENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVENCENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVENCENTRAL_PASSWORD }} docker-build-push: name: Push Docker image diff --git a/build.gradle b/build.gradle index b873e3ac..af1ae99d 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,8 @@ plugins { id "com.github.ben-manes.versions" version "0.53.0" id "com.diffplug.spotless" version "8.0.0" + id "com.gradleup.nmcp.aggregation" version "1.2.0" + id "com.gradleup.nmcp" version "1.2.0" apply false } version = '2.5.8' @@ -22,6 +24,18 @@ if (properties.containsKey('NIGHTLY')) { ext.nightly = false } +nmcpAggregation { + centralPortal { + username = findProperty('mavenCentralUsername') + password = findProperty('mavenCentralPassword') + publishingType = "AUTOMATIC" + } +} + +dependencies { + nmcpAggregation(project(':fabric-chaincode-shim')) +} + allprojects { apply plugin: "com.diffplug.spotless" diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 33b9f2f9..5aca7063 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -7,9 +7,9 @@ plugins { id 'maven-publish' id 'signing' - id 'org.jreleaser' version '1.20.0' id 'jacoco' id 'pmd' + id "com.gradleup.nmcp" } pmd { @@ -224,8 +224,8 @@ javadoc { def final stagingDeployUrl = layout.buildDirectory.dir('staging-deploy') publishing { - publications { - shim(MavenPublication) { + publications { + shim(MavenPublication) { groupId = project.group artifactId = project.name version = project.version @@ -261,16 +261,10 @@ publishing { } } } - } - - } - - repositories { - maven { - name = "Staging" - url = stagingDeployUrl } + } + repositories { maven { name = "GitHub" url = "https://maven.pkg.github.com/hyperledger/fabric-chaincode-java" @@ -283,34 +277,16 @@ publishing { } signing { - required = { gradle.taskGraph.hasTask(":${project.name}:publishShimPublicationToStagingRepository") } - def signingKey = findProperty('signingKey') def signingPassword = findProperty('signingPassword') useInMemoryPgpKeys(signingKey, signingPassword) - sign publishing.publications.shim -} - -jreleaser { - gitRootSearch = true - deploy { - maven { - mavenCentral { - sonatype { - active = 'ALWAYS' - url = 'https://central.sonatype.com/api/v1/publisher' - sign = false - stagingRepository(file(stagingDeployUrl).toString()) - } - } - } - } - release { - github { - enabled = false - } + required = { + gradle.taskGraph.hasTask(":${project.name}:publishShimPublicationToNmcpRepository") + || gradle.taskGraph.hasTask(":${project.name}:publishShimPublicationToGitHubRepository") } + + sign publishing.publications.shim } // Need to specify the sourcesJar task BEFORE the java{withSourcesJar()} so that it picks up the duplicatesStratergy From 4cc83abf44228abaad133e6ec2b445eafca6785b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 08:54:20 +0000 Subject: [PATCH 118/178] Bump docker/metadata-action from 5.8.0 to 5.9.0 (#483) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 811867fc..345eda56 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -143,7 +143,7 @@ jobs: password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Docker metadata id: meta - uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0 + uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 with: images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | From 57a7c3f366ffb8d964ed87a4355a46f732f6afb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 08:50:18 +0000 Subject: [PATCH 119/178] Bump JUnit and logback (#484) - Updates `org.junit:junit-bom` from 6.0.0 to 6.0.1 - Updates `ch.qos.logback:logback-classic` from 1.5.20 to 1.5.21 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 86f02804..b1aa1ee1 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.20 + 1.5.21 2.0.17 @@ -32,7 +32,7 @@ org.junit junit-bom - 6.0.0 + 6.0.1 pom import From 4e4accaac219c7544ad98625e82dda2cc8b0bba6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:40:39 +0000 Subject: [PATCH 120/178] Bump actions/checkout from 5.0.0 to 5.0.1 (#485) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 345eda56..76a6c067 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -40,7 +40,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -70,7 +70,7 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 0f30399c..378bc999 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,7 +16,7 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e1bb344b..92332eb0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -30,7 +30,7 @@ jobs: intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -66,7 +66,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 From 5f6f72f35ff4e6446ca35255ee3bd7662cbbe68b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:07:11 +0000 Subject: [PATCH 121/178] Bump actions/setup-go from 6.0.0 to 6.1.0 (#486) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 378bc999..08996f2d 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -20,7 +20,7 @@ jobs: with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier - - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: stable cache: false From ad189f04d7fe302767c64389aa9e5f85c9925c96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:24:01 +0000 Subject: [PATCH 122/178] Bump actions/checkout from 5.0.1 to 6.0.0 (#487) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76a6c067..21b39785 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -40,7 +40,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -70,7 +70,7 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 08996f2d..d5437266 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,7 +16,7 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 92332eb0..695acd49 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -30,7 +30,7 @@ jobs: intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -66,7 +66,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 From e301654db1ec4ffb458cf9bf5f2d15d725f54fb1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 14:14:38 +0000 Subject: [PATCH 123/178] Bump docker/metadata-action from 5.9.0 to 5.10.0 (#488) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21b39785..11b1b7fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -143,7 +143,7 @@ jobs: password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Docker metadata id: meta - uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 with: images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | From e2ab8d1ceab1200e1c153d35b9fe11d0f6891fff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:55:29 +0000 Subject: [PATCH 124/178] Bump actions/checkout from 6.0.0 to 6.0.1 (#489) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 11b1b7fd..fcf440cf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -40,7 +40,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" @@ -70,7 +70,7 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: "temurin" diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index d5437266..4b5eb8a9 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,7 +16,7 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 695acd49..ba8e71d5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -30,7 +30,7 @@ jobs: intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 @@ -66,7 +66,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 From 1705234831bcdf0633fd8b1effd04f77daa6c3c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:56:02 +0000 Subject: [PATCH 125/178] Bump actions/setup-node from 6.0.0 to 6.1.0 (#490) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ba8e71d5..3afb0fde 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 From 375361f929cef0a9eb0980415c370884486244fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:42:35 +0000 Subject: [PATCH 126/178] Bump actions/setup-java from 5.0.0 to 5.1.0 (#491) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fcf440cf..61be0c99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: packages: write steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" java-version: 25 @@ -41,7 +41,7 @@ jobs: contents: read steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" java-version: 25 @@ -71,7 +71,7 @@ jobs: runner: ubuntu-24.04-arm steps: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" java-version: 25 diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 4b5eb8a9..635d952f 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -24,7 +24,7 @@ jobs: with: go-version: stable cache: false - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin java-version: 25 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3afb0fde..df01c8e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin java-version: 25 @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin java-version: 25 @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin java-version: 25 From be7e929f802d0155e5261a724ae038e641bbd612 Mon Sep 17 00:00:00 2001 From: Muthu Date: Fri, 5 Dec 2025 23:01:16 +0530 Subject: [PATCH 127/178] Bump the java group and grpc-bom,junit (#492) Signed-off-by: Muthu Sundaravadivel Co-authored-by: Muthu Sundaravadivel --- examples/fabric-contract-example-as-service/build.gradle | 2 +- .../fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 4c2aaeba..69e14e21 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' - testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation platform('org.junit:junit-bom:6.0.1') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 67ef2e41..ab6300f7 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.junit.jupiter:junit-jupiter:6.0.0") + testImplementation("org.junit.jupiter:junit-jupiter:6.0.1") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index eb1923b0..3eeabd76 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -15,7 +15,7 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' implementation 'org.json:json:20250517' - testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation platform('org.junit:junit-bom:6.0.1') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' testImplementation 'org.mockito:mockito-core:5.20.0' diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index 5aca7063..c864a48b 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -36,8 +36,8 @@ dependencies { } } implementation platform('com.google.protobuf:protobuf-bom:4.33.0') - implementation platform('io.grpc:grpc-bom:1.76.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.55.0') + implementation platform('io.grpc:grpc-bom:1.77.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.56.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'org.bouncycastle:bcpkix-jdk18on:1.82' From 57fd7f12fbe11ac72e8898206eec6b9e5e03de08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:44:40 +0000 Subject: [PATCH 128/178] Bump org.mockito:mockito-core from 5.20.0 to 5.21.0 (#493) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index b1aa1ee1..50b6ab77 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -93,7 +93,7 @@ org.mockito mockito-core - 5.20.0 + 5.21.0 From f086cd187d88d70a184431297392879ebb9408b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:12:40 +0000 Subject: [PATCH 129/178] Bump ch.qos.logback:logback-classic from 1.5.21 to 1.5.22 (#494) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 50b6ab77..7193adda 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.21 + 1.5.22 2.0.17 From 6615b8ee2cfa5c45231a99d93754dd1dfe9660c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 12:42:49 +0000 Subject: [PATCH 130/178] Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#496) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 61be0c99..f7b83ca1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,7 +109,7 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: digest-${{ matrix.arch.platform }} path: ${{ runner.temp }}/digests/* From 69cb5bca16b6dc3ea65eb1d8f70b36349e93777b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 12:43:16 +0000 Subject: [PATCH 131/178] Bump actions/download-artifact from 6.0.0 to 7.0.0 (#495) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7b83ca1..b0d086d3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,7 +130,7 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: path: ${{ runner.temp }}/digests pattern: digest-* From c257f8ded5b3cfbc5a749feecde569e730b80ba4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:49:30 +0100 Subject: [PATCH 132/178] Bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#497) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0d086d3..e80d9da5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,7 +93,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build image id: build uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 @@ -151,7 +151,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Create and push manifest list working-directory: ${{ runner.temp }}/digests run: | From 3e0111581bb7117f9d67ff6436c49deb401bce95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:51:17 +0100 Subject: [PATCH 133/178] Bump ch.qos.logback:logback-classic from 1.5.22 to 1.5.23 (#498) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 7193adda..a5ffef45 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.22 + 1.5.23 2.0.17 From 4e2766b848db7e2ad8d2c8cb7378dbafc9955973 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Dec 2025 01:30:50 +0100 Subject: [PATCH 134/178] Bump org.json:json from 20250517 to 20251224 (#499) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index a5ffef45..6114077f 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -100,7 +100,7 @@ org.json json - 20250517 + 20251224 From ffa97c604e8c9e6d4f15c77eb7fb77f11f616e96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 09:16:01 +0000 Subject: [PATCH 135/178] Bump logback-classic and junit in examples (#500) - Updates `org.junit:junit-bom` from 6.0.1 to 6.0.2 - Updates `ch.qos.logback:logback-classic` from 1.5.23 to 1.5.24 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 6114077f..4bc6513f 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.23 + 1.5.24 2.0.17 @@ -32,7 +32,7 @@ org.junit junit-bom - 6.0.1 + 6.0.2 pom import From abd481da75f8373112926be581bfc60eb07613b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 10:04:36 +0000 Subject: [PATCH 136/178] Bump actions/setup-go from 6.1.0 to 6.2.0 (#501) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 635d952f..81c560e9 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -20,7 +20,7 @@ jobs: with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier - - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: go-version: stable cache: false From 22fdfa3b518a4a2e5a60d4f43b90e99fa04b2401 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:50:47 +0000 Subject: [PATCH 137/178] Bump actions/setup-node from 6.1.0 to 6.2.0 (#502) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index df01c8e5..51875166 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 From 481276c8a1897e937d44bdf15d1c188e53d3924e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 09:41:49 +0000 Subject: [PATCH 138/178] Bump ch.qos.logback:logback-classic from 1.5.24 to 1.5.25 (#503) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 4bc6513f..4f6ae2f0 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.24 + 1.5.25 2.0.17 From bdb8e5af8a184e04bc85da683dafa1bda5b7dd9e Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Wed, 21 Jan 2026 12:18:00 +0000 Subject: [PATCH 139/178] Fix vulnerability scan of release version (#504) The Gradle version use in v2.5.7 and earlier does not support Java 25. Generation of Gradle lockfile (used as input to the vulnerability scan) has just started actively failing with Java 25. This change uses Java 21 for vulnerability scanning, which is supported by Gradle 8.5 and later. Signed-off-by: Mark S. Lewis --- .github/workflows/scan.yml | 9 +++++---- .github/workflows/scheduled-scan.yml | 14 +++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 81c560e9..9ffd926e 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,18 +16,19 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier - - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 with: go-version: stable cache: false - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: temurin - java-version: 25 + # Releases v2.5.7 and earlier do not support Java 25 + java-version: 21 - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 - name: Scan run: make scan diff --git a/.github/workflows/scheduled-scan.yml b/.github/workflows/scheduled-scan.yml index cfbe5687..191af837 100644 --- a/.github/workflows/scheduled-scan.yml +++ b/.github/workflows/scheduled-scan.yml @@ -9,7 +9,7 @@ permissions: contents: read jobs: - latest-release-version: + release-version: name: Get latest release tag runs-on: ubuntu-latest outputs: @@ -18,9 +18,13 @@ jobs: - id: tag-name run: echo "value=$(curl --location --silent --fail "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest" | jq --raw-output '.tag_name')" >> "${GITHUB_OUTPUT}" - scan: - name: Scan ${{ needs.latest-release-version.outputs.tag_name }} - needs: latest-release-version + scan-release: + name: Scan ${{ needs.release-version.outputs.tag_name }} + needs: release-version uses: ./.github/workflows/scan.yml with: - ref: ${{ needs.latest-release-version.outputs.tag_name }} + ref: ${{ needs.release-version.outputs.tag_name }} + + scan-latest: + name: Scan latest + uses: ./.github/workflows/scan.yml From ce5bb181e2a8e03e98b136b69817150219bc462f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 08:59:05 +0000 Subject: [PATCH 140/178] Bump actions/checkout from 6.0.1 to 6.0.2 (#507) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e80d9da5..b813ba86 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" @@ -40,7 +40,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" @@ -70,7 +70,7 @@ jobs: - platform: linux-arm64 runner: ubuntu-24.04-arm steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 with: distribution: "temurin" diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 9ffd926e..6e481328 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -16,7 +16,7 @@ jobs: osv-scanner: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 51875166..049478cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 @@ -30,7 +30,7 @@ jobs: intergationtest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 @@ -66,7 +66,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 From 65de0fde9ef68eb939ab819b50adc27939051704 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:08:03 +0000 Subject: [PATCH 141/178] Bump actions/setup-java from 5.1.0 to 5.2.0 (#506) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b813ba86..0d6716ae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ jobs: packages: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: "temurin" java-version: 25 @@ -41,7 +41,7 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: "temurin" java-version: 25 @@ -71,7 +71,7 @@ jobs: runner: ubuntu-24.04-arm steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: "temurin" java-version: 25 diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 6e481328..70db6ada 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -24,7 +24,7 @@ jobs: with: go-version: stable cache: false - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 049478cc..a828813f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: 25 @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: 25 @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref }} - - uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0 + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: 25 From f891ad4bc864f8586d61b4101bdbbb73f62b7749 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 08:54:58 +0000 Subject: [PATCH 142/178] Bump ch.qos.logback:logback-classic from 1.5.25 to 1.5.26 (#508) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 4f6ae2f0..22b7e25d 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.7 - 1.5.25 + 1.5.26 2.0.17 From 65da468e61cd3c5e88c30f1713ddf468c27e833d Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 26 Jan 2026 19:08:15 +0000 Subject: [PATCH 143/178] Update Gradle to 9.3.0 and Maven to 3.9.12 (#505) This change updates both the Gradle wrapper used for the build, and also the Gradle version bundled in the fabric-javaenv Docker image. Maven is also updated to 3.9.12 within the Docker image. Several dependency versions are also updated. Signed-off-by: Mark S. Lewis --- build.gradle | 12 ++++++------ .../build.gradle | 8 ++++---- .../build.gradle.kts | 2 +- .../build.gradle | 8 ++++---- .../fabric-contract-example-maven/pom.xml | 13 +++++-------- examples/ledger-api/build.gradle | 8 ++++---- fabric-chaincode-docker/Dockerfile | 8 ++++---- fabric-chaincode-docker/build.gradle | 2 +- .../build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../contracts/fabric-ledger-api/build.gradle | 2 +- .../contracts/fabric-shim-api/build.gradle | 2 +- fabric-chaincode-shim/build.gradle | 18 +++++++++--------- .../fabric/contract/ContractRouter.java | 2 +- .../execution/JSONTransactionSerializer.java | 7 ++++++- .../fabric/ledger/impl/LedgerImpl.java | 1 - .../shim/ChaincodeServerProperties.java | 2 +- .../sbe/impl/StateBasedEndorsementImpl.java | 4 ++-- .../shim/impl/ChaincodeInvocationTask.java | 2 +- .../impl/OpenTelemetryTracesProvider.java | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 45457 -> 46175 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 22 files changed, 55 insertions(+), 54 deletions(-) diff --git a/build.gradle b/build.gradle index af1ae99d..7dbadf7e 100644 --- a/build.gradle +++ b/build.gradle @@ -6,9 +6,9 @@ plugins { id "com.github.ben-manes.versions" version "0.53.0" - id "com.diffplug.spotless" version "8.0.0" - id "com.gradleup.nmcp.aggregation" version "1.2.0" - id "com.gradleup.nmcp" version "1.2.0" apply false + id "com.diffplug.spotless" version "8.1.0" + id "com.gradleup.nmcp.aggregation" version "1.4.3" + id "com.gradleup.nmcp" version "1.4.3" apply false } version = '2.5.8' @@ -66,14 +66,14 @@ subprojects { } dependencies { - implementation 'commons-cli:commons-cli:1.10.0' + implementation 'commons-cli:commons-cli:1.11.0' implementation 'commons-logging:commons-logging:1.3.5' - testImplementation platform('org.junit:junit-bom:6.0.0') + testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.6' - testImplementation 'org.mockito:mockito-core:5.20.0' + testImplementation 'org.mockito:mockito-core:5.21.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' testImplementation 'org.hamcrest:hamcrest-library:3.0' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 69e14e21..8633c287 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } @@ -14,11 +14,11 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' - implementation 'org.json:json:20250517' - testImplementation platform('org.junit:junit-bom:6.0.1') + implementation 'org.json:json:20251224' + testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' - testImplementation 'org.mockito:mockito-core:5.20.0' + testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index ab6300f7..24bbc177 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -5,7 +5,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { - id("com.gradleup.shadow") version "9.2.2" + id("com.gradleup.shadow") version "9.3.1" id("org.jetbrains.kotlin.jvm") version "2.2.21" } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 3eeabd76..39ff9593 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } @@ -14,11 +14,11 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' - implementation 'org.json:json:20250517' - testImplementation platform('org.junit:junit-bom:6.0.1') + implementation 'org.json:json:20251224' + testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' - testImplementation 'org.mockito:mockito-core:5.20.0' + testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 22b7e25d..fc1d00f1 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -89,14 +89,11 @@ junit-jupiter-engine test - - - org.mockito - mockito-core - 5.21.0 - - - + + org.mockito + mockito-core + 5.21.0 + org.json json diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 07863155..6a9bde42 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } @@ -14,11 +14,11 @@ repositories { dependencies { implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' - implementation 'org.json:json:20250517' - testImplementation platform('org.junit:junit-bom:6.0.0') + implementation 'org.json:json:20251224' + testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.assertj:assertj-core:3.27.6' - testImplementation 'org.mockito:mockito-core:5.20.0' + testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index 75415c38..db4d4bd5 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -8,9 +8,9 @@ RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] -RUN source /root/.sdkman/bin/sdkman-init.sh \ - && sdk install gradle 9.1.0 \ - && sdk install maven 3.9.11 +RUN . /root/.sdkman/bin/sdkman-init.sh \ + && sdk install gradle 9.3.0 \ + && sdk install maven 3.9.12 FROM ${JAVA_IMAGE} AS dependencies @@ -48,7 +48,7 @@ RUN gradle \ WORKDIR /root/chaincode-java # Run the Gradle and Maven commands to generate the wrapper variants # of each tool -#Gradle doesn't run without settings.gradle file, so create one +# Gradle doesn't run without settings.gradle file, so create one RUN touch settings.gradle \ && gradle wrapper \ && ./gradlew wrapper \ diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index 3669c2c1..db3a965b 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -5,7 +5,7 @@ */ plugins { - id 'com.bmuschko.docker-remote-api' version '9.4.0' + id 'com.bmuschko.docker-remote-api' version '10.0.0' } repositories { diff --git a/fabric-chaincode-integration-test/build.gradle b/fabric-chaincode-integration-test/build.gradle index 240c506e..dc4ceeac 100644 --- a/fabric-chaincode-integration-test/build.gradle +++ b/fabric-chaincode-integration-test/build.gradle @@ -1,7 +1,7 @@ dependencies { implementation project(':fabric-chaincode-docker') implementation project(':fabric-chaincode-shim') - implementation 'org.json:json:20250517' + implementation 'org.json:json:20251224' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index f176b86b..b1bd6a40 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index 053c3dd5..c31118ce 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index 4fb54344..bb0eafce 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.gradleup.shadow' version '9.2.2' + id 'com.gradleup.shadow' version '9.3.1' id 'java' } diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index c864a48b..d5f39a14 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -13,7 +13,7 @@ plugins { } pmd { - toolVersion = '7.14.0' + toolVersion = '7.20.0' ruleSetFiles = files('../pmd-ruleset.xml') ruleSets = [] // explicitly set to empty to avoid using the default configuration ignoreFailures = false @@ -35,16 +35,16 @@ dependencies { because('CVE-2025-48924') } } - implementation platform('com.google.protobuf:protobuf-bom:4.33.0') - implementation platform('io.grpc:grpc-bom:1.77.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.56.0') + implementation platform('com.google.protobuf:protobuf-bom:4.33.4') + implementation platform('io.grpc:grpc-bom:1.78.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.58.0') implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.82' - implementation 'org.bouncycastle:bcprov-jdk18on:1.82' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.83' + implementation 'org.bouncycastle:bcprov-jdk18on:1.83' implementation 'io.github.classgraph:classgraph:4.8.184' implementation 'com.github.erosb:everit-json-schema:1.14.6' - implementation 'org.json:json:20250517' + implementation 'org.json:json:20251224' implementation 'com.google.protobuf:protobuf-java-util' implementation 'io.grpc:grpc-netty-shaded' @@ -53,14 +53,14 @@ dependencies { testImplementation 'io.grpc:grpc-inprocess' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'io.opentelemetry.proto:opentelemetry-proto:1.8.0-alpha' + implementation 'io.opentelemetry.proto:opentelemetry-proto:1.9.0-alpha' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.37.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.21.0-alpha' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.24.0-alpha' } sourceSets { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java index d7b6f9e5..f8a4232c 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/ContractRouter.java @@ -102,7 +102,7 @@ void startRouting() { } } - @SuppressWarnings("PMD.AvoidCatchingThrowable") + @SuppressWarnings("PMD.AvoidCatchingGenericException") private Response processRequest(final ChaincodeStub stub) { LOGGER.info(() -> "Got invoke routing request"); try { diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java index ac2e33b9..c6dd1b92 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/contract/execution/JSONTransactionSerializer.java @@ -26,7 +26,12 @@ /** Used as the default serialisation for transmission from SDK to Contract. */ @Serializer() -@SuppressWarnings({"PMD.GodClass", "PMD.AvoidLiteralsInIfCondition", "PMD.AvoidDuplicateLiterals"}) +@SuppressWarnings({ + "PMD.GodClass", + "PMD.AvoidLiteralsInIfCondition", + "PMD.AvoidDuplicateLiterals", + "PMD.AvoidDeeplyNestedIfStmts" +}) public class JSONTransactionSerializer implements SerializerInterface { private static final Logger LOGGER = Logger.getLogger(JSONTransactionSerializer.class.getName()); private final TypeRegistry typeRegistry = TypeRegistry.getRegistry(); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java index 5d204ba2..347c516e 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/ledger/impl/LedgerImpl.java @@ -16,7 +16,6 @@ public final class LedgerImpl implements Ledger { * * @param ctx Context transactional context to use */ - @SuppressWarnings("PMD.UnusedFormalParameter") public LedgerImpl(final Context ctx) { // Empty stub } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java index 8197be59..865c9381 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeServerProperties.java @@ -41,7 +41,7 @@ public ChaincodeServerProperties() { * @param permitKeepAliveWithoutCalls whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are * no outstanding RPCs on the connection. */ - @SuppressWarnings({"PMD.UnusedFormalParameter", "PMD.NullAssignment"}) + @SuppressWarnings({"PMD.NullAssignment"}) public ChaincodeServerProperties( final int portChaincodeServer, final int maxInboundMetadataSize, diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java index 56cae1a0..0cc6b08e 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ext/sbe/impl/StateBasedEndorsementImpl.java @@ -52,7 +52,7 @@ public byte[] policy() { @Override public void addOrgs(final RoleType role, final String... organizations) { MSPRoleType mspRole; - if (RoleType.RoleTypeMember.equals(role)) { + if (RoleType.RoleTypeMember == role) { mspRole = MSPRoleType.MEMBER; } else { mspRole = MSPRoleType.PEER; @@ -78,7 +78,7 @@ public List listOrgs() { private void setMSPIDsFromSP(final SignaturePolicyEnvelope spe) { spe.getIdentitiesList().stream() - .filter(identity -> Classification.ROLE.equals(identity.getPrincipalClassification())) + .filter(identity -> Classification.ROLE == identity.getPrincipalClassification()) .forEach(this::addOrg); } diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java index 1f502b36..38865e2d 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/impl/ChaincodeInvocationTask.java @@ -96,7 +96,7 @@ public ChaincodeMessage call() { // Call chaincode's invoke // Note in Fabric v2, there won't be any INIT - if (this.type.equals(Type.INIT)) { + if (this.type == Type.INIT) { result = chaincode.init(stub); } else { result = chaincode.invoke(stub); diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java index 4801ebe3..a834af04 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/traces/impl/OpenTelemetryTracesProvider.java @@ -67,6 +67,6 @@ public Span createSpan(final ChaincodeStub stub) { @Override public ClientInterceptor createInterceptor() { - return grpcTracer.newClientInterceptor(); + return grpcTracer.createClientInterceptor(); } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75ab801e22807dde59e12a8735a34077..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 36855 zcmXVWV|bkZ_jDR#W81c!G`4NqPNQwKF*ml&#gVUume%9b>_7z=BQY- z8${v$0On2okcB}A24;WZJvgKf2sMc4OW5no*K!=QkJ2UC_?9&TcjuMeJ*%&gwJOJ^ zBOmlRj!F(IlPc*L>x7BjWPSq0!t44;Sx(hDrP`K(m#6@kk3L15y8lPUffe(orgSCj zlG71p_(RTjUQnJdW+4C+PNUg*y5M3C5PE6_V7Vp8!1wW->mwAij4$W-rwY;c<}8<8 z6)8pacYaCB((&sk8alX_sFQJy+<2&aj`Vm_bK|l%C31^phDVTF5x?rKn(r3qzmg4L5XD9sAcpJWv^~@--?e#b~a}GQzalb39YEk9z z)BGZ7JL%7@fcb$ny7*fS8;<_d!+aeg8tOTqtpk-c0Ec&Q1COv-iDAdi?Y^r49&N9X zo*e^DyTz7dXN8NpuUaRWhep4MNe)|W_jj$mAEBHyj;b?jqtq){0PI939MsIK3`! zFihdKVb2?J)7a;VrBkydVeqZ2YRw&WB6zc{rMB2<40y4WBLz*pIR zCdaU7k85@e2%+tm$Cx@@w*gS4e~sYbEXY+HmWL)Rvw5Z@lLO!rzzdaKB~~jD*hM$E zhy^kLkFZibj7Mz{X&KL8Or}2}ZKjixR!lJ@$UJ$Z6>?kOO#&&89dN?Ch3(pXODZA^ zB#*l1lcx&qQ1wqa$Pv9W3t}kW*M5X?+ube!4LrPK3aF%jbCnzY!?{kOi1I07SRZH_ zkMeep`V{8&HqT%cIIh&2;#msNxp9#_eqVHQut@rT(3fb)-J~;_njzC&ks35D@>El%6Jlf!K~fXt~C69L#$Y5s9tkQVovk)hvpb z7zLPdriviW?VcMC_l}KgliJZq^auVo3G6g!Y~WY%X@Ou$3Lb}EC0|>+0y|q@-yg4q zyS{*JQsV$dG=1^$Q-jq zIY}4Zt;i@M5aA;Xqlre0KMhYj7fqcOVz>rS48I7bVmUSi zFSKkcoXcM>aukdb9D2l?hf&@tfyrpBd0T>8fPsGkbu%YefO% zhxxLcTlo?2280lv!sFIK;H4CMlW@%RR9Eo1kT3ppSLdc&;jX72BG~Z9D=O>^-w3!` zCR)^>e-0nQIBE}eg=%*U9FDbzO3j)GOYG^CgK3j!jJGH;8MR$$M0$zc5D8TvVoKN( zqE4`lZ?#zVp|PJ^bj9NYq$nTPG+SAhW%N^i;NG~U{!tQDkF_S|!TG)Oqyq6==#WRU zq@fS7tjH0T47hN)CD0r2_Ox{%rOiG+9spg5YBpr@rq^N}A^K(XTRqG%%F*8;UU;O| zVTT|#5B$fmPj_MrM$k}D?XX}>A`^8bCV(PZ49Pr%i zWe-XX^QYBJXRtR|ueTccRlrb<^KG@y4A(gpC=epwghdrdKr22ZGUi=cqBd6LB~z6H zzU!FB#AJt8892mo)7fS`ccPs3U3v{l^}3 z;PTHehwapHCIx7vh8;kz6BURi;<33FF3uN>`^SP{;C7qw6uPF7NPPSRXjO5vfFzmj zCPH_K4eJ-7CViY8@1nQtI21f#s>imxz{KKFMBtYvaT!$tc&Z7NeGaeJELq(|z(TbbR zmIlJTvkU0B)Rwn9e|aMO^gJYONXOr9)BOALOdQmgU_5w%LkrSlHxpZV39^?|QT5V7 z@rgMu9Ll-7i@UpRWLGlAV_dz$Ytbr47}sLxD*ZjTrYiE)U&|Z?M6jmIN*s8x z*CNqWuC4|Cd`5WKGLiW?RcC=Ql&x7hVLvmM=IZHsWgAo5L(YrCv`$IO9fuDy}Ut-0@nJWL5qJeUTmU!*t!&1s1LIj6=4<1 zrZLS4xA;K1hk2j*N{I|^Ij-YP)a_P()YTH-1h?1Ek9kkv0{XhEd*}%o_}rFn5=?f# z16$_0R=CD7?8Vl&=t@5chb1?GEdmJ#Xs&ImoPQAJhS`sj5xy4nP4s+5F7*fB;}JwMrhHxUIK>+s;`Z*0%kNQ*q2fy(5V)tc?_64PH=((*CjI-CA#>l z%vNSTJDdUsrZ(wez|gDJV-ErzTk@C6+%B%Mv!{84k@jb5qI}Ekk@AU zTe{?{4C-?ITS6^~=rxH;?T|t&QgfNk^y`StWlyv43**-~!qd;wa^XRqxt z${eXKuZuc%$TbXU0eUt-UE;OGL>;t2bkUW~QRA*L6jD-My`m^O-fOVwp*d5FE>jq+ z+dup`WSMx}E!iX(XJWBDDn=^%_%(*fNL_*1aS+U)H zPdDdwexkm9Ucl9GVeevQaM6--1byzBTpu0+pqBYeV6kbeX=D&4rsWb{DR32xJW0$# zT4=su&L2AW2Iab#fvF*0+7^5RS!*t29kT+WQr1Bd_J2kC<>d%-g|+SavF!Q+sf`DJ za`jW~{APO5prqjHXR~Jo`lndT)F3u1`5UA~SG*9Wl~$Z$MZ#oQU@&=n#E`wy_3K2r z9c=S}Nk0VHj&M1xi63?ijfeUVpMTJN#9bi(=t18=wJX{t4w!P;Cwv1}oIj{*ICoFl zFAdZ7O~#0x>hhQtr;hXIR`pf&5C2!<@^ikMF{L~HHy4bgLqD9r z+{$`FYsVmywN-rb)-CeO?a2G1* zJ8v}9)$miL-OiYRhD%bRx-W;>2Ok$H|6a_$rvUNLgl*36=XdbSE2}*R(&PyM`#mvx zG8VH4j7RtGp>JJG2LDV#qeaHfk*?@s@pM6Awt|!&$U7x& zyi9)*7EOEQuHa!2KaIuA(`ctAeH!*5qDSr=j~+hAa_xY8oI=JZ&6QUaK@y+hkA@#5FSM64;!Kl-zc-Pd`-T;a zEoD&>%$hTz)N!AW93M!~zmYrgdeQN^IjGZ$3;fLYey^f!Hu8t7E0_Ir-VZ|Gyl(Uc zHzJZl)fxbX1bdGw*l4egx19jri1w$Cej(ej7#}-RmLVKr9`;Gtn^IL2M=!L#Z`hYr zH3)xhitHFDH2Whwv=H|~#rT()QM@+?VzJ6*g`raipMWJqdychhqF)hfY04ZF-9m1` z4x~Mv{#M0OqTrwJJ2>FJ55y?jl@mB#%0tI^cyvr1+;S9=o$h9=O~ST`5AcfZUMWKE zl;6#c%vv|P=kn;6+!a*o`$?oTY7}uO^kR!9e6Myril7}uZpkkuOTA`;EiBI--cnGn zxKKR(7y3WpWz&_SFh_ub5<-W9Qdfcj;}PNivw)gFnC?tfb0N(AMdYn!A1zS#*CmFf zQP`pAp~;S(AImyh+vPX%@hRkoZujAILfGPOFz*`UE6apDN*G(m1%YaXXM&YydB2}F zUdf>{%sGO-?*o?tD%-lcn9IspolX;VSCsd!gxHcu%!mrykRB0+aYb;Rn@6NZt`WWX zufG%n+j~cL)mK{^T>N{T1e!rMti1Sc{7A&D@bCErSE60aApm^J@2=ZKsqn}7O6ZAM1cj#DX~{s zNmhGBwltgQSxMz%$xGnz#^rj8tmxe<(MHy=%-$PhWsN7??w)vG9+Xz%(qJ+;!&>hg zS$Jw|6qH8pefOGQxZpxeajoYJ%|#Xo9m`}**8B^rQ>zlaQlC5)rPgW!Mt=|vw{;wf z8OP?tnqz&EQ=#UZ;A~}+XH9mT#hTdjr?Rj}@nn7B$mHeP@L7E-@vvF9|0uS4LUFA8 zZ^6j?Z^4iN&(LrJF{f2NYa2@#ZIv6B8%Jn|fnb$jq{D!d-hTRcz8%)SaTwI-hum*c zsF~8(_WdY=7MX_9aWbwB9tspZjrcd-PKn7BKptLN!0T9PTT2$nwS06fUbtJ zMQjEl&S;7KX912j&Q^i@oEE9F__Xs(F5^I8juUnDjAig4^vA%K2Ob-)xQ;nxW5884)o!IS{j+*?J|zN@-2D zv!h&4BIupCzRI{YK=&o>_e!T)8GRoYh2KSVr2O{FvW1q*fZ zBRrShUVP~DBVZ~4n+G^CIZjB&A7bg~m8^W0_3=xsI;!>ZTwJ+drEF1k$_H~ zYaXTE@bi)d?qPnFGL1W^cTxu3KlSoIiEsn|ii&+2B&*}@?CBGA`}+f4q*ns>3xcV@ zb9*m`3KwM;ZuKLWNAi$Y@fco##N#N68sMf}KyYV1Sw6(d9`^x^u!Nskr9MDiqH8(??+0*_f#i_ z>p#g`VklyIuh2l4E>l+28c;72T4rC~#m|jgo1takXEuUnVWxCQ@=zN%TX7k<8OV`o zuleC4WuLymKQ#f>BayWUafropGIbcb{6uw*OK%wee3KKhZCbJavFCiG14EiasiU1k zU&RuBB8&0y@M54 zJyJCTxbCx}d%%A%6{frWC;pGS5pY3E3sv$R5#1L+C9xu5(Yy8EIc(TkIKP+T-4hVE0!9uFLGKLBmX zCJ7hY+lQ9-h%DadkML|5p_8>U=(e*z2Et5GQeAs}h>=FxZ5CiG|6s99iU3sOJ>0ad z8yfMCrTkz+8Be}?gK>ziY^NshHZxRF@?61G8EMWn>c8?_*r6*wGX_br-NAb-^Q9?11xxGy-~`l3f*G6E+#$~s#K6t@T1 zt-bP)>rs%QvxF+{!oherK6VE&o#0!F__TRe{W_fwNBNb3@ki}T9D)h8)Nu3+Ly(PJ zFsKWue$BKtYeEuj!y~--@$Lg0dXpu|)cI2Qd<@s&r9Vo_6^ig_4hUx;&gdO4guk!d z9C4z5*br+lJ7ymly42$cxM0me1O?HT6bFunXZ8{UT`B*J=Z9|Na#^U;jNs&~FiIZN z6kA?f4Rc&-ln1A)qR1~nBfornaO3EzX*lPVyc5c6R{i->6v{(cWFjuntW9`$8aN9a zI}G_ysrH1wfjyzTUxCI2H-uoZ`P*$^`v-yJ7wM9XNALirECeUQ*+shyhV%EEd6SbN7NT zM@7-s2xAH1fmH;FEC`BRF>m!392`F1(?j7qU3PEZKri$l9Sf&_kiS6VzMvSot9s;o zJ9cYc4fc5_HH})Nu4|oCS+7Klhy>QQh(|adJih|JYTgZACXy~NU-fvr_Xv3gab#|5 zTsOf{<--YB%S=m~%ICMiD27!5DlFCo<=9SZ&5kgHFZ14csCnXksrUjI|sGyywz101pB17$XF?vIyj$ zG7v`b`l$JNhc*_X3@lW21+8OF2K}?M2#A(^`nDC|V74$|4fkfXJwq_Fo)iGIp{@S22ckH*lV8Mhl8*op;7Ft2iu^>7Eq@ZkF zb+`t!eKTv5vr|6ViL4Mx;6%+gEYZagXC&o{C&_G(Yp`Qu9uwEz;V@k0NXYH$3^f8s z*%`}IAn;q_P_`5RADz>Y#PXeZanxk^Wc?=O zTfDR0qY|?p9Cp2Nd%6;CqWg^#vuNa%%SFS=#nixgV3~ky5-uMAwulGMCf5-uG?_^s^F0=m84io4D#8AuNtlK?cek?# zQmV@y5U}gjn>MrOzpabXUa)2QS|MICP+ER>`>2ChaGG~L-}^MneJ64^@#kTI-3{v5 zBE{n86gcLO+yi05ERs|L`e^#5zn?KDvyRGHqAif9I<^}5n~@~`4qmJNsjngauBnOxTU5=Dmjc0UCH-2U)n8|ojVbfYFPA(jks8YYN|rf>6dzN4 zzI>Sr{-iOT9wkYc10Z1rEjS(~D{$e?hUMNjT&Zl1FV`lzR_3u9Yn`v4JcK|!7rtLTJ)gPhU}2c@)8 z%YZ!L#HM(OEsxag(TiAfvlVBtQk3-2T^j*wUD2zx^01@5uT9(juI@b|=3nK(YD!jtPItUnZUt>0px?A^Xg~$TB70VWnVsk69DkKFy3P&H* zz>7+R_QE@!*TOkkdqZsyERX!L2@9qwFB;iMVQo@8sXJfi_SyO{e|>Ba)ulYwsT-BT zywza3byMQ$6$KJLe^N7b=QaE@7O;V1v?Gyt-ACgvV4P`dqrNmncq(ecXnPIG^%cVQf82(X~;>2D2((VmU*Oa_FBWYVTxDSDaGOB7n+~H)y803Im>dTImYiHLT6RV zDpoDk_}XQq$wsc?>}TT-+*PGvk|sd5B`oRLpjDref9{)%k)aPmuos3x^#VwQ0|2Zs z^SgeDMbIN-*{k1bc*9;c7!Nw=m+01{^j#Cc@Ix%YQ3Pn3{Mx5gZK~ZLd4^TQ<;L|~ z)GP~ObeED?!KC5QT`EWdBwoU_201%)%5EUP-Y;KeS9>oEN;i>!ZfMfrF&$~M(sF@s zvD8zAi@#uY%n52b=|4nUQi~N-k51jDK5ebOHg*jvc@Kh;lI`U_H_|- zdiUN42W4Lih1gQOVbwPuAd4A}&*^gn*us6x$p4KlbLwpho8{&S!8Tvm_!E@i%=yM# zb|_DQ$08k-+Q`uhj9uFI{q7a`eWK$UJa(wR!MtNK_K|tO%#h&w0mz3CCek`++q{tm z3wpAw^+BJ_KeY{X572MCS`-xMQG6u8kFPIYnM7OP!WbHDEXD?75z#0^IoZn&=GtS? z($8%x==)o-EQ%{T@2B#piK4=g1s<6Fr^kw)5}7XljYjY{J}sb;9=0CNA2cLY0_Yru zSVP5ls$>*Ke23!_xL6s5K_cda<(XtbBp7hEx9#xqnvR~{Uzrb>{zF5YRs)ydODVm- zpUHo7|5~j0eH^9$UgJae`f3vG0xMB)SeziH$o_QhL#hJGQ6F6lnn33mbEB6}ZxQ(rv-yBUrN%?x9MweAf4G5W9V{qN3I!}`qwURYwHpFV?lGVAtjMLBlpYz z$mSp!hglh)MYf=R`l^UujbSvzDvtpEtlweD64F@C5t(R|cSo5AI)@Y7%gGnMLGq74r9@28QEI}c?`7^fBmgg$JIG(o#H~ZB8ceC} zrZQG~u_!8m<}nQCb37lh%JY{%{g6BeuOv{b@K>phYcT%u(mD6|?6H3~%21owGy2lG#&57Aep(+!ZDzQX5GuX)r?~IYB@- zPPJj!5hvwzj(k-z$gb3E>X2cpqxv6KoO*-Vg--NE;2x>q=!Z!mFqky2#nkYOv$6Jyp73=+8h!d zCj(zFu86hk{z_3sjFmEVpB7{SQGuj~r5{!-nQ(aI##k8!aLR-*>HJ7f>9698YWogs zj{de6T)W=m3`3vbO)afnp!Ck=Nz9WIk7LLw%K0~pi_?VjF5}DIFV2;MzL_!3MyWj* zur4CQT^4!qNN-3}a5rAa>H%f#><3^AeB(H38{DT0QBwY5`i2O>@51PU3UPXotYsM4 zs$d!h{&#~8i@V2&04E8X0!KdMh*~+VtpBQ7tB+%m9wTT)E{~;v*HqpEA(BK-QK z?C^J(;OBQ8KH-zWY!gLoUpDpcn|-y#vE@u8tFT0Wk4fvan_~@8ZM2#6rA>;yLtabf zMP@!xZ)Ih~F+&D$fPsm+5M#m64$b${z=)!p=2eV}GlqKM$Dzrp=C`ET-i?KJ;Y z@9O?ny(_{-2P4*U0)2F5{IGQh{_a+Atnfr)?P*#dLQ~F3F(he{A%Eh@!K3+%stxh= z1OxJCBeE5gWCr>B-PQE2zcUqp!$f11lDa+4G#4O^i=_`e;Px~u{4TrO*SFw--+hly z1N$FP=KQYQ%DbH&-G2?O)2^(BnWW*V0ywdf&V9=rvv#}BP@_X5jSa?v{CrVDO@aS0(ksdGMeS8 z9*sfc5Ui+Npo4;{0P+@LH~W)E0aurfVm?V9i?`a4rsUi)8=4&`F`s0fv*`&ynTa0> zOL&Nj+{&60e3yD$p8xM)qJ5NgkB;&lhOyBNO%_u!{U;X>W6X2 zkg7MwO02oe9Dz=_ob?HKOioo*jjNHA@DXUniR#jU1Xq*X<%fa+;a46LUQwuxvrXN& z7LS)hPs>i!UlOVo&x`xBEh?>Lais~mjWtftUY+H}X-2#e+0C60+RceY$1rukS7~70 zCGTz-G|6bosCY~({eZZw>TI63u9jxPkAi7mAvtbq(I_Hz5oatXPWBMNX_~1 zEH7~ihnbA*R-Y_Dq$j&#to_Mg-co&>yyOgcFKM9>YlmqwrUpU%S+nv;@y%tbEVd=h z?UI&g6$4b>kK(3TtRPk2xV-b*1ZP;j#c0p+`!lStRZhw1T;7DJ$9oN1jVCih=VX&F z=Ugf82+QQq5#Vax&?-aJ!r>dwR!|bEJ<~IV><8Jw8WWt|c})9xodHKc04D8)M#cnC z9V4^M?U*o3E>E+bipA}d9GJ2zxVFcH+j#DqXo8dHEbr~Pjg_&z^|i8Nd#O&f2TvRk zh|3bQvE)WuAl(HR$Jf6|byI(-GlrY3L?0b{TuZh(w+Sio6_MMu>`@@p92;G6vR;0X zmife*r0RI2m1u&S$WJ)T>ka>awwDiV`9aL#bY(pMfLilxuw?_ewj|Z~f_~?BKqp2a zy)eIpJ*==o2mE$|XV?)mBlo7?e}ZlKuY3m=IIQ!)$m^G*E6j@Fh#KsithaEl(N&&l z=g@+_##B1|K-(Ib`MFq}1oYzhX<3grU&1@}*b8faToYFQmtS2XuGZU;nC>1>f&tIe zWa1a&J06N#mDLJPNNgnkZ}KGDCfY#q?Wd@2xm!zvI^i`fxw`|=y7LRw-LZQ8*J$?h zxrxe@no{<{{Goz(^E;`<>4I@cl)!Xy`4uz3uSrbRtdaXYIvCv}wK#F-zHj`~d1gVxVmEjhhVEPtlmL|B=*D+4R%&Xyf|^cV}ARkbVD|WhV!!MwG_H zi9txZvq0yt32OPwF~gJCN<9tvQ9ZUU8j=0M~{`e)#v2rOwzj#?3ofu zcZ=kQwegA@L=WH0pRa#LxB0$zgcuTze9fJ5FVvdG%EvUwr;TTu6uKRI^LK0IN3$}7 zE!3lc4LJK^gWIUYu~b&3z+%b~Q}uJ}fLYm{yKZHd4T&BIt4x(Y ztc?*@?Awkd;_(1)PKkQW_r309H|~oC!#AO+9UMU*u19?vDUeUJDIJhVlg86X2XQS! z!*se3@q}m(sT^z7pzq)=@*fN$lL#L>+vke;T5~g&1MJ*pxPm42eZW6&3i(|X9yNDp zt+o_*3V$)9(ngsmxtL-INmHk~@QxDNei@D=*`EhzMPe{?EQcaplrPgP%Bzr!%F5=1 zh3W{Y$Iyc1Nqf1uW+r>pyLfB38Ho0|1GrTLxV1>qVDVm0)Zq>3Jnp+&)QWvLsGG1< zZ>U4=H`D^7mv{|)e)krNT`UHd#~0+;4wiu;7v1c>6jBwDYX<=au^*8J zrqF%@0f|@@{;#SW8?J8R0^^aG8U5xLu<1WOwh;9aJ%S^)<=RS{f3W?`wZjl4JWHyc7R}S58J2$UB}aK#63GkLG*)!XzNC8|I0KRY^g^;_=y7 zsO9EGpr@rayIGLpkupe%t?TP(DEdJuh6@6$ym7_an$8+8_dYP_1O5O59aqf6w4W>_ zdO^XgY3{I8Kk3M{uJ#)r9Guo>SsfSNj>pik0SNmsrl6_+zGZnr&WcIo^-xF+s91yD zazFWPWC&ad1L=miefaC*K))f;A}oKKOR(`BKMkAT{IW^=)+Bz84vs&2n1D}{^wOTo zJH@Xsk90kG~sX-Q#e@cxfh4T#EJqkyxMb6dA(K1Y)ThTkyTBjWD z9=^rm)#<)()n@CJ!7eUt`ZKE!#8$=8724%zy1u4FupBmmO}K>zE#+a>(@q8MN1Q2 z_@99+=dF)Q`iBnL|IiVYGX#E9Ai8;PK`7&9v*vDD3`oXBaRl3{O~uC70B~ z739IsgSWkdIu^gwGGnsGEc^(V$te`}@=ffNczOBbd)*BiL24?dq6OJZq?bPM=PM4z zjKGPzzr5aYZgY<5_wd7rmvH*!VIIqz$V}iEVy<`n)u^G$8LoE&TjJ!~z)6=_N1_>? z3t7+7)z6JkHv}pGu_}-NNez~18L)}EcZQo8=xbvWER~fK`w8@Eqr(N0Lz!<6t0;wK zodBNIF?5bv@pyPUnmh-I)TatRy8mbbGC(3B6MzX*t0i_ux)38~C7|oCCOO6n(k||- zup%%(Ws>y)P=Q0kI7x|qD6v;cO(Z{~aUR#{E#+V)9lBRb1p_hg!Zr0x*&0xdohg43 zfc9H2h?0bu5;d#X23V_K0-77BlahEyM$$$})&3nu&nEt^9NN;H=y-%l+<5WhF}o<1 zsI&9^S*X5XD5`>BrxBnHwAkWuuad_2r~RlNF7T?#Dq?gU8|IdAar>%-l-t-77B*W_ zQXH>^Q`YoMwhknm%CRC)B1kl=ZVdXejU)P#LOah!;L-NV@mfYz@7h3of}@$g<0^k} zUvWO9dcBgUMxUnM4#C58!h&Q;o?=%6^)cx8b2gm(!Q}#uFYc28RM zCsMkmDkV^)^7`-?P1UXvKTTX?o>4e!K;jc{d~t1G-6fr@^oLx?<&YFW;a4ciXdh*G zTf?77Wkyx;w(tdVjeM{`C>~xJLyTw?bBxKjqh&6SVh?&I!v#{=Ur_Ia^4KtnwKl`W z^Q7117(OhT)T!pze5xo-lK+zQl$Hc_2hrjAlTpybm<{!#r z`t@@s0WsNRlW=R?_O4J5T+F}DS9p?G?GhF*r zqq9nOC^oB9$jRxc^J!QA>>T}Y+q1>4@e+df3Uh{Y6hiwMU0ea}BwHkPC;OzqLC7)- z;!}(n+pk~1dt|>L&Z5l6DJpi_8;&R&6S7`!o8%_07W@HCUlOi2xPo4JBgm3f zmv0S77h0^}>@>rxm6x%ce#J2mgbSUemotvL$Z?d3WUHOgc95i)X7*}haRpBp`H?0W z1#>S4wsRVyArGTEgAod}7bh3nrZ@bza3#9uH)b(_PyFwnaTrs%;M(sAh3GmSP6mCK zwR*kti@%Ke-WOE`3*_Jr0bW0R)C_gXt5raz z)M7uQHufd71!W0s$5y`G$K1cm#?YB-BdqhR>V@|#; zAg{kbqhp2uLwDE-$I0bvw%OEn%QfpM$v12P!c?KLBAq~-JPUhN1iHRKZqX>nqG{8} zZcqRlV!9+!z*42;gaPO_;7)(jmqmg;&@?iXPpC_svSBQl=SSsMVK9F|EX^W$1p&p+ za>e30ydcU_c}{5Khf2~dyQ=7lG;v^DkxFmq0{P-W)Uwdx_*Z5- zMkB>$c7+^VrWn=A*G7VQmEaNe5;7i5gq*j;)A?NNLJwg%+FJm|?OyIE9$D|Et(e3D z8PEGL78P;=-TM*#)*#L$o3wQM@7Q-F`2Um!+N*jMtfA@zWXqy+cIl2}iBMhUYSlNh zb){>}|KjF#z zt{>`5{AnEzkiLJe#n?|k1?@tWhj&z~Ctq^D+KqIz1_Fv~+OcpIZpD8vvShYmUE(2c7?6dtLZqn+%ReMe zV6oG;+|2eLUtcjGBX52QD%gH_S&z&QrC<~dVCdR=UsZv{+1N1j@Ud1fj_y+_|(g4Efqce!?jrHre*$Ipf3xM|Lb zb}R&%mA3TV6P$aE7FJ4r()r1;1o{=G9O({~S9x>f<$Y6rjLpp|FRE^q99fEKKf%48 z>*hWNGB)OpX=6}j=GkR|0zXNq96i=cw-I2qmRW`_!+_{<>nmxHK z+u%HyGGH;r9RT#oxti`mQ$%bXJ{we-Yz1`N8i!zLRQAHC%;Ew{od?Y{^CG5Xh%5{LV<#GV_m zr`#7s#UlT|8HwKprfH;_Qgs(6I5Mfyi!Rek)m?BOt|s_26?Wz_j^IeRB6GZ9D(z*a!R3+Y6+`TGL>Kl0G?*g@P=%c+^K_V>m zjOv{rxWjsaAyWk1zLKFB={A}R-HGN#7a1Vbr|K8K`fO~jF9!3PuC3Q&lXDDhD1SL= zf0x|6Oeu=6^Le`RDbQ!4Sc##Y|M159=Pcl;J1j*djt6K5#UJZbqKlXf`(U4*wZN7^ z`vrMM#lJ({gZm`V>UT4KzZ^@i&U@Vt@U`YP@O?*z>9#Ul8&~^Yux55RC3R}?-b|e~ zbIBL|uo#MLa3sy#`UIX^rjKsuH;QTg-Kn?p@VSgmt4m>dz2?9iLd)@BXJsf~0BlmM zm*}|r^sEvm zn~L~%!p)rJmTKs}kWK~xCvF<$7dcRHmSceo!iP(sgO9!LGB=yZh4q)I6kXcOU zJzSmJep7HaKQxDlpfN0`TI@%m09Dvu=$EA%SW_kfq|Ci=?~#|7E5lxc^ZIqINmO?u zPj$KcEJ-za@?Z^i1v8(LN-(ugnrGR3;<#as$!DCAf#_}|UK$u0Ds26%Ym$j685YrK zZi4O{G)ut|7kw#m4Nw%O8eI=M&=RgR$J2E|qRv79Hr?lL3~4Tv%GZx(%Xl<$`-iF+ z)~1{zp=rrJK@b?xA~7ryx$UFXLt4UEVw-03@TpUJiQGL)e|7(;BsJ6yJTyFLlX9F$ zdZfSY4Rtez&}0Ffo0_k3)G6QzWuk;$R2i-GD)pWl$10yz=0>O3c`}Rye5Q{CQL$ZF zo5(odv00wM$pBh^#U9lEp#m8?QLD@;jr2E(8w)4y{uZJ)rS|2zOunrx%WDf0`Hm(SA-d!L0Hr`$zl>C!MPnV_ zg134bu%~HNEsgV~%C||C52G#FBk6aP=~mxkXb97fHh~+H(VgRXR}r@?Xf5KlF!|_~ zB5v>53$>|;_xD5(!MC5jE(?8NXAvL19YNC79{OkzpA3DvQ^n^vXaOJQetUYVDID;&5@?4XM7RQ?e{|Zb1$TGaW$@|d*m7N z)Gczn6?e$-PTVcW{p1%hK7UH}dk&3HQPmaWGk8{x&*6DFda>w(`T{n*C;;6?cwZ!7 ztKc4q>PcLV8VT_mi6uZl*spJikRj!ObUkbjvX{R>p# zWm3PRwYDboe8Ly{d%_=0)P{WtCG1bAk;H=9ro;lJIT1P>uDuU0?vwdQEtAA+&A$Oq zO9u!PF%D7L2><}*5|a@c9FyRF7n8eKGJin)Top>fcB93lL1KbZ;GqW7S`(j|%kFf$ zbiZR(<8_5Wq)M2 zSquRnZL=UmnJ#qXz{$3Q%g#shXKaNK}Mxq-vzh*ZqI7;n_-wT5BSNPnk62oyVE zsw~=ZJrY<6m18Nv7YL&qHNg!PO$>Fwc#%Wdyc>@n77Znz_Uxu4O`(cv7==wptB0*h|8*R91nx>OY&` z!tIQCrwk2+0;X_RVDcG1Ht&84dH!I6t8;8@X(*z^_kH$OFu@kE^aV4oKVh~~ImN;W zu2*jIaRU7#?tK8pv>cxk$o&9NO9u$5i{lpAlfhbAe+PV9)w%z^t8uTdl_kYVlqsBq zII(4Ck)e=)R}v?(lg1e+gG83DZ4pV=Xe4n51=_T zp{2W&*F9bzrF78+asTIB$+m1cq`#M+;of`B_kHKv^v;bd3cj*c6QNJb?mlRbfbrWsWSf+PFw8NtMcrF)sCjI1`s z!|Ak2I+Lf%$m~p+84v-BO{PVovTCVCBW*;osaU4BZY<0O7rAJXPUSS2Y5t{QRhr5) ze+dUQLRpr?OmoK_F|rHdZu00fjixirng~jz8BFCM8#E)*m{3fCXwt~k?b#Isp;_eB zX(r8Pa*f_mX)co^WA542G7hZ;X!B`-PV>lDjMk!3B~uyBY=@5|Ajb3p>S%4dXb~;e zX(3$+t8~J+8dVip&4N>D8I#kvF$*7Kf2ybojy3CsrTbk}Lw=pAsTQ`fIEk5cf@a;$ zaHbnZT+UdGddg5AA6aK>rDG5HH5d+5e8GARY-Z`23|e{8BTJXZOxJbK&e=HCzW*G$EL~qvVB;7V%m(mHMqcp10TcNxW3R}bJZiuVW z+fWiLtEL-zEmq+u!D7hPa1V}qJH10V$vejp!nR8P1p%Z&;8L@yMswR}#^Y8c0FgWC z-8!A3_b_>@O2b$_`#zoSpwps|1;=rn2YJ6vx6|EBYhEcB7Bv{1e`d-G=k{zzeqW^z zGHt24gwtBs8^%J6Q*NH059{m zkxGLi04`VOkLdITdK5DH{Rgh!c&J*V$MBH|XHc2bF8Y$-rkcKt(vZ$}r1S1wQPom1 zTYr_#3+Ts@dCg>zwEHi!1iYfC7Qs=L!?9nZuM3s^H`B`he;i+>Zy=lH*%elPN@DbM*&x&1LcE4ck16bQ+!U{><_Q)I72s0*T;!=0L9X%T-> z7yaBSalb&Sf6in04+(@{6`D)QPkjM1-=+LUr{9XwSspQy8FaDf?MAPQekZ!IQ}lmK zGslY3kd4KoqW=CK#RmcK2c4c5t%*}K?@1I`e@XEtAOlJNM1K|}{(}6GF|AD(y(k)) z=jm@S7J3Av#e#ZW^bfjUXy%_%>ri7)+{mDJc*!#Ff6L$`j=?0;Ewcd(IRrqeX3Qbw zX0px9_XRGt2@T)NV$hIu3g&1|MqTU_J;lAO7WcEVbgEpI?_7qPs<8!OWM_km%h{!~ z&Xa^fq3EkG$2-PlgOT=vr=lwGG^Q&r4@YGW5<+lHLCzQ0JGr8ar}KUM}L` z4qhShL%KQ9lj(KwD)=9J8Iy%Q9ecImV$2d^e_`#oygOWIR`PlQfpKENsM3jsper1g z0pENgV&tub(PECpst;w&m&nF5F}S$TYCUQ--lX$J5pWCgP*KxJ`;uk`;KvMKIN57~ z0HoLeP zf2|!i@#f*ixmGmJwX$*Mt=52=_l#b+=4GV-D194m7qJlp*|BG8+y)zitdTtC;++;C zW|wLC^GA&|+|IPHs(6N*VD#WU7%+G*Q&kDYjJUQSu@zwyN225Ftos8i`bP)-f-z?< z9pi^C-p>bg4)H-WgC))jnq6Jufa^ukf7x&GcSPsI92Nuf2}B@VFe1`jJtMJJmLQS8 zGig3yM6#kC;!b$INHa@H>SJtnvd)a@+{HKGOgMgL4Ar$LAB{PxQNm*)Y09sgkg%L!7VP%aJG!ojJanfe|S9x zDaKo+x@rPhOZEJGf_rtokufo?tSTk7Wupxxa9b?py;h*Vj%juY<6!c{H|TsTW1Kp4Nro?BjFOv0yyQ=Mlg>Buo6&+qW1_X} z$XdZ57}NX- zZgYl7-^uS53dT4!DPz{RH@39oTLgZeyg*@$P`1{lt2BN;Jh1o@t<^}U!(B#GtjiF^ z>;qPsl1532%efU3r>W93z|V*H!#aPEF$FpH?B48Or?D7(K(?VbBfM`$e<_*=8eIHw z{)A8him5Z(6GhGkg{lJ$qE>y1?-evZU8u9@?z`(6VqGoCj3E=mXMhxy9EeOI$vwcI z6*!;6PF0H}1ABd5=ll7L=$_7tx14C9kPD`cHeW+Hjhgk4$meN(7`E8CYsa?c#@!l! zVGN|ar{YH~$a8>vb*#t2fBvGi_9bi0g8PcK_EkiJaUv4WrenwCjcRzS8BE2VRw^X& z)JpD^%!ZZ~zM=C4e$w&^d4+@eQ8a+&?{)Z_{4JeSei}xtjYp1ZfBYR-GjTMEG2X@B zv+_RXkMbD0{1iF~Glll!ht@iVj@cs=cV&|qQB=`i`_2&t?qEvOkrViu^O3pA~(FmJBCNk(FhGz0JkH zR=dr@n0d?;}B{dV4CFM;hW3ZSvd@UR44kwdFJT1-AXnm;s z`+|VuK!RXcF@jxou6k69~=H3eys9KXk_G_Lu1@b8?O@AdGX$nf9!$N<%SsTWIKD2hje~f zp`v+YcQ?!$RTTxPBpo-59+4fk0bH>w4qdS+&O%>b05^}z%Nj)kWCX75QgnI{?y8hS z3;AD%T*@R2Km39+83vBWIy7Y}I)V}*&|sPwWQ%Z*_{Bz!=a^zwsES)xJRAViFk>X9bJ}$gaa(+^8LKPd6?&tu63!g;J?2K4qbcTCBIlLY4!?Kfg?XEwh2L zL|0}jRVZI5C?fhSqm8|jvQ}~6GNoErt_Fgn#ZO7_f213P^z*KNivo^W*$WXT3=$2ocL}v^etJO zUQ(+mn3tT$u_)+ccrBry61*1XBxS48g62WlhGLNKhsC|UrUb<=j3q9oM%}I`ZRi4& z9ZYpTxET13`i_TV834)bKU}MQVVR+P8B-R6e*mas+H#75FWxa?mHT38U)K6@MN{?^ z<(84kqwE7uBkIEp+YKdQR`*%Alh8_tY1yUk8;4U>K8P?yJ*!}fs>zpK-^lc5l`f(0 zkx5w2PB;jI)uu)yaV$kKNTw38q~VJQKkPwelk(@2nQvP-mQ8dRDY=3a z?;ur{Qp6W&_>Yw?qDe>aR!*cUr?zH+$^#EP<5Fvho zedOLZNcExC>Krxo)7F~cvg*S3cKp}of8Ocdm7~4=6w1*->n}J+*M|-sZ0o16{VW-d zN2od!vbnq3?e186juP(bvy?8ZX0du)tnMqU^kU^TVkP8$9RS_0KTB^IptlUt?V*5u zknRZi&(OPa^xl5DtDinFNFNFX9Dc98pYC~xKFJhtdYuo^XPHj(d9OpfpJ93of20Fy zjs{Ni$GxiiVId|>8>BA)SD>Ej8@hn?FXregr^yR670P+Ss~*nLg&aK{aP$q`hyCx! z{aUdRrv02$CAf3;W3(Q~J1x}YWA3%pJB=V=GZ1XP)XdV|+7NY977 zWry7_^wS@6^w%8yUF=rdYCw}@wIZ?>GZzB@@oE7O=o>l*I~m2yUKFQ9Cgdv*&>%2!>=5s3f4p`u#o7Q* zZX2Xi;JlxwxO;Q#KEpF}JbT32)KX+?56{o>6`?iS-84gVo$K6-}D)ob-;MW}Pf9IP9`Q}h7B5#my z1xZJBKcDpX^KF0+wVmO&3HsCohCTfD9KS2HM!j1&_GGWK!qU00org~q_H@Xk_R%D- z(^jEM%lJbeGr;f7@m&GU!*>txJ)uCE7q1`7@h5Y9-yq))KeDgUa{OS02A0T;62jE=dbo%RIf6L7Rs<5ASh6h0is+D;__c{V)eQ*=3JR(+&6O{ad z&>4Pgm=>H<5`#_!wX!q(f^L0zdFNl=iRh*ke>_5 z`1(@~IQVmp|0W&jU!k_gX+9#|KAQ zQTvBUud%Ic?IQ=b)|{vIL1lL6U=R>`olmWP5i_r`XQvJT5vV?o8jvUbK-!@iu-{5hdEf4RKfRt>N%%LbI~LSy52=eBbN z6~i_jrB&MIcR6LJN7*HeTvnvXXWK_5u5O`MhBN zk$5_%e>>+mPY^kmIakQ%T4z8$H#s-U=VoV%vm4K#bBBEHc3v-^9nNm~yv2D^t;h4E z^PLj@l=D5}sn)AO`P`xIlF!|0r+miLTf~zT1=u!&Ru6$aMWu}@EhJXynjxB;{|4D1 z`Ut7khy1%X5gB>2(P`*SnZ1ZTQ%}29ri^*$SO0#WiXpXIs=Gu1BJX<%-f43!R zf$fdtv)x8l*uG7bwijuk-A0S-DlN88p)2ifT4JxFDtiqrwXddS_O(=PucsROb>z1n zqFQ@|>g*?Jx&33b!rn(K?GMl@`;Ta~{YARU{x4eNU|Q=~MC%-WTJKm+0Y?jMaO|L~ z9SPd#I7XWsy>yM^eRQqk0jhUSIHv~ZT55E@hnk#sQM2=hv{~IuThzDFR`n@rQJYt%27H$Y#+5QbsO9u#{)Cb{z761TUEt3%%9FxOwF@FhoTvZkR?@W^SGMR1(X*;E~ zA#EW|Gf5X3$^eCuwh#>go0c%N5MO6rl2>Ntg_$>PaY02bZYYae5f|KwiVB!cB9S6u zTR{bJ2T^fBLB$185s~PkEG}W$f%Qe?*S@-(- zomT8hJAW0gkJQI{>znFhZgRj$Sf1mi!bvx7b3JV*Y%61Pv){^uWBqpQ%1kzysgLwp ziHzM;KhPIWS_5H6c*NtUty#Tx4QbQsisyT?i3Ari{Z@DtQ9IS=q-;Cwr24qJ+fHXF zi|gx}*EFvS$L-zqZ#1D40$px49kVw(30q;In}66Z3X#9n2lTH1Kb+L^Eom^`@K zN-RydF)MMIGmw`yvqK+q+!n#lRHzb~xRdcVI%$QPB9?Y`X2nz6(ure-QnuH!ZA&{3 z&3_RxO6_&}vT5y6h2pdA( zRBt+#uUNCjq zysVRm+i3%h0jv=52HAC5NqeFOd2%ufqgj}>(9`0BR9qq4a6IAhXA7dpVii`4v^6xo z*}c-lS_RW{^Hf2cE&^6yox+kyBREcqc3ngilDu>>%t$)QO<%1Ydsz@?W4-L2Lw|Lh zjBp8JLw@Nzg;_Lq!_JJG$a?n0me(J|#=Lc#6c$XK5(duag|uQZJHw1z$(-zKm^Op{ zpB2*_URr={QfTPAcDyQp3-D@%Q(xgB0~b=;JmCdyk`A~?60#E)k1G>hS7$ssX6{+B7Q3#pAgGJ1(PfJ4u8B;=-$Ny8n2*%_b`}_XEO#aGjQ%W6WR;wRPMcaUlp#$ z4Ycz3eFHZ!qu87~?Y&+Q@5lNo+>8&fvZnOHhphWNg|S zvj_5b?yLF!lP|?1d4D^;#Zfiy#mf}L*Kxma`3AjF)atx! zZ?B!U<6CS?x4v&OYQ??w)IhdSnTp#-ifyxCPzi~FZ%q<5-IE>);6Z#_p?urc&Ea(> zzN^qUMp(jQ%C7cE07vmXDQU-!^ZitQJ$^@t=*`*xH|V_vA;xpVKLAZZ;9GOSxWMuT-u&-l_gNRx;-NFL`Mu z$@F5X8Tb_=m9cv5ZD|(LMGX^b+{7sT2EPs9*LZ5eEKw{P)6NpVmz(#rf@(JL2fBk! z%DAZrmHd<>oyVT!f4L#)*4KtMdcRU|p zAN)tL=I6_p+z7hwUkbi$UB^0N$sSMs8!uMk1^kDiJ-5T%!`{Oe#hB<)>Pbca7cU2J z6-H^u9w!xd_hd}PH-gFW+OwP#OZthWR8hgqs*LAVIsLQKNfm-< zDnnuZ*eSY12AtxAs469^`uU16RTT@_>1)@TY6gv$=4++gltX>>%~iAX5T#~I1>ZhJ zdaLSy3aA?L3mscS;|zWuzB?AU4^qI zNto?ZCh>U2l-!_}lecQ*Eg3u0p5kUYJK)*zvCFEON=B&mi%K?{MZ0z5h7Vq4mIXtt zVuL6=^zus+2mAag6g>ICEbB?JsN>B^ zIvIJmW~4mu>Zyo`C1cO-wD;(-Tb-pR7ZkG~{zlLq6{S_()%a6ZkCOOstXTD+m`gMtAH8 zl^w*~6$dfD=^z$_4`N}c{2&$$;pDp@e{)ceCHZsaa>^uk{|${JSQhPQ9K`$_mXBaX zw6SLhO&VR9!)ev6{FlQSLpW;?3vxJjKY!M)$f0dNnt5g}e+!~HY#v5O^uj^BCfa!f z6$kvYR@{wlGTEMkl|#I{F&f=LYEsPa9K^y%8IMKE2eBv`sc6cfzk3kLh~aNFD_SeV zn!8zR?nj_094gBp8!FFX?=7er#x)W10NMq=HX1RHQr76RA#()#qLIK5t~=CP<$rGt z)&^^GY;T4-L;h! zx8aeHaTE_VX{u<%(CiFxa1Qs1cYp6Ia(p0Sj%cYNGZY9HLJ`hWt}LNs9O#e{9FFdg z6Gx*Xc#s+n;XBn258=@v{4j@~M9dr>51A3;06N8Cl_6QUuPIuz$mpqlk`@i)cR4&$ z{l{Zw75B}a>SwjZe?7LPB1T!OSzGCQZM3!WW9rOW^Ol#piz&e0Le1>Xl7B={Rk9t8 zlu3ZApBu(M@5W0xCa?14RKaS73uCf|6 zv#Y$dBB$omR`hfYsS|Q)KGP(nNuqm%qKbzU^agXgwaZV%nc8#)|{g8edXn5(bTvir`C7t3lt}KO=tMd5p`} z)TTmkxsTPjk?(~|aSuMq$y?wZ9H#{iazqvQ4II_*Av~<%;~aXn3m{*6?fUQ4Jqe zKU7Zv>c{FajX$OSDA0Gk?*smsszt+q3j1#LeL~{`1;5Sr8I21R{C3|#jSCcf*f*ka zfr20M-LG+hfQ62eJ^NSpy2=US7=-y zaeuXcp5Pi1hfkf)vU?rs{)Hqn&gb>HNVWjJ)^j8 zN+Op;ROpFOlub=z;IO9pg%~ys)e~BybEem5luh&hL}Qce<_S9UWU?BEQL=itaF_!P z_fBDmihIcKP+=8rGgQk<@RLfMIYz^+0u>~%r5i0{8)c;%;`02)3pja{9lDHtx#@WCKTt~t z2$O>I1(UvhXn)s3>*2<`Rq)hx(N-ub-Uyn$&&o_jw6Ay7F_yC$FmrAc5ZHIW|~8EW!xjm$DK{!wCc zsrBM_-Y+gz#-PB|wd_e>%OvtoudXS`%NST3)$u;9#PHGA132V008is5+=%tf;01 z2KV`uQ01n~KQq7;Q(RRGhO^*sFwW~Nck?K50F$eimoJ!Fdq%DPjF~5(kCyrtrB6^x z2MB7q>hqI~fKq>W9MyF`*ZY{&YWyuPB(#a01}G^NZD<;|W@X}lp-q9%k~Dp%rKBxM9|>tv+O#z- zZ2xm-R@#*%NLzpY_RhKY+;h)8=Rc3D*WUl)3q*94xJQ4`>HF>*+=k>I%SvnTSG%J=I)04-nLdI(99?{a4-rkfOjb*f4 z%wQR*)K!}{Zr%jm{MPdRkwQ9+32RJ?Z2+lfM~$qm=Z)+rW{>N63uj?|YsaRJt+AAT zyy@Nm2|<6sA+wNA>Ngr`UC?D_ezbEmucgv@=XhSr<@9`Kf7Y_KbXp;=pe1)`$Fb1m-G?6Drp(lf(pY;QXt$kW<(AViC3Nstt(6SVFBp|?T}L0U?6AqvsL8uHPy z5Cy1)zgC1ONVWWR8QiJKU2E5`UoU8M&I`H@-4>V5G|Wyu%%!Ajhipd8wzd!0yw)B2 z7^Z*h+fm)_OKX-TsG+s3LYAD|7NRR?HCsUy6skN{p(Z#)KVew5B@K2cL~E%fNX>L* z72F)16lxXJC}#_{k?!m>(`ld($hH)U2&&ODIeQ`wX@cs@dPq*5gBtA=3sRIiz?#Mk ztAKOsTH6j+TO&m4X#;DqQPAR9YYGCJ8fJe)_vG`MJX4`9LF!^p*BaJ#BM;5Y{6vVZ zb}rP73u-B#zp*twJC3&T#jl}jc|VZ3s9JG_ZV;px)(*a1hk(O}Z6TQ5b);W_SdDOZSYqML)%M*V`;{fMwqXh2YN>xaTr z#@MbP#c8)7uVvh&OC=)xLrs4zw+o65*;*c{V(kWnJ`$wc7+r1EHpyxk&KEXk zojG89JD;Qp+WFyF;p4SDUv(Na>Kwap-=v^rs42$CL^&t+xdltm<~dOE;Z6j=hi>kP zZQQ&iK%*!nlEu=Kg}h-;bnZeuZW(_t%`r*` z=?;R%%PY0(&*lm?MCe*ZA(N9swek+$?hI0nP>dEF?p4Sx=L7ImZ9fh`;tMhFYdze{ zkUT*XK^mvK5LJa-O0%K6f~Ed`7JCof%NpHR7AJ4BZ!B+)Yr~u??}waZ+O+f#{Ww>Z zar!9aq~wKg60%rth#sV$U?G1$S-w_oi*r-SqmBdKnNqaOuH)|sDyZEf>r z{e-jU5=c)+^v}`9g7mZW^V|TS+pxz%^l`d{gZvYiVk~8G@l~yTm+p2IfskLIUu0cA zDJV9-3+LH+ig%ty@v+Uau1j0zRP~qWGtB!K*P1&E=%+&T1Si`z`elDMAUZD_HvO!V zr+)=0AK>a4w#;DF$RD|mUpXFqen45o1I^1<+GnIP{)vyrVc}`uZ2`S#9YI&&U#xV>gk8`)HBY87} zG+^fo7N;Ij33sQjnhKtf%N%o9m;Xa8;MJBU{MmdFgg2cY$7H z{+FucRj?@Zy9hPBc6OP0eMef)Kq?~h_qe_JGQEsEl+{nz?!xTYp02E~(pQ-MHB_Wa zwB7+VClvYvXpD&7jY1isuW}^6PG3XDnYSP3nBSMz_|<=;In4-X#;>D!wX_kL5m=U> zD}SV%1ttHO{v=3$M1RUBqYw0Fj-h+NUH`&KIp08@EIXmMFfzi4U{ArWs3d8%KZHg~9)ctJ*)(clhU{ybDDuD51zHA|0YH(s@Sc_baRDo{B*F7rX@e%mTuc zn-sZI4bZ=GMn?pBIr;<_P>RdJolO5ZQ#&RDeoQ z47PC_g%DoHfXV}60jALc! z5e>5n?!2vgMZpz~Fu7PJXzh@mM{KBh-7e&_Na{E5+qV~#l|yPp{xwrN%qdosAA9cU ziokyZ)n}Xg2jdkcaTeoHZI!q@C{~Iqs<*`zfmh=q6fv%eS?9Tj)H`ec%o-#$iRPeK zBi14(;KkLeSw^y_fYN{z?G&Y%Cc12y`Gg^K#Fb(l+YE2ddH^snq;~qWD;cex9Q(P^&Sq9$ki=;AI%H;@&Yn`R* z$~BJfa5HN0tb5$x^h$%S>-*sOkmyAhD0)O6H-B@qj+Kbo!HBvMhEow>Dugp`@KAqz zha-FS^vOdeGH_Y_nam*YKwREBZ;leX_zHMrEg6+2u;G@t)2WKRtmArdOVuA4&}!=( zQA3DeJQ_HDovGQy$C(At_KO2Su}>Vt2E*bOI-f7((B_0h0+}5vhkV5UmJs12G!LVQ z5{uvTdiIjPWz7!lwcGU(t&q0M^xl72+j0JF;wZcM_Ub<_{ci;+Vi+~L+yUanX&0=% zFlg@Jo+q!+n=SCXQc0IXcb-VY!a_xiyvccG*YBB2aB}s zGzHI5=fEUgA1%_R#K0@$pDcgTiskqn!iiDV~Un$Q13Fq)&ni(DpuF z$+rIzwp_&X93>Xei`0zy=0qYMsXshLN1*H}YK_YC*F?|LZLHu?(8GU;_{+37`hxcf zs)>3wPLfx=Qh7w`k|P#MA|gOUzW@_05O?ACZdzD^sXc7zHlh+N<-upOOVyG`q0QyB zh2#UJP#0(vY6_R&4`%Oj83eN{4tvX$CF)_i*`aU1*F{=gf^QaJCJv9>4Fw`_xE~w$ zVs;F|j>B6YgV@I~I|+Zjw*ZWHu%`sR8q#UR^(wD3biUgD3VF}ekDa6J?(>vObbF&y zWYsO9F9o`NVK2Mv?!*@VV^kjt`#g>QBK_DT+)bZo^e=dv{r+Yw>@CvCBK;KhKZN~L z^sr}(uhAEK;YsRx=ZMgAjj@sZSp~=>sCZ-p+C! zPwXzzlc%6kG*P6dfVQXO3VS7Sq}%I>40)qNzV;!1Y^eU%!(PWl&m`cW-@G8TxBv?@ z(q%9?0m033Y{T#7X@`BBg1+}@nL>9clvAisq7@|b9Y_)iJy2rv!s3n-r}^Nnixen9 zy1!zvpr95IIx~MJT?f015cm-LbP;(gHb^&jR-Y*SxCom2;KxUB{A>8G;YW}gw)-Va zh_*x|kYgC0W&E!7T)Qd?E3ab6N204X0`ceQxzptHJacjZZ2B#5KJ^TC3VHX1D!JKa<7(`R_&9HBZ{;o)W-|emQ&VtsbX>l1^ z-<>RdCzf#W^fvxamhK;j;H0-Nv=`}nXZYs=vRM#U>6J!XD#zud%CU)BD8kZ*cfq1QQz!PLaynVx+^p>aTn=v`V-!mYeg0OqBPcgerK42~e=r2vkH zG1k#Pm%T=JVgu*%TcYjf=m%#KyCaFS6y`9D9<6`>w<-D|!Uq9X{~!2icfT*<2XR)U z_g&W5Q8d=fD?HOn7jPH>5`N?k2Rq0yH!7g&gje{So z6-IwncYvV zdWvFu;@UcT^$AX9UFYeY1Z%bGD5DjoxT!((L+!BQC^sc`UKj`iwv+UIcPxf|iK5uk z?XPPEpm!C;;1+L9S4~Yc{S1Yc)i!z`eDpLek1gX#y{qP|&@i>EwkSr!fp$+LV&%Imp{us5X0r4I>)Rj< zRx26~g#EFz;*JK9h7HT1gSr=pvb`hliFxo0s`ci9@-^X{261QkehtFHXH1$1_bz`p z?utx_6BjBazf1v6*C)e1{(?epM=sDBM1v_NMO==b1yJ&IucUco`d+%9z6YAeZ-YKb zpOZ9?On;t=lID@=m*`bV^T_m9@XIuhO#cv1V5WIw`aQ8g(ma9|9^q$Nj!Z8SOC`-C z(<{XqN%P2bm)It09+@5#`z6gI)3<+$5lQpN^qt}!N%P3`)8ZTQo-#KGgO-$_I$ANI zh$T)L7+1s^j%p-;X4#}+g+qOu%CTO;SLK4c0V3jZNoI^@xvYrwRT5WFt+UF-2yOMu zcCVM$yJxM7s`Z8vHOzIg(=JpTJFPBOR?`A^MfN+2yWL4>?tMIHJ1VCk*S$Xu+H8!o z*C1&%_4)XjDP)i30Nr98+ z5)l9Z(;$-(8XS{okuHC0PZL2DhToyULMfC|KoC$|72CqH+%yd}CWgd>q+VhTM!rpV zhwZ}N*bBxO`62uYHHwKJ`~m(V^@H&YEkdxBo$O}zo%6isOwP>r-(SB0Si=&-(c$6q z@>{jejXmL+>bh#|s0*s$yMgWS*!Dfm^-V!~C>+5fL5mF@X-0oT7<*CTM(X+wcOtQ% z2A1aXK(nQXX|AoV++C&EuzbqzB#uKu)Zp4O{R+>rJt0Edvq(JyQV52=%IOSt3->%`m*n54i4d&(fdPcZCrv z=w%o^Qy&uHnY@4Q2nBr%J^P6*Vg|O&(0kwZ?DzpgcVWA@#gHl#w=&3JC=CVK4AL0r zM-Ote;`kQBSfP66TZ`pBDv~=_L+woz3s=DyF@8dM#+r!j>(3}YCQ5L(lED>B^kW>8 z4EZ(z3Z@v8KnjkR!3;*zn8r0KnV)QjVd;D=8x0=T#D0GwJVR89)pnb&FzA;d{}ee3 zRp!0Pu+ov;-0YZe`EsaD$~l?x4mG~8(b0M0?^+v!k~Em7u5QpNWEiZ)bkHC3;Dv-4 zvQ;{SPZGB-!V?8K>ahZbetL7V>2yzeXr93!eKqubTl#B+kt3u(;_Cb{uFF7%#ir#?3=uPn8!cw7#pIgIK$E%kvh<$Bu2bq4ve0ST zOO%wQ!|j&CJ#^Cm@=b?9=`cNWjKT$vA4Hvbq)t4FovWBS#=?KApbJDUayj(}P)i30 zC$0jCTLJ(8S_G338XS|*HV>2Ueh8B=lqG*n{~4>;Cs6j(O4FdN5UL0wcoGza-nW}+ zvh8LQcGGwe`yjrBC&7ac;6sTM(Sx%vAK!1knPoq}-ai0f0(%TzHkxp^5pF z%LN~DnP-L4qExvFvOGrO7BvcobeRel$Q0$utux1`3!xnjd65K}C<0aQh~vrlb zSsVS$FVt$js6?oRNy6Lt5@p$j7K7HgGOD~_aL~W`38*}* zx1RlXgBb&_KbUo)1HKP!*kRDPqAw~y51M4_VstvNO?{VKkJKY=9=$>L^*2z1E%3ep zP)i30?%vMzBmn>bYLk(G9g~`sO@F3AF@%KJLN!7!wnzmVpb{*mUT`uwNd_h}FeAo#wKHWDVB`scGWRVO&GS7s@g?Pa+jN2^EfFhnwQcmTz_Bp{Hhn5 zENQ04lQE~9s%lQkkQl|{#Q5ba<7De*_WVn}X_COJXsJtdAXi-k3=3x5Tj3}?z*pfYqC-cDNW@saxxM9`%ojFSv~P2XwTG$}IG<|*iA2=S^Twg{2obo_9T2zqcv z#cA|1^fpz^JQbX!uvZPs5Z8mS_aZol0Tul?&(PnR;hg38A}3s~Reu${A)_5CFmQcS z#UL&)beOhQWH{F}YVi+jFCr$x3^AP0P21xUye$I{VwkX-xz1`{g-THnS1}@!>Rjhr zIW7*DOCldf4Y>+zY?9XAeL?d)9gwnsHHt_RYY9hrrywK6SNHlu=4eX%7Z)q=xl8T+TlQ9zj#$B3H4RGU+9utJ8}C$~s#a-H7>0TD-I=p<|?jeg)QO1m~E&*i2qRJ#WG_@s+gP*EiaPTy1=RitZSA(wv#V zR;U?4_-ltji}srm!=p*PD>VrCQ~Rdqu;55{J~YAL2(Qyo87bc_TQ98rV#}utghX#a zRXk0>NropmfSXPmM;=(KUl|NG8tdJqyzTu^614zprYARC;H=f`v29SH4wJQZvRDdD zD?Tjr;lsjeF967tM7KB7g_?13{TioVh~Vr=7d0`lC>QQJt6y(}wDgpyO~ozBwFHDe zdyvT-4)rXGg<7l2FIgdNPMHt7$y=0U+VWvk1pwM9S7+Mpn8`Kk~A(_q74L!c*vaqwxYBDD_zN8 zdQ$L}F|a*cVy?Dtw30uFrnwl87&tZ9xiA4Bt?@g(CfX0719HiL+Atf#3f_{tvj5(% zmCFUAGfVzX)Jc!g8Amy%e2Q1WuTIfm#)^+Z)f&rCPcJf(rr?Ta*neL4Vz{V29A8;& zoU(8`4m2XFDASL{2_fUWszgTREg$ef=IzZDT5UvndCiuYWN2CtYb~bZopC#(U%H2g z4$g4&j_=PwYk-&~h=vF-3;kSWIu?pp)ew+zlDqc9Vu9QjjuK62v589n4c&*djXPAB zX~vf>ESV0|1d^4P%buraUEX8W<&i#?m8mL*-WyMp!-aluvpHzZvQBK$c5R08mZ$j$ zZEC-3UrN|?=_zZ<3s9VnyYWLeUJ#GA-%e^{l5yWPoQ~uFj#g*@2YCrhzuqA=6KRR5 zSVPi%k4sJEe62QU*6JsdPG7hbg71tEi}Lv7Ah@HH|h{RdCL} z$3C9L;Ytua_bc<*_R$?N9T?<%7=s^yAFHf75ph*n^N56)blx1(x^N?6J&rvm63@kV zn;4Zts)_3fu%4Nb*8CQ8#XhKsr>B;bC#Ff5PJBaT%7Hgg% zK>dAb6J74w1wnHH|B~fG(_M3@89=>BBdvt3Qa+WGB(ngY>5+tr*BM4!B*`yEs%HN^qW~OpY=Vf4Ey6k$}K#RJD3+E4axBJ%CrhIW6 zzQi|n(eP#i(MtCX+^gqC!}F3emHJkNjJHq;QwX79-`KX-xgM&SymJ_%29JhH*V~3y z)LRTs8s2we-YsxY=nu-u^TkAa&q7pnyPvAdy0=GCD??aoXNJPn?eTtS-LN$0NvZ(L z^G_>MO_q!V}bB>F)4Ebm`d{f3Uyf+NYxwMPB$!>HWhGL zJ0l4+dJLK{c0%pB?;RBjg*cwf7pd}h)#1AONh-g@ggj0s#YU(=(W)!4$mHYJLsB}o z-xa1Sc#CWZ65gaxuP~Htz;|9-SOL}rMz84AYIRv4|R{M-rl{X6+WeP z*?{P+*s-@}TRyPjvYR&v&Tjkg$!ci=0&x(jpq0fZ z!q-lHNJtqbV)$PYx_o&(t%Ton^`=|jF26hlP3tybYy(@d|$eP&cnH2S&B(v@r|J`B=d=cOYbo%&B=2Xec58}o zPphF-AGe0~_*mw)VhIY?7EX_r2?hRfev8pHy@%_GTMzB<9b_p*ii^@;;zkW>V!z3ViX!MSBcf zS#Q0RY__kzo4=J3e>?X)MCsk;Sj~HbyB=_(pJ@dvxtfpYT(&io9w}{N_=J2MuM+!u zU4;uxEQZ>scmjA5$I7lh7*X-%GubZv%fEA*r@*qYSmQ+CDb3KY9|iz3ESVbVd7 z`SWcoS77M3C%Z}F2HEDV&R5jKfNuZT-PU%2oE|BUn)5E<5e6}Q@N><5jpYwf50ZZg zwKz<3qWo!#k@r{1=T#hHM*KgtjhHCp)Efs@8r{=es4)n48a7&I_+rMC^=*Ko{;@IL z&s;{ZLTTJ?gnsTVCCvtmwt`SHps0-8>44bvn#zI9?|n{qp&a5J$8q_XMx*MN^}?aJ)V$cm7fDuN8KZ zXsu(2=*@*@;q(5PE6bw8$a0oV!{*V;%P*1T@ey9WWoJx2Q+LEGctiZ~>^#plCa-ze z%+?>TQ^d4=ZoPb^uf3?h-;k%tSwtx%h0{N5xC1*ZvA~!#KP8-6>0po~7nMTize`cm zpnGYa1-KUAXxZlko(chwLRX$$`}{BQ5?gFOSjWlUY6h?IKQUBhKIH^uWC$1=#;eg=-u#aE$u^xLTwL z`y==a0;wMY&I%p?nT3S+OXJzs%^f1UWlUzZKWsH0C@;Q5`;TBN>r*K8iWuc$7ICrt z3t@kRIsYBc-x9xpV4&ft2#lfuNuJwwlS`31{5%v98FCF<{2#6ZP{Zla?8~44AvjKI+!^2uP6(*Q ziSYa(_5XJyj=&bq40b>}PYwWaD1ap$U>nCnmH;NAk9M{Dt%z$`6bu^e>NF# z`Vhd}5MX-=1swE6_N##QA2#6J7f@;gBT7bD2?Jnfc$!k{``oDXK>{sOg=O)_MwhfD_Xc&okfivFfsW#rOD`DIwo|%B} zfeDt#i{l23mKWe zR<>b`0|-(-jNu^n$4@2@IQkX_p<%hQ1qs{Cbq0E z>L1hef!!ZqHNQQ6z1)Z}8DN>1TcoavxZzW%0LL~YbW_aN#P+GAs2 zR=Z~-!vbIPqC?W$cTU|nm2|JJ-VD$F;SzfK$uj2%)ibp94<7pYf*|dq7ftx!LfmBJ zXv34lP0VN+okYf|iD|UE^cD53M}OvlGPiN1LDGISKtfYKrb~!*5miZ%l142qqMaqW zu$KL6zcef>;NsR-kEyi~bIH10_<;;~&m!rjxXS`i4+uy$PYtHrs8kPDH;Zk}Z^r4n z<^xCJw*MOn&n=d&+EdvqjfjpH{=QF>=iOaj0;7~3pn&I zae>t!M$%P+F@RC%6pEPlu~_K&{>k~{I4J-qVf6-^AAqRH{qFMoy2|AO(Np{*j0vdwzdoh)JQ;Fchq#(r6RJu|x zHXpfK)~z3_)Qk>7o^jv*z)9zY3G@(}W_BUhuvvD9i79Pgt@EGgj?r`twl;=o#HxMo(*a( z*76K}@W72{ngiSF20&+U(5#B`y-FL8qP@2peO^0nI&0+N_W|XKC25UTWDCD4H9bm* zr)p+W<}lWO!~}sLMaH-TnXrI`Rbccjz6=vIB70%9o5$4sHcbM&&Hc#J{L>c&xulgM z{SG)Hk`&CLKR`-3guft@^79^lVo}r;`flw&#mE%b;In%-rLUV}eLoOr*(7Kon7Bk? zY%0LN)-gVgjCrfm8;8K|NWdJyp}-QYUVD8k1C|~|*fhIH50h2R@IeEeSYwMjJ(tQu zzA&>5+w^;J?3hdj-Xw3>|1S6v=f_@FXSETu>KV#W`)N4!Td+rIw`2{-$+AX1fmtwN z8ErJRLmQOWF;;{^6GdT9oVG-Gvnih4k70?Yi`guFgez8i45DJ?=gu8hvd&oyNk$}8 zk&0O-yQzd4{x+e}kIph7V*NtQ*PneKI__ThW-7@c1W`MUzs<$q?&F+DB<^%TNiqIn z968lJnX_}6@@opO5-z^<*Qa&M7V%#mP1Y9{=4eOrPoBfAOh=d7@A27WqguN#$ZrV$ zdt}S6`#n0~U|>xNf5`9?K8eW_q)N#WDljl1AjqNc-dOhyt*XP@GHRzb%L5F&@jW-!FkatbU4@qZJEKj*_MXcE z+ z`sLi%>0=yw%!Sr)E&3k9zHAe2!_y}RXrdvSPV7MU@BGjsndLN3(kvK<3wCTg*?;W__49<-WuF+mr!M6qbKpcS)7b7M0< zAW~@=JeV$XK`HR8`}JGz6RdjttSlt_iKiU_cSZ7ge1d2Cjd$8x;K|wJ2;hdY(BWD}e;VIw~nWE($m?ejf-Uy~#&XT)w1QQ!tTB05?~Tz}qd(mdCNwZH{t@ zpR?R_^T7CvZ#%rkO#x-YIwyH^wkpOyjXPA;N9Lq=Cw>kL(C2{!WH)X>(#H%MH~DQx|b`NMrB zNc1cqd&jX*6;Ta4p6Ve%CJnGu{wrAnZhIy|3nx#Ku{2R}32PIfH&fL3SYe%d!Pitd zDULXt1ivZ1=AZzC*RkF*SUC%6^E1IkC^l8?S@vl&RTYD1dd)S+=t*XAq+TIbT+LLs zxy}EL``v!!X~*KqC%E-)0ncJn(qSsp5q9c zt4*(Ts+#d<%k%zJ$AS?_1`zvkC8rJ$;&&%;#mAX;V{)-nR#!v=;DL3#kc|7Es| zpn~bfs$d+juP5>llBJ2=mh4{Cpsx-h_%b5(9)E<>?w{>Ea?nPUk3%ghU^{%vWqI+d z0}xv`s`7${$rFmz9W^R&s_EW7j>S}WG`8`tAyJYqA?K2D9U7_m{uHJdlgtTG=(**Y zwFkb6rQpF)ft;m>F8?NYzQRt8@ggE*YH%__fcAmN+Fh_Gl}va7V_`na&byDll9;1k zn8Ra!SSh;`E@vj0g@4!jk^q6Tf_ShckL5QwcrA-5t9lc_d4A1rWUx;J+0j0?5Goi_ z4%>z03W~IL@IlDAEpm+uj+=OB!;6kJec*r3kAQUX+=7HrNwZSwu`741+*7M>Y_<8& z=}82-7~MW2PMSbj{+!1O3Z7WAtT+3lse$^Zo|~6>L`hTP2Dt$V+p&AmiC7eKyI zyNMC=qUR*nVfcveWTT^&(LPtmdXUT-$KL>p4pBmUlPysyJ0?sddWZu##2GLc+C}+3&E!{mr1eXncb|9DxL$9n>h^*k)GttNDaD7Eo*GhKy6c5_B;>_z?jW zGa4#w%pyOE_ar2~zBz9d+|c4B0)J(N$bBp7zim{}p?T#I=f({Ta1&x=R=&#c`Q!@4K<5t&ZzXP9PAOSB@o=-sdx3U&2y%@F`dE{QYH2%%(edNaKsd zEf}Mw*!7!tKf(&8X3r=`z+g%Y=IeGAZ;?Shuj(G&oJC;CGi5+~ zO^+*tkEmdFOYxt0=GV|OfINmnlrqILzecz-`;lm>= z7!R!o$CUw&dUquEN10Aql$5LrN4~-IFMMFn>g3J|a#c6n4@7ayf+cZ&D5WO8Pja{7v)qpW*x7ZdEG| z0|o}3uuE(Y3{0}k0-*iao`GNMOoZFh>9Gj1FkZ+QYpCx^9ln(i!~zRR3dqV<~VZ!3a!|SlThW<;EBhJ1n8g(rZ2Z5bEo-#|aqTX_%$+Iohx=ayLFuU~r%I~YZ|<<}Z8 zY?0f{oZq>(Rmnsxy8H7_t z(_-QH87yD?)~+has8Z3txcl}Z*mOnPcrVg!%s znK=vv%47VB-zFduAlf+zZ}f0V4j5-6>>>kN45R;;9Jc)s$Rms@-=i_RZ3(cZVc1jF zF^S6E8F$rx1bVwFswrSlNF@~2p21<4wuH5E9nxEg$NT2IXlMbj`7GaYHgQ0;E1g>p zYa||{>s38m?E1Ow;}#P2g6%)nj+Fj1N*7a`Fo`xPdS<PTwU9XZ3)AaUWegKa%@{yx-ZO8p zEHpr(S~qy&LiLceT2VjPwC(>nxcOkE)`Sc)4`6Fz#_y7rfTjkSRuu+e8X=K@V6eCy zLY7VWW`uTamUgkwIG7vk_gs)nUKrAj2=;W-pN;rSih7>ymnnA!=fnSUs;oiW?%n99 z_-TIn-`6e&r_+kEqs5>y%nOM5y=+Yvw)RxiAQ?lrOL!KHmhuy*+^cr-bv5(54JR?6 zFdq|J2BAe!bzD|D&f+jd7_Ex>=S#flj~$E_4r%ROtRm7NHvGUD5n|nNF%K&bAFjf` z1G%rI-y(?{H0h*tJ2>cjnRFAy=VE!y!wT%uMho+7ohh58rO$NQguhqdKmRNiaPSPX z@!CLzx57qI%d+=aU}Zb~q6VCv()+Uj`P}8qqI0)sQ!jf)_|AEDeI7ebQn$eSGb~)a z9kPXu(fRcGSO8_?r9MJ#nP(F8AX&_1GvpkFgJyjQ4^bIf5c;y!Vk@Ua+SW7V-q_*Bw!`P%@n{Fl!M zZ;9r|;;H(~^bB1z@96v-)oS034owA0+deH@kkx^@sFkY^s3nXLmA4MKw9{i(b>&C61 zL<@6BBgqWdN*jHnWQbfvHWQ>&Z5LI~${pl1m3I3zLZ96Tx!K8`F8Bxf2N2eODO8|1 z2(o9SJ8UVX;Y@^{*o0thH7qBW+`+$T0Gqq37f5m}x=eltXSq0|9@ebunzKKP`D&{1 zr!l+h6SvoxL~Z1Z>@)!emf&((QN2i zwLDm46e408vEPz|{u#?Wt5_XdNf%Kx#LvVZn3*&WJxIqf!jU30ULp^@(|21FcN6cP z?;l`b`UYve)9vkdmvYF?j#1ojO%TkmOW<+l!KxdhIw6|bL^sgrP7!3^TM-A52OH^G zacz)V>RK?+EK_fQB#B$3TWf2`8T!=AE?-MX(uJWlA_R7dq1;J0vyxdTJi^8&jC<{8 zIm_*a0r@*_I9P#Z0*p~Tq@}UFW_EK_?7T`?aOC;@yyGqMUI#8iQDS#D4cB}EFuue1 z9Dl|PZo*?c3R>jz=bzz&tp&4$eATT^95}Y=1`otbH!ES_n^eYqwGm z?#o|?taDNaDqP54EpmKX8ibgQuqP#BTMh60+4Mdsx_Sq9`&_S0%HuhF983~#!2^mW z1q(}zml4eEVbggeB(Oxx`W)2?Ye_^6-4}nKP>_3q3Ex6y>03KxOznJn%}Y6=xP{+c z5Y2vK2`mhwgy|e@ghF7_`FDnPPTobtw&%S`b7GG z=(3ud6Ga977Le|2pLzaf7C)NC`jqW`H1YAdKh6pEq-6f=;PamM^6SFkLy}9^ReRCf zN^Vhiot2&-wJLwrP92#sn7oDYxNh24?h4@pI6}D6)wa2x%xG0+Zo%=y#=3B9V{3cr zPN-O6lYR6Aoh%l#eY8e_A8ec&jXdW9FbWZVRgHKy`_StwbsbdnO@THZY1r^z7(|^% z0i@GLfrveqQ4lv-aNDbFor~Kgq^Dc&gLT%Q`m(i!N-~543_oL$Jp1>eXIHN9;Q1th z#G}YZa|TrBA6N(V!v-VLiY=|vXlp=78N?aR4+{vx&#AmAQ&LNlCbZwG0Yo&c~%<0jbrN!vV-Qj zpJHH&7SUOPalfQu^c+|N(Kkp?TaIRdI7*91X)IAOthuK=H1w!Viajo0ubw+Fdg7w8Ab!5^2jk&2(8 zb3s*~QowNOWs7N&rdL!kVLCB>Ysh#qKD`?%y3hYClDikVRf0dAF;GT^R0w&vJW7f! zoxQ3$A*ENO&IHc~MU}UL3RWm3%Hw)zUL~#J(Iq5X%HYQbkspFW0F1zILg^;%AxucT z)T-g`SM|-sX~q}@uo^fSz@?r27e`fRYy|B>T=RZd)4#cZRGadREY1Zbh47fR>WB(i zZNG}Xi=s|pC)tDB8c?TDD$cE?Tb%e*!%CFa zRd$tsEzwJYM_e+>8aZm0IOsmnx#`%!plB)S=zHECac2mkI;stc_mo`dzV zbox|6>WlOlUV-&ddY~x576#$P0nN(bI42|AV9u*5Njf=SvY`%kNFi|sE>>@Xz4~4a zliKF)H8?si!seNFzM{y$lh(TzE5xq^>;V7>A|uif2D>=HfcbR@1wF;*^*0}? zeH-dIBB}nItX9^i%%80FPfs~H-C!Gobp0uTfhmOwUcnjO!dkC+c6Mi;oA;e%`?oVU zg}X1we_BwgcKrVwd`AK}OQd=WO(NV6+FnAFRIA(e@2m9#!?r7WHXw##wVtfU&=m00nRu_0bQ{o{ zb(Gk2i(B@*2~vKgrRq7L!?J&9T}pj*>XeJm#TcCtBZ;9nf?lGpSsgY3VMI>Y@PDHr zZD+_qSn3?Wegn^xtGm4MLR}rC{AlV$^K1j``}qkug7T;wqD>_Hlb{$Z(L>y@;MW!xR>Vrq%&m1LUZB`wXd0=~|S{VEqorX`)A;AiX7`PIUOPlk0TMJO!9yOb)kQB-?dEDQ+Ji!WJJER zQk%pTn^w&57-5BqRxEY=$I8(q=c(fF(~S>i8AfCzysfm>P*x!&nW2xh|IDLh?VE%+ z12gQ61(>+zdmOs_mGb>>t^`rt;Zn4l-$q&LbZ@FF|AC7Jr;}d{aXbT!_LcW&Rn3L% z^2L;2xmO8$uzbnu8x_X)o>^#%j&Ga9k({oP5?~-B72(LW+^I0z61Z@&fd3EAO&$ol zT>jaDVMwrl5EB9t4Gb0*7VICytS0;ZZ@S11)K*7T$J!i*q#V#7|HFo1nr;Q>A4{W$ z+%XuM1P+I?Al`7#|wOWii-ZH{nudv?y=tOY%w zT$7gd$j3a#x2wK;{QYK{(f(WJ5O{wCrNYn~!C-MK3oU?si%{KcZ_{zGLX|y>C*86D zNK-^JVh5+|pgm)hwoYA0m#EqPt9Ji`Ri|0Zy+cb{&4azL6>r{rI$Kpfi@0L3xeHiS zbY@aB&g&Xq)JJ6rLQXbI9O0&<%a|hZ)>p7s(3eJcz8NNF0y*?nXoj~`odgJRR4TWb zII3YF1V&__gutksx3KkmV(E6E?MxH%CjF% zjd~sJ1y|^KIa_oI{;H+;pSAr2j;FFuc#>XS8LoH>v9cYZh!D+s@&rI|VS$2x6rdt} zJe2f)3n3NAALsU>5Z_sY7-klI10XUuCr=M5g0T7x)mGBU7be>7ph9@q*Lg1OAPN7_ zN0M^k2w}bHjJbiD20F*}x6Ap*j>Ri)J)Dda)7x^+0lOlgC0&#F>mPv!#RyPTNm#2c zqswN0oYlifx%^}LxuTMM7ugV9eFbm)gKT(J*pD?DCR`1R z)B>c?I^@d7j)QV4vMR)x?+Sa*#Zt$GfChZKpO5&H)b{&Y?qMxcJ2t8Cr+8sXyWiD9 z24~vQGw7Ymi3pa0aznY}BVRKlg1oM zP>U5Lv@ZBnifFcFQmv$myPZYcUcxQn#F@d z!Ji-O_FhXCZW9?mh*=Xy>{(6=>hFyEino*vpI}dzeQ&rcZs#{Old~XlJOqAUsGm6c zLVM`({Lk2JGZ%rHk$6@_>rTt-5&kj~>s|foqgDCEuYuLGI0y{8379R|2;vI#xmQqg z0wgCmjC90zcv0JsE8~j-+eF%cPxw+Uyih2F+1>+qP%<;{cAdl94)blL$Tv>|??S70 z({uxf*cCJ-+wY-C|8Y%`E;=f8=Z1o@g>`q2gu32LHp!~c|9hC=`M9o5#E1wBe$T-QA)rOX|7QP% zQ%IO`Ag8f%Uet~&UaV3)4^;a4-OME-lwoo8v(Rn_7ES8bYNtnu(*3`Q4biR6b zlljDZbdb{B_4T7i4Gk-s&)19bwNRka#H}^^VfuyjCvYT(8D30H1!%K4(+@>DE@kf& zMT=1!vmTB=kDvZC)KF!Q1%ci^_;G`cDdp$mwFk#F5>-|}+V*qfPqe{c}lUd{noMyU<>nJs0Cm6M` zI;b+z;%&D2pJNgOt$zYRD+WH;s%r(CD$# zt(IYEs#RPBDQB8vQKfI}wRI}7+H=Y{X{V-j7@Xgn*RFyAZ8FC4(iqW4GSC9${341< zdBe(+ug}9u+pM+?xLCJ{ZwDZtho1)^IOTgtMFLWK=RqocKuhev>$Y8Cd&V}$rpfRC zDK5(Wj+*#c%8D(ge%*wvqBicHgq;LOC69Y!!4+L2hf)qs^mQhvy)cTA=CfB%PH{&u z6CC5~CSVFvFVPR{rIYZoMLrkOP(?y;SXQowvR4;UHQ3ejxVx^U6dhJm)aC+jP1QT!*)wLK|gEtJJiVht5ln&R4ZA9ax0~l zr0lV)wxo%=a`xP3CPZzvzbbY*m}fw>P@|x*2bsVgI6ar$k{whQMoN5J!CJ$Nd5IEY zlh5p0>01TkyiX9{_qPjIMk6`QlMROTAuj7KN{d+k%xBT1QiRHd!AG{o8KkLLLb}WY z2E4zb|0#Zt9AiRf5Ye~jz%;V~} z@a;wLD8WVf(C3oMa}|k~pi4YGsmf_!D8pzlcZ|<&zkdwqXghi5#*!>-igqZA>{We- zH4oS}EQ!1m?h?FpNZ?f-5+i<->hcM_@wi3@Qebxtg2T-NsvR36S5^05uLz8?0ZaYt zfn)am4x2`XQ=Y$bou_7qF*tM7{eVJPSZrR=JxW3V-5{B~!T^EY1ST1y;Ni%$YfqT7}XryhqVELkq%RK4Fo`bN$dU@0e| zga$#;qSHvR%Gzhqf^*oiZXxkos?X&7tJN5Xy~WQJ1Qto)uCqUX{IMp9OKuT2f` z@Bty1(fDdlEh=MPSK3m8OI)}YB&cZuVD0Fr;QtX@XCAqXH0n`VAyI*WZU^Fk0Ky%K zux2QCJBFhq=LDZGAD?erJ#9VXcXx7UvsaSrf7otgd=?+9yT;;kIaro8amX}9E3{e2 z@M~8S7!>)GA=JsH1Wu**OAe9tiQ@VNV}Lx|lV&0p_)berpHuD##u^TM*lelFIA@6? zr)*}fqDwanOWF?~UbLYW2Lh8qu!;8deKc(|Ajl>b+>qL&xLieSd_9>nD(>lc(ITac zw<^#+t#>Mh#>sdbAWC-sx@?{@$vYK26<dxSdiB<`Z!S=&!8gc@W6tKq3fh*r($WT26Bh zpgWOZURFw8imxDrO(DV1frAG=wv<8f{oqv&6#Y4_OF+wfb>FYm_tr>tWWh*J4_Q2| zSXI$oe)WAX6>M?85$YAq601;ngbEQ(7gJe@vF~gvPrcf8pzW?0Zb;G66aqU`Mu`r~ zDh=?Vcq>o$PPHgp#QWHec5Cmr*-q;@)xR&!ATJ4F3i?2L;eImC27Ll2A4PsxKML2 zM5rbUe|3wu4LevAo2i=a8t6S>tMM^0k1`#4Qgj(G1=20@N~8BLyfsDY zfk$YNh-b0aBNF49)L*cA3V4UGmgYq}zvzq?c#%r;tb$l-$98}=#d=}JKW?A%05D;a z4{Q5^_s-V1T+=&~vgO!3%5LeF8SAagHVlD!4GcEY$r)}G7yO!oQ=CCfXWpP2I||e) z?5PWfrj4mKpdjh;2kC63xMjgKun(tO)e%lW&EZ=L_84ND9Kc&Eo#EVdt9yL? zWpHJ=VBEzxwgDJShs^THfHgu0f=j(OZjsiXh9k`XqIVDS6@jdBH3$+B*>JC%ju^CE zesu~W6^RrWjI{RU3t$~6v(BRG5nJZgB&xEW#28^-CMhFTV6vR-?&)*R#5Wv#tqQ$x z%K3;wcpCfaX<4Rgr9ay%#ngC1P}fTcVAjch;u@PDE+)rHZ^$OIJrJzB!Lp>^{XPbZ zP@#H|@_!&Bdd{U8_1`i~%YRE*22%g4nC}VlRm=>gN^%NlLdd?8mn`RXq;ynUN07K6 zII0XpEL4$uGUo7JX9fEUn|eONlk8Q&&;)-GLSXiOX-`T<2Gaf+QL>f%Dj6620^16r zYBt8&i1LwU>LIGpMm+IJ=xCZtZhBmLJB@4atSXK~yHH$EDV?yc_dxz^7dMwlCH_}s z&aWY+9W$1Vqr^H&_^SPnQA4K22a+K?7>CY$?O`nQ{a!~?y38eeAYnb<4 zcN^e zOb0$xvHe^Op!@#Dg5VmL-`UgzEF<7GtE$X7Zig_&8u4b)`5POrK`Hu+k~v?b?&q>m zN7t=GA%U9(mQN}OnTm7XU+rEP7p0__Bie|T2bAYOPcaupnjwkWSF-^NFU zvt4UOD#yjD!kY+r=>AtxT%5x3zN}Mb%rg~5L)mzay0qux^srX2SV^f9So@;AjZJheBoXEjwP;b_e~KVtE3_X+=@ zV;7M=SLuB{J5q$sPD)2w+?;OZzwgS2E{Yu!>hgVi#!)0?yksZ5r$A;Edb-kUtR%*| zMK9J4Hj(4m3(71bT7M>4ePU~*iJ0J#j2DgYt&fe-UmK541P-+WMk3X+vFQ?jZvz%V zzs4a*`pnKYNG7C(yKgdZt+)1(GDNMc7}lokfO^O3V8Ptji}j$mOb$SBENL<|>>-h5M+=T>ItcqF&PJ`k7;qI*3s z*Gg2jFp!cuMT?7Si|nidetvJ?cc=-deA+sE*1JPP3Z_@0_wqGj_T?+a^H_dDsjL-H zNzk?IXO7kbC=XEi41EvHgJWWb61^`6)RKW{s^n(7%)GqkC&SZ0XRqB4`pEK(R`SS9lRP30xj1{r*n zl6zq+^%80W1sQ6*7b0rPYS;^Z7XDnN^JUGf`~G7I{V})Yt(Gz3q{D*X<-V*m?69lBZfo=(0WFSFE zyCz5*)Zrkc{h=9Q2+8k7Ld@`Ws$tRY!)J0!?U#OBl4`B@L%Ea;_cH|E;#R^7(zXhf z3&1(x4C;Lrl(d%8g0AJ3d$y<9R*d=Klexe<xGa42Jgls6wmw*%}fE7wt8 zZ~qpdi^Wg7^ESvJK0Up>(rcSxR1yc?jG0_m;eVrM+nWueN}I6Un?Wk9z@^*$9yHE> zxOd^Br)uTfKis?e{n>yhV2mBO?(A!q)k4w6>z1#6x9)EbLjuSE%45MPK+?3PTq4C|n~+68r1o8%YQTcco*1uS9gvg*9zj8(6J#;(0FH~4=B6^%R=FBs%Pk8 z*ob>nOFu?|DtNq|ftF2yBBl5fyi#O2iBcV8U;aN{{Tc7lB(`_v=bpIkao05Itta^= z1n!HO+aJ_Uw+JHnCd}EN^s05$2=c`{(lT%9X$muiKV9Tk`%iS~OpnUP7^#jDbu+tV zzIFGnOcE+tr)1}SI{RJD8b?aK_Kpv9(grr#e}>DdQVTRkAmu1#)pLb$lqn|;=nX^- zR2lKr(&H5J{Vq?u2h2?qUoopF`GO+h$+NPb6TEJI`0p>&8mk`i)^d&(uV>uTJp6}e zQuL%FWdFGfl>ZxMlgh~f=`mE1I~YsWg|(G>os@b>^m+urqN0$@R=!`1xiwGO3H|T3 zU?+dtqCr$HQX&00f1zGSR$I0~%H4eGW$Nel&%4Rb=a&)$hM;xh|ipb^%w)NR60FDcN@+rU=g{Vp>9OLgCW>$4k8I+!QaV&oSlIto@idJ)``*p@b}?%{BJ|zRC%jdu&Wy~w zBv#)flD?~ERi_aHPi;NAsFcY}Z|QfL@zOVYQ+&teH;)RLL5GgxweM#DeDN&C$5>*M z0Rk(<+)_p4S!8h;gmj0{Tpq@E&r8p?xM?VseWXT_6fgUVcKH7GE?77lZ>%GwP7r`q}4K( z{FjJ0yxok6FQ>|mld^PI?~KI&fjOJ(UQxJ`iA6jRdwPGOs>;4JwWk5(<^l=h9@59^ zl3RKrmeYm3aD}4Z1oe_Jg2<#bi~mOrqEfA4?hZ(B!EL!MXwRO#DX#qmBf3rU+z6BQ z#8f>Siri`15isS>bpuU%V*_PQQ!xA#>IaIu0MvAJf*FEUNQ_TGmYgoYz`J&==sW94YoEc*-?)pVbp0Fafx`{ z+Yr>=j$5PMHv8Pkwqn+!RtR_et9hbuQIeikPk$4=I8qsXp(a7iAP zu;I%&a`WkAH!`E=tLz!BF#x9UR}9y;rG@FU)I=2PKs5pyHE9!eIY!;plxD~&*Cn~^ zwXrjJI0HEjCnHe*B&#$l99K!tV1Mx=(VP-Zy!w;)HHez^G} zv`qOr(75ep<49pd@u*wkbAe$0_|dLui8<_Kwt7vZ5b?powUWA)uP3tkUWKQHAZg%q z;(5YY8!fV6I;jQ98896iL;mig4slNu-sm6(;Lh`+fovYp=$I+O(f+Fs{W-IAc|U$D zNdx_NfU_linEhfs6u|&3FBJWJ&v6))1^N6P$pC#+Jz~~msaN`)LsuyJpqaAyGI7$14`WItP2tZE#<-DaKKnLY_(;Y3K-4=Q`_M^ur5_dd zQbrRl53`8*)Y+JJzhX_f9!dh}p~3~D)h99%MR8rrhAbx=8#?TGbV&JVZUJ$|gyr@l zP2%_dbd1<0Fb4kcYwyI%lf$~P zWeWQ^_vF6mgm5MZ^JVE3^N3q{F)-2P_`gY)m2a}hIenuib2VvjAJI68&4#ce`aA#9 z*|tAJp2+p<#;wiA4CJWWJ5nT;-p%?OcaU9)Hb^$Wqd|JY9CJLLH~23_hjvLz+HGg; z#|pwWDaIC!-_%0_qS`vp=YaGolurjx0(seX6nW(Cm|con|j(Y8S{3WaX^^#({!#fpkLtgHRjFFU++R&^Qu z*Ry@O1Rm!7w^lzdwJYCr1*_~PfyxbOnXu|tlcJx~Fnwc^F~A&unVrhv)A*h2xA(OQ zh;~d&t3W9!(zyZnqaUAJTpTyr?BDek+O22X#t9DT7FH*7LqxNiiuh-wjoitqs=uCq z4q9d-HcHVeX+OU#`*dF5XWfF&dN+fqf(@5@;*0hvIvu6i>CdXYCrD+IB8snL zxl=bQ$-x{kbz%k9yuIpsNG|Qc?c*W~hdspTrInqA(eA%M^coOY-Gqb14gAx=KY9Sn7@bLqb8JD9BELKKjU#1T8f6X=bJCHur(EruPonivI;^jO%0Z$u#G?gn~1;N4nh6+B9wGB3#O ztQG74BljPkcD)>@ek$A2A7;7*_3=n;f7_!cRWqN}2x;D_+=4#0)KZh#_bI)#RsP#= zA@eBtif`Js_=JVicb_k}Gi2g&#I>b1K#!mm(LyiF-&Pp9?)@liOSAXEH!E^|QCvMP zOt_*s5MnP8>(Us)uQfm^l5>f6tDF0=|7;TqeD`8Xvv~-n2!HlDj$lXH5&RLN^^wbn z@Jh>{m%yG|O&*H<$eR8u+#|k4nnkOAjqug&$F}ytw$!{rd~n0Zn607yaftBasAm}p$C^3UXkoJvFPT#??1P~+W)rXyps$` z089O*b8o22+Khalr^jx7@-j*=V)!cR_kb{={;b1ZML^o1Z;&eSg^eqb68n+XLc+qn zv0p3H9t=Ym?WK{1DvU*<2SuJ6N!#7%i*z<5$Qgy~8k5N?eM0?8GH{^GO82+{b@R6Pu&}qmV&Yso`r!5&-r0% zHH^7IA8_pP8j90IREE|4ymX3SK+|G4pII$#f|sJ zOxV<70V=Axs8PYKBl^Wchrvnvhv3Ls%lTN@xfib&z9qG{vk&~c7SP8+WlMjCcvl)) z&0`Kn>e}FOHk+DAYkgXOn%4iu+f&!mzQ6zLBWf#QDHdFNd!e$ct4KSSur*tDgNf;V zhGGcalgxN;M{o$lPGpT$?DziwZ9tO0tZ(+E7t@*^IfgHPBg4&V^forut$PnSSJi*< z`>E$K5D%oW&MpOx8xScsa2Oqtin$l#_1gVf-LPq-zttcFitR8}7VWwo39N+5F&!ms zkIdIfMiD73Ob@vaRH3TZn-;8#WDSITKZCRchxXELITy^!O!2I7yPg2*jN##)%nBE%a zmT?ZHB4%)2ppde(+JLobxbTOn_EDUWpT|Xkl0(UJ74kgEk-&2GtdiBUP#KqSxrjN; zbK`6ofh}PC7x$-TE^!4{Gogz-saZQ+t%mFDCE;mYs=!?JpUszWGh^N=Lqnl}DclyA ze9Di_yPrayKbYX^92;92iYW1Ym%SBCumvoB!OW|Vn5|SkVc`VVDmVBzf&Kw^-UDM= zj?W3?egIHQ2MDXU9opIf006QAlc6LWlLK8je+hh4)w%z^JIlSf8MX-l1`x&o5=bTi z!~lb!*?_<#P{QJ{2se|PWMpP;oCQc1tG2YZ)-DgbVC`m?wAN~CVG>OhyP@r)+S3lBd^M5~n>nC`mirk!hFQ_*2W ze~y@m&Wd0~q^qL3B4WjRqcI~LwGx52)oEfqX~s+=Wn#0(NChH2X5>gJ6HiqHyNp=M ztgh(o4#bV#KvdA^sHuo9nUqC1)}&15vujn$)OGKI6S zzP9GdnzeyW^JvBEG-4*b-O3~*=B8-Oe`H#0CA(|8lSXIEtUZ=AdV9@e?PmG8*ZyiX zq6w9pOw(^LjvBQwBhg*Ez2gQml2*yhsz@8brWilV#JWs9a{#NSTpLGMetI9S^hKLmrxZsVG@Ir! zdB*OjG@r?pws!AqnSj;;v<0+Kr_0D+h}NP~1yc#mY=@7;A;!!+>R4@iXfZ9(X%Srk zt8~G*8dVlp&4yEHIg{JGF#{iCe=4sGjW_H1W&1o-O#z*%s0OyOIf+`ef@bXwBi#cd zu3&P2A^1;ap%8hQ#=?WORdl6JD`_>8cjCTEbzmuN*&aEf7l4QrV6UZhrL=~E;HHS1 zsdRPT8{~4EB|WXl?Al~y5}nP-q?J@@V_vB_vMOE6qzXp_2Oes$b=L?+f3A)uqUnv} zbTi`89%`mdI@Qx=+a^1Vq?t&2s6`N{r>!>8HY09&C}gj-g6M&o8;s;)jkd#kYI>6v zA}bv=QyRSrd?n4^m?0uEnSx5!7CE;FC&fIVopuSc?PgkfX+)$rdj*r%+0kN)BNXJJ zeY8&O>}T?i$r6!R6!8#`e;bL;5b_NWQYQ3!5FSx!(>tWo^>i4YbOE;E~MM*G!qed{8f9u9f)J$u16e~>{ z9fyfieW|n=4+ukR^lGN5l1wHYjn#&tDWuNVLa25#?Y9B_IgjY`TV4KikLlmKr`2C+ z)^ykS15NQhvAZGOchrbw%w;ti-Gmc5%~T{A&FRNm%o%Q`TLhoC=97Rty*`;V`Vhcx zgm#UT;Du>Pfp+s*e;`!IG6=qj-mKFJx^1E^r4w|H(Wpvqh4MxzY%x+j5LczQp(NN= zO*Qn{tin-3g^;aAFOGXVy+b(3J0}prwo3m60i;6UQgbTDa@%OdVs<3}kvr+#I-R8V zF!?Hr!`MFiKArBMQ=*WCCUBhtdB0A#)7?yUuM`Z68_X^%e`$wvd!{3|uhIvZHdkK6 zX>IKF;~^#}H^yT?f?9IxP|wHd6Q%Sq z>SwBcMXBsZd)i2Y{-^Ti7En~_)5w45X4=f-X_*iZ?4P0gOX)s(0A(p5mkY~R&fh%r zIeJjQeIEWAe>eI%Oq`TVZ_jyn(PRwbXDF-Fy)?k21Ogg8#1wc%LF&7}ZZ03GG$aDx zQg!}_PG6u$A!8u0|N0FFt2BBHA8{j%%AE4hmjpLe^ktNWRHh@9bMNxXmZI7Et8`94 zKaR|6B?_e7cZnt76-BiPjR(`ZiP=O>~;ax1%yRp}ZCkeV4u`boG7V%Po_s^M?ZD zN9b^^M13xeGc^?Rod1;DAJemf+y6m++gr{_g$;ug(&0tGfuRQyTEK+-?ap9P7(Ab+GSd(%TNibm#n`WuXe z9sy}FuU-%RgYFla`KQ!6)Yuy{)94*uvd#N4e>jO@FiH2wYyd+J1CXj1b4aO`XtQ#C zfrlMJ!}qcnG$ft8Ihqrl9(IeK;$Bt@`&n5!RW8YOE+b9V_<}IHv);p{?9o~0DMF!8 z^wpQ*9TT#_XnVoaQ5ARw(-oJ7qjDJ%LTFq;&K1}@xx9pD@~nKSO4$ zykjeLd3xxyi(+c zRCByH-RI#e;eYI7Ocu^m^wp+^F-wSre>D^G?nt3o#p?tF#)*YvN+%kEZX+fGzWI2> z%vlSg#XOr;Kgyavo{6QSaB;ugdemsVQRfXJ;1=efIxREhPgrSyA2t0(qR$2eWIej_ zNvG}I$OBu@_l7L%NTye13?g%ynm5(&4(&R$d1rl7sQJ+D_U4_3wrp>0_HZ*=e>-mC zO(TtSjcA-}WaG?R>;X0B8GUfgOG*Jy`c~d1Vj~2y=^P(OPz7>}GN5 zxN9VS3%^yE<#rgUR^vO6e-1FYrd#Ze%ERxlivZ>-MpnWcrKXH7b9XYzv|y6koDtG@ z^1FqCF-}cMTlMXYEiJhgf!`-DP#7bWqqXTOjo%LsEWAW(HB%|0+iZ$nw{r3{Rh$O+`4E3t=MOTbAlL3)n*wV!7K0DSHuR;1_suFse{+9>hd<7r5K2HX zb!U1zk@G>Ja({!URiEN}1nytap4x_JcS|B|$^`KlAazO(M5d7B9^lUkoX=sW zvPF`Cy*{t={d`(bkHj*m=uvs&TOWx)g{?*cT0~fH80&jc z2$)P5G5cmNW<`!bUA4`VqC@|W^Aja-%C9lapFH3euT&Y+M)IP;ROo5NLLx`4=w8um zXj|bMI-ln!ZLg45IH(^518DAEhrh|+(n;l~Vbq#f;Xad-!{H-pBk= z8bz0%L?>Y-(SH2UUdPZeca-AJOd^duIi`*HF=nJjD--LKtwAJd!sGnC@~+L_nWyIO zvXXwGcE2!yUt^3L)4+9oN6Lz2(xz?MpUO)`{+Z6tioQcj7zs;cW!YeF_3$tGSE4rm z+C}2uw1#UPf5hK;EI)NX-8)f9t+;JTc@xSQEG`?lmW}iniG&$TNwYNCA1ePoFW>}_ z5ExeZ4;a9c$29(<&d-U0t_yA3U`&@+j=2^tMjzV$3;$K1z6d8yC;J3Zk&Y(A6Z=5= zJO4xH=NZGt`u~R?tNaog8F}Z>7_(C5tHgC)tZy`Xf8cbvAx1md&R*bQonKa{U>@1k z1G9Fjih@*u&gw)h0!a1v616Brr4FL;?UA`;j$}ISsGCMzf=6=hNQ4>P>g8merxF`1Ke%lCnl=qr+jW=Gu9O$bhV3%p#eROpIdS>&M>`)!GkWq;w%FOy))Y@jUFmAOhK z$`=ZXh(6nB&Nm8*mv>NE^=^7n{VGu>lBplgc|*gt{5 zSdvMzOWcXp+7v*0of6ckR9RneV^IjDDjSd_qlu%|5hS2>MFz>qua*mjGUXcOT3y+w ze_%**MMSK5lt%bHjMc={JeoRV;%7Hg-jUnd^XIkc-&()ZA5G+!$Cgh2(j}>-HJXBX z$&DO~fDlnFMi)RlB#k+gemG-1yfXYuI&0pr$4)N34M=F!g6-P zK^UwyHX?~*sS|@_G9FEs{)q6yUQ{+Ie=eE%w;D-*SJI06BUY!`0ip9IJe+SUe{-Ee zdtV}L93LZZhq(Q@2=ASOclfGP{HBXMfJ_-Vf&pTefI+<#S2b;!c!!ykD@gG!Qe`Pc ze36F#Sm`F3au{!=L|VDmm8EG}D$mlqEL|QBWofB*S(a)~sn1jm(p3);;wRKk-n~Oq zA8xJ6Qqur!sSYi#%71Uee{J3!f8L#0+A~1mEFG}_LPKSWr%JM2c1K7M>uer z-j${I4$xf#^noGzP&nuc_?!cD&qMS{rl8yBeuzHHbc)aUT;lyS(_k&J#ZMP?pYT>FJ=WfA~J^e@E`ui2dms zvh;&G0ay;uXKc`Nm-DcEdm>9e5lF{?^fQU%7f8-gP@n1^1>5l;{qioF1K?jvV0S;2 z4$*JJ1N6UV13&|0P=nMye=SSTouZk7mUz$eHa(D|9V`)0B@*flKGzUEANG|T^1d)Y zf6UTfv-EedcOF7#>0hU)EH9|d#)Yr>@NpsNa@A?&norHLa?gb`K3BQsJS-$F*QBUH zO_J3L$lAitsI{r3z}98FAj_AB>$JORhM-r*i?Y0QZ~ySqJ}HV%b(CvD8r69? zXKK0qd7m>J5Jy&dyM>_NeC=8LwL!c-$eZ_;amygL;;eI2EOTe`Y~d*iSpnLm&jz$~>U^T)~olxCvGs5i81_Rl$;gPxF-sN&!LWG(R>% z3(hHtL8pRR$!Y#_IH>2TmH1pCA*G%tc15+Xq-qSIbA^O*ukI0=r}^tcd_ElVK~kTy z8Y+D%%ioq+INU1Y z+Oev&pIqEpeU93Pl)2#pAwbN_DhpbjkI-ddM|Jz4vN)?;F`z6PR0248WtnniR#}7H z(s0P(-Oyg9ti|%xSWvOByq)pYus5qTe@>`Pe=cuxQ~_-B@bclf=lcOJrbnou!#*7^Z5aN`&UoVydKToDVq9s81@_IR~BR=_91t zAM)>dm2Ow*UX|`6dWq^(s#>`Eied7Ke+Fq7jgnRr7GMH=F`mP;sR+=Md7xpmRV9BE_lA&I4Q}#Oe+L~f2Re*v_~jI zA10k#@tDJ)NC8QAYpQOJ;Gg;`OIE>`-WlCty7o|$4e~gGb z0ZxKQLv9oY7XVRSXZ4z^Nz(kM;QKam2t7%p`8H)fFTcgV+(x-=Cb^;Vb1FaYRQZMc zZUZ`H0n5*e|2+r4Qc8x&U4Zj~jq_X{M4D-NjNTa+D=M- zcednUESgQS3}zW!9}%Ytwo*z)e>a5nN@?WZh}Y;7mq<{)?gDuvF>$hBVv)^++>9tu zJZos1oFdj?e+NX{M@}*!a};{%1IFvY@w;I1dvFLESNaqv-Urh@fOve0rqRuu+!to+4ayn?SQ>7)&X>^6tOG}-VROzgyWzN;K+_{FTob^=gyp96SgH+>; zP_6R>t#E#fRyzA>mGc3*()lA=?R=50a{i0zTuf_Ri)pPZK=2Pz^UisA!xyaW`6iVE1Jh4K(}o1mg7 z_(a7Az7R!3MMUcVd`Z@{w1xhD>AC0o&UfD5Ip=%qwfi3eaI9)qxc<^hH?4g~eXkX} z$WDL7>m&8CzWS#6n427Q5|-zMz zGKIO@tsPcN!bC0`4I2+LCnHz`8qU+IhZS7hbj0Qykl|r)Hf* z+)f*43}A(bH^{EjO4^e($di*<7|p`0g`O54q~Z$UhSw9m{%k=MS**fpk#-D?Z+0&- zu|~o4+&onf$BBRySgUa4lo6aDMY}E{3Q1l%8D=CM<)$yujy*q!ldw*9Po{smPDZ!{ zu|B_as=^!^yS_K$CbFJ=w&e{3u_15WX$p&`PYDBW;f1tfF+0PIT*;j5Z z4lgahHYqgpT|3?y!09+c;pjJc$iSJ@HcxoEo1_EIl7#HU*%Qh{*CiRxP8!%m&)I3- z>)L~ApG_@2>S|j_YOonwD$#$1b9u-6EGLmo+h@`bRzFjwda8su4^feJJ}bo(3=M2! z(hbT&f)$~5s#Ic-FGNoO7vOCSW1I!pqZPgRFvgfX3}aiu%48^FLelC*s$io}Zdd=* zPMhj78*r#hX;teQuvV{W?aC&DxJWG8jzsY~7OIGW)I^VJ^$iTt{e6F~6mQ#$4JaHw zWm*?Ykyx8XMuP0oT6-6D$ON$?Z|zQMHD1Kq+(d%uPVF)VnDUi&a?rb^gC`h^q9-(^ ztkDtgz&itYJKjao1Xn~noi?vw`PRubH>D?O-j2SH&ikj zH`3}2l6wqlUA$Ol>P*}$HK<2w)-4L5X*n6Vjh>;%AU-GLpT&Re3`0Jfbt9cODKErV zdvK>@!snT4rO6n?7p0YK$6agyp1Z!Qt-ZZiKff#`%*9veKaLYl-z6K|ovDOt#oG$A zio%*HZrPhDwfEp&(dMg6=xplk&R~bk3DYI?K{I%8FLH8lm}PZ5U}Vt3A>*`NF?%q7 z=kCk*pL{7E&D($R0N0u``tq50h)CLI!QR1YQ$Ky%DPE=^zJ^DH%h&0RqE@G7`}*v( z9p7YIy7hgNQ7i7Xrv|fy%2eFmUu>HNgGxvYd~1rZ>7Mjh0FUC^3gufiZw#+B@m+<+ zal#TF({{D*1#kf0my&kySYD;V{tp7!had97kW0LSLu7vtPl?O+;YSo3OSl=X{6yx8 zefVkd#%eJo9{>4-jm-mTcV~VS`~{uT=4KP|x|HkH^-1Nbky-jZe^UD7bA#!ZgWZ}GbTeuHNx%@W0;G2<-p2f2BFR8Y+({!Dk!Nf|d4 zp^|@*zGr`Xh4vK0U&TGY#NVizn`usQ$}#bGjt!D>X_xwYtf5D}sbPka|AChR?1TR- z*8F@KlN&+z{aeAerR!ivEZO79|KOEMyo~=+wC8rXJK1~qq8JxlN?#_&<_(m`}UVE04Vo5)=)QYwNE8S&ZoV9;bF=PfjXnPr5~^sRiLD1XZn?FO&;-(O$Q0sF1k8a=eYwFF5hF2i2i!aX>9n9Ian^0vn*w*qu4z9^sd5*QzXpR zX_I&&V@hsN%gI|c@|KLBX-{!8ogMV-`1oa2O(i2#`&lI$&7$4f3Bw1kGRuOYRmxTx;P^hj&dE@pI=(EOcpck`-fK411_r8)&uuEv zdW8?Ra!!V{8Rc{5$)gP*3>F|CY#Q>prXinq0DPpc!6AH>ZzR^p^A&_k8l&5`h069~ z{))X=*t8dm!h5keRK6EWhH=C_kiU7T$C3GS=5op;cmK7GqgWR0XdJ@A9F~t_MYOSJ z7)=^onZvQwt^Ak6@xwTA2#az!WjBA;tjM8lH=227K7Wg%Icyw3NA%1goD=QbkBUA1 zIVRTR6b_Z;kPVgRuU`P}jp&5Jd+wR)Rid*r$ zkZ}NyHEF77#L(;vac~X~ig$k>E^_=v#2nR9LuM!tE`%bSr(9V=$vDsA4kj_eikw##vXKv!zx3v@NiSKXpzxV{R}M{!S8eUQ}uHP z%_{DjJ=M=^i(fdnr6NXIt65v=dt0=%@@92Ht$F=x-Nh8(Z?R@}cS(ODs4CfxM#?0> z)h~|VU-#nG9Ftf1a;joCV~3}-&E?@5WzsO!IjREDiU)CVG#V=JiTZ0)u&b;_&F(61 zt;nf)wG};G!|ITnTFA7?sU^FS5l3{28zM%COZC-{_t0lggbX@jR4paluv$iU{+I;& z(GaSrQAbD2vIk*ABb9&tkkLhVSLW0T2J`98J($biB4M;7sqLVLmW{BejNuid<>6k_%jYf0%d=M5%@0+SLG=utRu`+QG`w0}qv5sc1`TgiBN{%Sp3v|K^`v?h zP(M;X)%dgOIf1@weAoGBs}>CdD(t(_cZ`1^Q^1ZBafr9_nU!ie<#QoL& z1%hix96t3Hmfb5+_dlF#V3~o=S1@~wb6>zfxn4M3|9AEO?FNS%1&pzZPfNfWjtavV zV~wAd#=zyIdJS_8T%pwBG4_h8>G_dJWcp{~XK1y|nMi*=u1SucS@ZJ^+&_jZrzLVp zM1`InL)r8+2KH&HUy5NfP(7_RI(cS|#@IC9AR4F1Zl0hsPbRBz7$vLw3Wqt+aPKIF zsJMsx4i#46Hbb?%3O}jDnd3CvDo{ZJTe{IQzEM`XAui8vyo@8p*rChVrwfD}DdoE} zpGpTe6!l}~+k27t7-w)C=qBA(?q5hhUdCbI3etUyirv8$|0)7%J*w0O1XVv~sU&9m z)?tosGv@j(z&u|J)xLhz_%6jE{w~z|FT{L*91Hvo7Wxwi`3JQezaBgM{|8V@2MF_% zQ9_g6fM|bLYwO|0yH)Vib@511@kS5@MNkmDOt;f*GJ^)Bl7ZbJsQ6gS;nH)y#vH%OvXX_=`c_M)UotQ*oK zE%9bsS}$l*aBDk}b$44*TdKKf=tVO1RPNE(*;#)NHny2H^`H4xM{5>rTYBrW#l(buXk=59e`jQxlJQSsn@Oz~ zzVl&zu_6WqCU0a{`dY@Jf8MyEAS+^+{l3PJlZgE$PWy~X{M>(!g_cyhW9W>ml_3+= z(_d(p%PhYwQ^WfzR@s5T{L){8|M2paKw)Y5%7KH45{f807{TZ$hEQ=(!dPBS2@D?c zE1|+ok$+}@E2g-r%7KKkxO9u$1 zr-P4^tb$U1d|T&LKc6M}$~VfxcI?D?G`Du#$dYB}vDm57m+hpjW98{QrX)>zEnnL= zk#tqvt0Zn&x3ZK+3yf`rEh%eDp>u(*ERf3Xvcv;MJIcB--jCA3ItFY7Mqxk;tM)(N zm2CNy4#+P*efN8v?|kR{&;Ojyue|%YYee)uVGFu{_~3&Fwmr}|peIfn>A}WmV`8YW zwJ~9(GGUz%E@d}HhxDXvv^HjjBPl%-FTV&8U)A#{D z2|;Rqzm>}-j62PwA!wDA9c~}a>Vrw6{cKjxWQ=TkZ`yYBWKtoopk=4@GkSYcPY<{6 z9XMqq9EBBxkNH&n`fk6 zU5SKY+q?C&E>F3&e6yK$jBHv@whv)pd(ujOoW_OQcP_Xc!Ygkv)24HqpnHPX(f7I< z&NsPFcSgEw+ei&0vAyN6AWyL6aDbN3GL;mn7PS5Up|?V{DlMn#00n4q75S(>Kz^#? zuayB(X%T;|f;)A&YyHNJ8wCx|d%>bZx5uP2O{<*`EB2&o`yEEj_Ll2xUSDi`7^duh z+hN1$N$NHLUmI*GlO+eY2j~V`$5zk;1+@lkGiLG6@s{*|tIlYmL@U6D&XAe zV9T+Y)(Fr>+QeFH7PNHMoPxln+G){$UD>QI&s3;GrB3$rBGcYsW}%st9SzXU?uDYb zpgsun*9Bv<<7hiy{1&>E_XC+rW-6}G9fB0o-pRKMP&YL%qAuzYbnji#JK7)?WzB&c zTSD8=Y;Vv8EyLE*mZK%Cw4yqYxpN=vjpl{1O#^|;z2WsknncYyV-_f(6iuIcmx<{oGjINfMHc9I#<_m{eXC4^e z%O~lAcD*-N_;@|bSDiwQHqS2HHzBAVImH|rEpcK`F<}YXIuAlXtm)J%kmo=Ty_TAt#(BKYp*x+z55n?d6L`ymWe{Y)S%%UIWmjTm%oTj8orwAIa zDA%qxoyj>6VdyD^EGCDU%DZ^GPo)eY8C4wXR>&#w0oKgeeg=TV7h>KQJl4&SJV&D{ zou&H`Rk_Td?m%}1Q@y<`_DARgtkHudaq>0?N3zygeSo?0Ly(h5TDB3OALXoamOczQ zgYrT+2`ttfpoi(lSjdlmm#$T2lJ18_r08K1TaF$UlxD#!?y=UlZ(^ySu0eg!~-+JnQlaL6L=B zxWLW}yz?TGk7Jc|T^^iQ)nA}b@!BUi*W8ywJr$s*m~30<7ukS+sJtB5^p{+o{$)@; zz|}QiTgjYba9$74r&&T1jfslN!;E_~A&WQ78k#Rcv>_c(8N9JM-JFi2zM6MUN*~om z^fQJwU>Ir5(Nl+!5#7O$p=~JN+&`itQu=eL4O%8^VWTsu zAzVlKESF6pMK)=FE6#(>G_Ex?(?)b>nYxe@26>C7XQ5g#j$tr)TyeWLl(kZz0VkWY znFeiHEw=H+c9dV{P&OIWnr)00HIX|!#iOOdHY&NNIo*|T;E=LmtvGSmv`t4F zah!}DZ7)(}8?$AxP@XQ4+nKRkHj=7OO|W;YA^6I~3FYR01F`oGxz-wBKxsJ}=FznT zE{W@wFKyLq!;ntVOvh$xpD_VIaNw_?PMyZufn3@#QwAzHBg6X?`n6e^en!6fj7rbZ z^C&}H@S$3mhiQ%?sFSjoshg@$W&-;+=ruM)Z)OCo zn>VLU^V^Jn5(_)pkD3{`So^$6SDEz`Bkgd06x1-I%G#OErHrg}JCvKGFYx-`njx=j zi9)}FP{V6yx0N+^CXE!NA~JuM%bPFKOW>ijan31D%#Q7;%=#tzJzo9_GSVEacS6lk zg}w}p5z%{)Cv4|xgIS$lO}bluj4(5P4aKXi4@pK~S%Pl*p*Ral z{t^ALN`FXy!Y88+tW2Fo^?%K%b*4jL?56&!T(F0_k7z66mpV2vaUnJ)m1>o03KK>x!L_}}z>WRC-26Q(IY6`&YwQ!Eq$ zcpU>O4~Ys4qXfny*>Dmg3&l^`aM}+Y=#}w*vlvqLfmPFv`>tLVY?)P5rOnK4KvatwRV)*=vl8xt zrF&Vz6?HJVs4qR?iZT_k66!nFp#!n9i@K9B9JorXRz-tYGjm%^5jOydNKKsS((WUF z4um>u|MVOrY2rpztP^-K*5e)3t=ndzD+j^{@w%yIx->4`cOhX22(ex?vnBA(tN{!Y zxg@HwL$;Ca8ivGx2*UZ8Zh`Z8G$M!nB3$B`IYJc?fhgN>4xq+BMYgY)nDOFSup*w7 z7(~0+sERhR38sPkvsU)>K_nF`2l^9#y#cXBysrv6ZAGrYImM%=R(OM4MT$n z8B!U2u(%>1w!2fepf(IH7~0}CUUNH~IV{g`aPOE~;E662c$n;-@is?=YA_IY0Qji2 z8TRhbY|eH^;mJG2U8>kA?#2ew=E^gh&1Fy>1jH^7B4+x0#Q&BN;UwhT;Vfc*lAppx zdd{DKW=F*O9mbHJOFE_gzFFIG{$8<!`f)vq@)K)5-@KAGdcFzbdYRH0r z*Dm(PA#qq02gMQ4#uRM&EhLnZ-=>L9#6ezD_0w71*341;j*ZiC zD0_i|VR` z_05IOdo&wfY zkwHU6ukt)Y=PRu*llM~1$ONVLT%k-n>J5*RUA>Gx?~nQ#yzH_E;vJPwP)(%4=c%jA z(+9`kZu)p#WyO)JO@#+1=%eu{ zHa`Y~FKX~E+nA?M9)WlaJ$~f84~Y0$E6aH@z9&ylUw}&Cc%GgC+MbOm?3MWOsMizf z_lEm@t^Jje{+eHH@VYK~E)EC%`lQri5*DbVRWLaL!A-J%ZNcx>DTjTGRNuQ)uh1!l zG79Aiw2~x+qDw-dhYD<7Slo5u)H=B9ZSof&y|QdFry$@7H4=A=4lYhY;3MqQCFCvJ zAl=+P^F-;#CD7alKYkR)zk=^7evTBw_K<`LQAbDuIfCW|#_xL1t!u)t@*0MGD7D?=ehG0u<19k@|owbQ^>n7CeQb&Mxk-B@@d^%<`_MXkKY#vuUF%H_%NU(lBYkIpg)yC_GcGpDck=qkBk+*I!4D@BUk7( zUio^QK{QTZZ}5%NH}dqYsJGfX3tErU(h{`3GgkP2b|hZJ)0_A|R`^g~2q(Qc*_x++ zy2L+|U^5k0>6S)YF54BP$+nT2WgDap+1^aI$#y60l5LFk%Ju*qm+f&n34;^q2n%jU z$dYZ29+fTsc1zHFQnoIHl8l2T9GYL0ZoSGr-Qse<)hP`5rlu8om7^Go8W}uOqpvA+ z77!wTdWTjPa4WAAfN?3~9je?>0*4BDg8;{)XshX;OJ1YS5N z^1N74QfT!a_BN7?sA4pUs8>XNa>-iI2ZJiAFsgvhuQQ-T6Y~NXi2ui#LBxi<2-S+# zlX~qWgbMyde|D&>9gZ>BU)3VPk_n)QD$Ue8+f1WPMKDXR| zktSuITkgL^UzUAtx&ICNmh5xOeY`PcpIh{W2X8R+Wy}3mRP5a6mir0unAFpM4a@J* zk^+uWWq36)H=}Un5EJVVQ(iCAbX3$9s1_*^p@!-Zvs8+=0=~+|-CdXwM-|SUepl>_ zZHVY~R8gFexxdmC;Kp`QtVa^-)F=c?sRbTHJ8KGJHZn^*R4#~EX`dV{9b6@)7mI)z zu)uzV>^tXq&zYQ=@4vr(1F(uEhNHv7=jFF*of~_?ZK&(2v7;7M!*hJg=8@&O zn&UMD>4C5X4+SkYd8iqGO=0YXu@kE6JKPRMQT0vD;l5@`kNVo$vaxcHVuSK2zZ2Uw z31O3K%k(Q;({hCfEY~FUKm;M>BE4L?TPkY}aiG2%0Aonjyf`q#Bg+;H(_UceX22V^ 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 Date: Tue, 27 Jan 2026 20:40:20 +0000 Subject: [PATCH 144/178] Update versions following 2.5.8 release (#509) Signed-off-by: Mark S. Lewis --- COMPATIBILITY.md | 3 ++- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- .../fabric-contract-example-gradle-kotlin/build.gradle.kts | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/fabric-contract-example-maven/pom.xml | 2 +- examples/ledger-api/build.gradle | 2 +- fabric-chaincode-docker/build.gradle | 2 +- .../src/contracts/bare-gradle/build.gradle | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/fabric-ledger-api/build.gradle | 2 +- .../src/contracts/fabric-shim-api/build.gradle | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 13 files changed, 14 insertions(+), 13 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 57924e50..b8087a77 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -11,7 +11,8 @@ This table shows the summary of the compatibility of the Java chaincode librarie | v1.4 | 8 | 8 | amd64 | | v2.2 | 11 | 11 | amd64 | | v2.5.0 - v2.5.4 | 11 | 11 | amd64, arm64 | -| v2.5.5+ | 11 | 21 | amd64, arm64 | +| v2.5.5 - v2.5.7 | 11 | 21 | amd64, arm64 | +| v2.5.8+ | 11 | 25 | amd64, arm64 | The Java runtime provided by the chaincode Docker image determines the maximum Java version (and features) that smart contract code can exploit when using the default Java chaincode container. diff --git a/build.gradle b/build.gradle index 7dbadf7e..4244e3da 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { id "com.gradleup.nmcp" version "1.4.3" apply false } -version = '2.5.8' +version = '2.5.9' // If the nightly property is set, then this is the scheduled main // build - and we should publish this to artifactory diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index 8633c287..c40cd07c 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts index 24bbc177..62da1a96 100644 --- a/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts +++ b/examples/fabric-contract-example-gradle-kotlin/build.gradle.kts @@ -14,7 +14,7 @@ plugins { version = "0.0.1" dependencies { - implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7") + implementation("org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8") implementation("org.json:json:20250517") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index 39ff9593..cc7c603c 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index fc1d00f1..81462ff9 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.7 + 2.5.8 1.5.26 diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index 6a9bde42..b6043754 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -13,7 +13,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.7' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/fabric-chaincode-docker/build.gradle b/fabric-chaincode-docker/build.gradle index db3a965b..843ae2ce 100644 --- a/fabric-chaincode-docker/build.gradle +++ b/fabric-chaincode-docker/build.gradle @@ -59,5 +59,5 @@ tasks.register('copyAllDeps', Copy) { tasks.register('buildImage', DockerBuildImage) { dependsOn copyAllDeps inputDir = project.file('Dockerfile').parentFile - images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:2.5.8'] + images = ['hyperledger/fabric-javaenv', 'hyperledger/fabric-javaenv:2.5', 'hyperledger/fabric-javaenv:2.5.9'] } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle index b1bd6a40..43c964fb 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/bare-gradle/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.9' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index b6962bc2..255bf44e 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.8 + 2.5.9 diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle index c31118ce..c5cc4328 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-ledger-api/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.9' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' } diff --git a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle index bb0eafce..830b32c7 100644 --- a/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle +++ b/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/build.gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.8' + implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.9' implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' implementation 'commons-logging:commons-logging:1.3.5' implementation 'com.google.code.gson:gson:2.13.2' diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index 1b494496..a7b72afb 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -12,7 +12,7 @@ UTF-8 - 2.5.8 + 2.5.9 From b36b409554ddca8f59cd47656435270481c465df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:18:53 +0000 Subject: [PATCH 145/178] Bump gradle/actions from 5.0.0 to 5.0.1 (#510) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d6716ae..cf9d7f26 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Publish to Maven Central run: | ./gradlew publishAggregationToCentralPortal @@ -75,7 +75,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 70db6ada..a10b766f 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -29,6 +29,6 @@ jobs: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 java-version: 21 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a828813f..5d81d08b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 86da4ea97495b945cc406969ab02cbbca8287d92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:20:33 +0000 Subject: [PATCH 146/178] Bump docker/login-action from 3.6.0 to 3.7.0 (#511) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf9d7f26..cb194128 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,13 +81,13 @@ jobs: - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -136,7 +136,7 @@ jobs: pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} From 19d061fdd0a2ae8622ed13a368f3490df57e891c Mon Sep 17 00:00:00 2001 From: Muthu Date: Thu, 29 Jan 2026 22:37:50 +0530 Subject: [PATCH 147/178] Upgrade the assertj-core to 3.27.7 (#512) Signed-off-by: Muthu Sundaravadivel Co-authored-by: Muthu Sundaravadivel --- build.gradle | 2 +- examples/fabric-contract-example-as-service/build.gradle | 2 +- examples/fabric-contract-example-gradle/build.gradle | 2 +- examples/ledger-api/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 4244e3da..c12b354e 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ subprojects { testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' - testImplementation 'org.assertj:assertj-core:3.27.6' + testImplementation 'org.assertj:assertj-core:3.27.7' testImplementation 'org.mockito:mockito-core:5.21.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' diff --git a/examples/fabric-contract-example-as-service/build.gradle b/examples/fabric-contract-example-as-service/build.gradle index c40cd07c..e81439ac 100644 --- a/examples/fabric-contract-example-as-service/build.gradle +++ b/examples/fabric-contract-example-as-service/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.assertj:assertj-core:3.27.6' + testImplementation 'org.assertj:assertj-core:3.27.7' testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/fabric-contract-example-gradle/build.gradle b/examples/fabric-contract-example-gradle/build.gradle index cc7c603c..45dfd56b 100644 --- a/examples/fabric-contract-example-gradle/build.gradle +++ b/examples/fabric-contract-example-gradle/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.assertj:assertj-core:3.27.6' + testImplementation 'org.assertj:assertj-core:3.27.7' testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/examples/ledger-api/build.gradle b/examples/ledger-api/build.gradle index b6043754..ca402576 100644 --- a/examples/ledger-api/build.gradle +++ b/examples/ledger-api/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.json:json:20251224' testImplementation platform('org.junit:junit-bom:6.0.2') testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.assertj:assertj-core:3.27.6' + testImplementation 'org.assertj:assertj-core:3.27.7' testImplementation 'org.mockito:mockito-core:5.21.0' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } From 10dae56ba9405fea362dd22da654feb1f050df12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:11:48 +0000 Subject: [PATCH 148/178] Bump maven-compiler-plugin from 3.14.1 to 3.15.0 (#513) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 4 ++-- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 81462ff9..d98ba362 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.8 - 1.5.26 + 1.5.27 2.0.17 @@ -110,7 +110,7 @@ maven-compiler-plugin - 3.14.1 + 3.15.0 ${java.version} diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 255bf44e..4f078711 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -43,7 +43,7 @@ maven-compiler-plugin - 3.14.1 + 3.15.0 ${java.version} diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index a7b72afb..ee663a20 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -47,7 +47,7 @@ maven-compiler-plugin - 3.14.1 + 3.15.0 ${java.version} From 2c08ca0f92b139d8225b0bd4b42175c94c0dac0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:36:05 +0000 Subject: [PATCH 149/178] Bump ch.qos.logback:logback-classic from 1.5.27 to 1.5.28 (#514) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index d98ba362..ce7af9e1 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.8 - 1.5.27 + 1.5.28 2.0.17 From ebc6b21962cf4e1672baf1886b0dd5697c3106eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:00:32 +0000 Subject: [PATCH 150/178] Bump ch.qos.logback:logback-classic from 1.5.28 to 1.5.29 (#515) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index ce7af9e1..509bad29 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.8 - 1.5.28 + 1.5.29 2.0.17 From 4a4e2d0f20e8fafd16a41368c7f6e2caa4b35db0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 09:16:18 +0000 Subject: [PATCH 151/178] Bump docker/build-push-action from 6.18.0 to 6.19.1 (#516) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb194128..9ac14bfa 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build image id: build - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + uses: docker/build-push-action@601a80b39c9405e50806ae38af30926f9d957c47 # v6.19.1 with: file: fabric-chaincode-docker/Dockerfile context: fabric-chaincode-docker From 22c354416f1744f49053c2c3d1f5ccaebfb076d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:05:25 +0000 Subject: [PATCH 152/178] Bump docker/build-push-action from 6.19.1 to 6.19.2 (#517) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ac14bfa..a129cf9a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build image id: build - uses: docker/build-push-action@601a80b39c9405e50806ae38af30926f9d957c47 # v6.19.1 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: file: fabric-chaincode-docker/Dockerfile context: fabric-chaincode-docker From e45d66ef7250bf403acf67a017b1cda09728e374 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:28:30 +0000 Subject: [PATCH 153/178] Bump example Maven junit and logback dependencies (#518) - Updates `org.junit:junit-bom` from 6.0.2 to 6.0.3 - Updates `ch.qos.logback:logback-classic` from 1.5.29 to 1.5.31 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 509bad29..651faadf 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.8 - 1.5.29 + 1.5.31 2.0.17 @@ -32,7 +32,7 @@ org.junit junit-bom - 6.0.2 + 6.0.3 pom import From bda64e8d496c67fab3cb5f771da83f84c78b3a37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:54:26 +0000 Subject: [PATCH 154/178] Bump ch.qos.logback:logback-classic from 1.5.31 to 1.5.32 (#519) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 651faadf..2b5f4cb9 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -15,7 +15,7 @@ 2.5.8 - 1.5.31 + 1.5.32 2.0.17 From be590d939b6eacc11b2eaf74a30ba3595db043f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 09:21:19 +0000 Subject: [PATCH 155/178] Bump maven-surefire-plugin from 3.5.4 to 3.5.5 (#520) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 2b5f4cb9..23e1636a 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -106,7 +106,7 @@ maven-surefire-plugin - 3.5.4 + 3.5.5 maven-compiler-plugin From d082c386a61828adbfb75498b66fc504f7ae5323 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 09:10:11 +0000 Subject: [PATCH 156/178] Bump gradle/actions from 5.0.1 to 5.0.2 (#521) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a129cf9a..01f9b6d0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Publish to Maven Central run: | ./gradlew publishAggregationToCentralPortal @@ -75,7 +75,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index a10b766f..32e1116d 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -29,6 +29,6 @@ jobs: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 java-version: 21 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d81d08b..fcb9d719 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 + - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 07d8a410ab45a90a9b71b987352df0d67399d368 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Feb 2026 09:12:00 +0000 Subject: [PATCH 157/178] Bump actions/setup-go from 6.2.0 to 6.3.0 (#522) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 32e1116d..43b839a1 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -20,7 +20,7 @@ jobs: with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier - - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version: stable cache: false From 0d60cee4de7f158b8a61b75c6d02a6e0c0a4b26a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 08:42:59 +0000 Subject: [PATCH 158/178] Bump actions/download-artifact from 7.0.0 to 8.0.0 (#524) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01f9b6d0..03c2a33d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,7 +130,7 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: path: ${{ runner.temp }}/digests pattern: digest-* From da4e34bc8e0a34fb3cbf14b5612bdd731fd2da16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 08:43:27 +0000 Subject: [PATCH 159/178] Bump actions/upload-artifact from 6.0.0 to 7.0.0 (#523) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03c2a33d..d6b8f8a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,7 +109,7 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: digest-${{ matrix.arch.platform }} path: ${{ runner.temp }}/digests/* From 9617b30ae891a7bc905295609e1aa247e2fca0cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 09:55:26 +0000 Subject: [PATCH 160/178] Bump org.mockito:mockito-core from 5.21.0 to 5.22.0 (#525) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 23e1636a..f4470629 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -92,7 +92,7 @@ org.mockito mockito-core - 5.21.0 + 5.22.0 org.json From dce3b2e16c5b4bb9efa1ef663d185a6208a82b4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:09:08 +0000 Subject: [PATCH 161/178] Bump actions/setup-node from 6.2.0 to 6.3.0 (#526) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fcb9d719..b4361ea4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 From 77ca9b81552fa0b5d875cacbd391f02b3eafd1dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 09:12:51 +0000 Subject: [PATCH 162/178] Bump docker/setup-buildx-action from 3.12.0 to 4.0.0 (#527) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d6b8f8a2..5379bc07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,7 +93,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build image id: build uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 @@ -151,7 +151,7 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}.{{patch}} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Create and push manifest list working-directory: ${{ runner.temp }}/digests run: | From ae2289bfaa3cc03854034b62be186f674663c6a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 09:14:13 +0000 Subject: [PATCH 163/178] Bump docker/login-action from 3.7.0 to 4.0.0 (#528) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5379bc07..317256c8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,13 +81,13 @@ jobs: - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -136,7 +136,7 @@ jobs: pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} From 42a00bea41c5e330df7bff0e0808d6929318440a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:31:28 +0000 Subject: [PATCH 164/178] Bump maven-shade-plugin from 3.6.1 to 3.6.2 (#531) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- .../src/contracts/bare-maven/pom.xml | 2 +- .../src/contracts/wrapper-maven/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index f4470629..16d0e89a 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -118,7 +118,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + 3.6.2 package diff --git a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml index 4f078711..4fcc03ad 100644 --- a/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/bare-maven/pom.xml @@ -51,7 +51,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + 3.6.2 package diff --git a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml index ee663a20..bf64b273 100644 --- a/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml +++ b/fabric-chaincode-integration-test/src/contracts/wrapper-maven/pom.xml @@ -55,7 +55,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.6.1 + 3.6.2 package From a0b0611b60d95393767b0ca692fa5ea23efd2b70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:32:09 +0000 Subject: [PATCH 165/178] Bump docker/build-push-action from 6.19.2 to 7.0.0 (#530) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 317256c8..65b33070 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build image id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: file: fabric-chaincode-docker/Dockerfile context: fabric-chaincode-docker From 447303443aa70bfefc13a673e527d62dd17c1d08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 11:32:39 +0000 Subject: [PATCH 166/178] Bump docker/metadata-action from 5.10.0 to 6.0.0 (#529) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 65b33070..0ff33fe9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -143,7 +143,7 @@ jobs: password: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_TOKEN || secrets.GITHUB_TOKEN }} - name: Docker metadata id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 + uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 with: images: ${{ matrix.registry }}/${{ env.IMAGE_NAME }} tags: | From d97f466cfaa336ec87a31601c066e773204ceadf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:50:18 +0000 Subject: [PATCH 167/178] Bump org.mockito:mockito-core from 5.22.0 to 5.23.0 (#533) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/fabric-contract-example-maven/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fabric-contract-example-maven/pom.xml b/examples/fabric-contract-example-maven/pom.xml index 16d0e89a..b7657d2a 100644 --- a/examples/fabric-contract-example-maven/pom.xml +++ b/examples/fabric-contract-example-maven/pom.xml @@ -92,7 +92,7 @@ org.mockito mockito-core - 5.22.0 + 5.23.0 org.json From 115d8dae90864372afae94a1442739496012ba7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:31:33 +0000 Subject: [PATCH 168/178] Bump actions/download-artifact from 8.0.0 to 8.0.1 (#532) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0ff33fe9..df049c3c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,7 +130,7 @@ jobs: - ghcr.io steps: - name: Download digests - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: ${{ runner.temp }}/digests pattern: digest-* From 8aa860c476258227191d777d90fd2bdffa548659 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:10:49 +0000 Subject: [PATCH 169/178] Bump gradle/actions from 5.0.2 to 6.0.0 (#534) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df049c3c..8de570f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Publish to Maven Central run: | ./gradlew publishAggregationToCentralPortal @@ -75,7 +75,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 43b839a1..9df03d48 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -29,6 +29,6 @@ jobs: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 java-version: 21 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b4361ea4..1d3dfe70 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 + - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From 61fead260d787d3265292c402cb357ad068864bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:21:10 +0000 Subject: [PATCH 170/178] Bump gradle/actions from 6.0.0 to 6.0.1 (#535) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8de570f9..8c37ca19 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Publish to Maven Central run: | ./gradlew publishAggregationToCentralPortal @@ -75,7 +75,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 9df03d48..9732cf86 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -29,6 +29,6 @@ jobs: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 java-version: 21 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1d3dfe70..83af71c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@0f4528296b4bc09e8ae0fc7be30185a4ab435545 # v6.0.0 + - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From b21865eb68b7e47c8478e4b4d7bc3375d54badf8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 18:04:03 +0100 Subject: [PATCH 171/178] Bump actions/setup-go from 6.3.0 to 6.4.0 (#536) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index 9732cf86..d9a368b0 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -20,7 +20,7 @@ jobs: with: ref: ${{ inputs.ref }} # Go needed for scanning of v2.5.5 and earlier - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: stable cache: false From 4af95ee354e91d97c8b810aebe8cbaeebf919c3a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 12:05:54 +0200 Subject: [PATCH 172/178] Bump docker/login-action from 4.0.0 to 4.1.0 (#537) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c37ca19..9f4939c7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,13 +81,13 @@ jobs: - name: Get commit timestamp run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}" - name: Login to GitHub Container Registry - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: docker.io username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -136,7 +136,7 @@ jobs: pattern: digest-* merge-multiple: true - name: Login to ${{ matrix.registry }} - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ${{ matrix.registry }} username: ${{ matrix.registry == 'docker.io' && secrets.DOCKERHUB_USERNAME || github.actor }} From 751b300d57f1de720fdcf3a6abcc24a30445cfe7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 20:19:16 +0100 Subject: [PATCH 173/178] Bump gradle/actions from 6.0.1 to 6.1.0 (#538) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 6 +++--- .github/workflows/scan.yml | 2 +- .github/workflows/test.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f4939c7..bd05f51d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Publish to GitHub Packages run: | ./gradlew publishAllPublicationsToGitHubRepository @@ -45,7 +45,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Publish to Maven Central run: | ./gradlew publishAggregationToCentralPortal @@ -75,7 +75,7 @@ jobs: with: distribution: "temurin" java-version: 25 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build the dependencies needed for the image run: ./gradlew :fabric-chaincode-docker:copyAllDeps - name: Get commit timestamp diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index d9a368b0..c7065530 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -29,6 +29,6 @@ jobs: distribution: temurin # Releases v2.5.7 and earlier do not support Java 25 java-version: 21 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Scan run: make scan diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 83af71c4..9258ab64 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build and Unit test run: ./gradlew :fabric-chaincode-shim:build @@ -40,7 +40,7 @@ jobs: - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "lts/*" - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Populate chaincode with latest java-version run: | ./gradlew -I $GITHUB_WORKSPACE/fabric-chaincode-integration-test/chaincodebootstrap.gradle -PchaincodeRepoDir=$GITHUB_WORKSPACE/fabric-chaincode-integration-test/src/contracts/fabric-shim-api/repository publishShimPublicationToFabricRepository @@ -73,6 +73,6 @@ jobs: with: distribution: temurin java-version: 25 - - uses: gradle/actions/setup-gradle@39e147cb9de83bb9910b8ef8bd7fff0ee20fcd6f # v6.0.1 + - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build Docker image run: ./gradlew :fabric-chaincode-docker:buildImage From c8d97040e22c08c2b662adcaacdc20282429587a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:37:33 +0100 Subject: [PATCH 174/178] Bump docker/build-push-action from 7.0.0 to 7.1.0 (#539) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd05f51d..d9c98aef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,7 +96,7 @@ jobs: uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Build image id: build - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: file: fabric-chaincode-docker/Dockerfile context: fabric-chaincode-docker From f1843e47f4f0e474cf8b77c1692bfdb93de3513a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:38:02 +0100 Subject: [PATCH 175/178] Bump actions/upload-artifact from 7.0.0 to 7.0.1 (#540) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9c98aef..0c2d47dc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,7 +109,7 @@ jobs: digest="${{ steps.build.outputs.digest }}" touch "${{ runner.temp }}/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: digest-${{ matrix.arch.platform }} path: ${{ runner.temp }}/digests/* From 25ee3616839eb621f97027f6de1c60ec044a8f95 Mon Sep 17 00:00:00 2001 From: Sai Asish Y Date: Fri, 17 Apr 2026 11:22:38 -0700 Subject: [PATCH 176/178] ChaincodeBase: fix 'occured' -> 'occurred' in error log messages (#541) Two log messages in ChaincodeBase.java (lines 205, 260) read 'An error occured on the chaincode stream'. Fixed to 'occurred'. String-literal-only change. Signed-off-by: SAY-5 Co-authored-by: SAY-5 --- .../main/java/org/hyperledger/fabric/shim/ChaincodeBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java index a90e6bda..b0831498 100644 --- a/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java +++ b/fabric-chaincode-shim/src/main/java/org/hyperledger/fabric/shim/ChaincodeBase.java @@ -202,7 +202,7 @@ public void onNext(final ChaincodeMessage chaincodeMessage) { @Override public void onError(final Throwable t) { LOGGER.severe( - () -> "An error occured on the chaincode stream. Shutting down the chaincode stream." + () -> "An error occurred on the chaincode stream. Shutting down the chaincode stream." + Logging.formatError(t)); chaincodeSupportClient.shutdown(itm); @@ -257,7 +257,7 @@ public void onNext(final ChaincodeMessage chaincodeMessage) { @Override public void onError(final Throwable t) { - LOGGER.severe(() -> "An error occured on the chaincode stream. Shutting down the chaincode stream." + LOGGER.severe(() -> "An error occurred on the chaincode stream. Shutting down the chaincode stream." + Logging.formatError(t)); chaincodeSupportClient.shutdown(itm); From 583dd1477427dee3db56f872f2b08dd93ed29cbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 09:01:29 +0000 Subject: [PATCH 177/178] Bump actions/setup-node from 6.3.0 to 6.4.0 (#542) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9258ab64..f03ba23c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: distribution: temurin java-version: 25 - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "lts/*" - uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 From 5cd4f4588b5808d72c6561e4220a0ad6a85c19a9 Mon Sep 17 00:00:00 2001 From: "Mark S. Lewis" Date: Mon, 20 Apr 2026 13:19:54 +0100 Subject: [PATCH 178/178] Update dependencies (#543) Signed-off-by: Mark S. Lewis --- build.gradle | 14 +++++++------- fabric-chaincode-docker/Dockerfile | 4 ++-- fabric-chaincode-shim/build.gradle | 17 +++++++++-------- gradle/wrapper/gradle-wrapper.jar | Bin 46175 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index c12b354e..55c913bd 100644 --- a/build.gradle +++ b/build.gradle @@ -5,10 +5,10 @@ */ plugins { - id "com.github.ben-manes.versions" version "0.53.0" - id "com.diffplug.spotless" version "8.1.0" - id "com.gradleup.nmcp.aggregation" version "1.4.3" - id "com.gradleup.nmcp" version "1.4.3" apply false + id "com.github.ben-manes.versions" version "0.54.0" + id "com.diffplug.spotless" version "8.4.0" + id "com.gradleup.nmcp.aggregation" version "1.4.4" + id "com.gradleup.nmcp" version "1.4.4" apply false } version = '2.5.9' @@ -67,13 +67,13 @@ subprojects { dependencies { implementation 'commons-cli:commons-cli:1.11.0' - implementation 'commons-logging:commons-logging:1.3.5' + implementation 'commons-logging:commons-logging:1.3.6' - testImplementation platform('org.junit:junit-bom:6.0.2') + testImplementation platform('org.junit:junit-bom:6.0.3') testImplementation 'org.junit.jupiter:junit-jupiter' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testImplementation 'org.assertj:assertj-core:3.27.7' - testImplementation 'org.mockito:mockito-core:5.21.0' + testImplementation 'org.mockito:mockito-core:5.23.0' testImplementation 'uk.org.webcompere:system-stubs-jupiter:2.1.8' testImplementation 'org.hamcrest:hamcrest-library:3.0' diff --git a/fabric-chaincode-docker/Dockerfile b/fabric-chaincode-docker/Dockerfile index db4d4bd5..b3fc3da8 100644 --- a/fabric-chaincode-docker/Dockerfile +++ b/fabric-chaincode-docker/Dockerfile @@ -9,8 +9,8 @@ RUN curl -s "https://get.sdkman.io" | bash SHELL ["/bin/bash", "-c"] RUN . /root/.sdkman/bin/sdkman-init.sh \ - && sdk install gradle 9.3.0 \ - && sdk install maven 3.9.12 + && sdk install gradle 9.4.1 \ + && sdk install maven 3.9.15 FROM ${JAVA_IMAGE} AS dependencies diff --git a/fabric-chaincode-shim/build.gradle b/fabric-chaincode-shim/build.gradle index d5f39a14..ecfe81f5 100644 --- a/fabric-chaincode-shim/build.gradle +++ b/fabric-chaincode-shim/build.gradle @@ -35,13 +35,14 @@ dependencies { because('CVE-2025-48924') } } - implementation platform('com.google.protobuf:protobuf-bom:4.33.4') - implementation platform('io.grpc:grpc-bom:1.78.0') - implementation platform('io.opentelemetry:opentelemetry-bom:1.58.0') + implementation platform('com.google.protobuf:protobuf-bom:4.34.1') + implementation platform('io.grpc:grpc-bom:1.80.0') + implementation platform('io.opentelemetry:opentelemetry-bom:1.61.0') + implementation platform("org.bouncycastle:bc-jdk18on-bom:1.84") implementation 'org.hyperledger.fabric:fabric-protos:0.3.7' - implementation 'org.bouncycastle:bcpkix-jdk18on:1.83' - implementation 'org.bouncycastle:bcprov-jdk18on:1.83' + implementation 'org.bouncycastle:bcpkix-jdk18on' + implementation 'org.bouncycastle:bcprov-jdk18on' implementation 'io.github.classgraph:classgraph:4.8.184' implementation 'com.github.erosb:everit-json-schema:1.14.6' implementation 'org.json:json:20251224' @@ -53,14 +54,14 @@ dependencies { testImplementation 'io.grpc:grpc-inprocess' implementation 'io.opentelemetry:opentelemetry-api' - implementation 'io.opentelemetry.proto:opentelemetry-proto:1.9.0-alpha' + implementation 'io.opentelemetry.proto:opentelemetry-proto:1.10.0-alpha' implementation 'io.opentelemetry:opentelemetry-sdk' implementation 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure' implementation 'io.opentelemetry:opentelemetry-sdk-trace' implementation 'io.opentelemetry:opentelemetry-exporter-otlp' implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators' - implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.37.0' - implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.24.0-alpha' + implementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.40.0' + implementation 'io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.26.1-alpha' } sourceSets { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 61285a659d17295f1de7c53e24fdf13ad755c379..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 39855 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