diff --git a/.github/workflows/build-timestamped-master.yml b/.github/workflows/build-timestamped-master.yml index 982802a..b4b8f36 100644 --- a/.github/workflows/build-timestamped-master.yml +++ b/.github/workflows/build-timestamped-master.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - java21 paths-ignore: - '*.md' - 'docs/**' @@ -19,11 +20,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: '11' + distribution: 'temurin' + java-version: '21' - name: Change to Timestamped Version run: | diff --git a/.github/workflows/build-with-bal-test-graalvm.yml b/.github/workflows/build-with-bal-test-graalvm.yml index eda657d..c927802 100644 --- a/.github/workflows/build-with-bal-test-graalvm.yml +++ b/.github/workflows/build-with-bal-test-graalvm.yml @@ -30,7 +30,7 @@ jobs: call_stdlib_workflow: name: Run StdLib Workflow if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }} - uses: ballerina-platform/ballerina-standard-library/.github/workflows/build-with-bal-test-graalvm-template.yml@main + uses: ballerina-platform/ballerina-standard-library/.github/workflows/build-with-bal-test-graalvm-template.yml@java21 with: lang_tag: ${{ inputs.lang_tag }} lang_version: ${{ inputs.lang_version }} diff --git a/.github/workflows/central-publish.yml b/.github/workflows/central-publish.yml index 6eeb286..0e22d9b 100644 --- a/.github/workflows/central-publish.yml +++ b/.github/workflows/central-publish.yml @@ -11,11 +11,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: '11' + distribution: 'temurin' + java-version: '21' - name: Build with Gradle env: diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index cf1084c..a46352f 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -14,11 +14,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: '11' + distribution: 'temurin' + java-version: '21' - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 2a17548..4e1fd82 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -10,11 +10,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v1 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: '11' + distribution: 'temurin' + java-version: '21' - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -35,11 +35,11 @@ jobs: - name: Checkout Repository uses: actions/checkout@v1 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: '11' + distribution: 'temurin' + java-version: '21' - name: Build the Project env: diff --git a/.github/workflows/trivy-scan.yml b/.github/workflows/trivy-scan.yml index 9c187dd..aba3079 100644 --- a/.github/workflows/trivy-scan.yml +++ b/.github/workflows/trivy-scan.yml @@ -11,11 +11,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v2 with: - distribution: 'adopt' - java-version: 11 + distribution: 'temurin' + java-version: 21 - name: Grant execute permission for gradlew run: chmod +x gradlew diff --git a/README.md b/README.md index 8902fe5..8b128c1 100644 --- a/README.md +++ b/README.md @@ -144,9 +144,9 @@ public function main() returns error? { ### Set up the prerequisites -1. Download and install Java SE Development Kit (JDK) version 11 (from one of the following locations). +1. Download and install Java SE Development Kit (JDK) version 21 (from one of the following locations). - - [Oracle](https://www.oracle.com/java/technologies/javase-jdk11-downloads.html) + - [Oracle](https://www.oracle.com/java/technologies/javase-jdk21-downloads.html) - [OpenJDK](https://adoptopenjdk.net/) diff --git a/ballerina/Ballerina.toml b/ballerina/Ballerina.toml index 8d29aa3..b9a5102 100644 --- a/ballerina/Ballerina.toml +++ b/ballerina/Ballerina.toml @@ -6,8 +6,8 @@ authors = ["xlibb"] keywords = ["pubsub"] repository = "https://github.com/xlibb/module-pubsub" license = ["Apache-2.0"] -distribution = "2201.4.0" +distribution = "2201.10.0-20241025-103700-5c9e6a27" icon = "icon.png" -[[platform.java11.dependency]] +[[platform.java21.dependency]] path = "../native/build/libs/pubsub-native-1.4.1-SNAPSHOT.jar" diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 7601fa8..68a791e 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,6 +5,7 @@ [ballerina] dependencies-toml-version = "2" +distribution-version = "2201.10.0-20241025-103700-5c9e6a27" [[package]] org = "ballerina" @@ -14,6 +15,41 @@ modules = [ {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.__internal" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.object"} +] + +[[package]] +org = "ballerina" +name = "lang.array" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.__internal"} +] + +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "lang.object" +version = "0.0.0" +scope = "testOnly" + [[package]] org = "ballerina" name = "lang.runtime" @@ -31,7 +67,9 @@ name = "test" version = "0.0.0" scope = "testOnly" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.array"}, + {org = "ballerina", name = "lang.error"} ] modules = [ {org = "ballerina", packageName = "test", moduleName = "test"} @@ -40,7 +78,7 @@ modules = [ [[package]] org = "xlibb" name = "pipe" -version = "1.4.1" +version = "1.5.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] diff --git a/ballerina/tests/errors_test.bal b/ballerina/tests/errors_test.bal index 07f8df8..a179f39 100644 --- a/ballerina/tests/errors_test.bal +++ b/ballerina/tests/errors_test.bal @@ -139,7 +139,7 @@ function testClosingPubSubWithClosedStream() returns error? { test:assertEquals(pubsubError.message(), expectedMessage); error? cause = pubsubError.cause(); test:assertTrue(cause is error); - expectedMessage = "Closing of a closed pipe is not allowed"; + expectedMessage = "Attempting to close an already closed pipe"; test:assertEquals((cause).message(), expectedMessage); } diff --git a/ballerina/tests/pubsub_test.bal b/ballerina/tests/pubsub_test.bal index 2f80d79..43fcfbd 100644 --- a/ballerina/tests/pubsub_test.bal +++ b/ballerina/tests/pubsub_test.bal @@ -41,10 +41,10 @@ function testGracefulShutdown() returns error? { stream subscribe = check pubsub.subscribe("topic"); check pubsub.gracefulShutdown(); record {|string value;|}|error? msg = subscribe.next(); - if msg !is () { - test:assertFail(string `Expected "()", received ${(typeof msg).toString()}`); + test:assertTrue(msg is error); + if msg is error { + test:assertEquals(msg.message(), "Events must not be consumed from a closed pipe"); } - string expectedValue = "Users cannot subscribe to a closed PubSub"; stream|Error new_subscriber = pubsub.subscribe("topic"); test:assertTrue(new_subscriber is Error); @@ -64,10 +64,10 @@ function testForceShutdown() returns error? { stream subscribe = check pubsub.subscribe("topic"); check pubsub.forceShutdown(); record {|string value;|}|error? msg = subscribe.next(); - if msg !is () { - test:assertFail(string `Expected "()", received ${(typeof msg).toString()}`); + test:assertTrue(msg is error); + if msg is error { + test:assertEquals(msg.message(), "Events must not be consumed from a closed pipe"); } - string expectedValue = "Users cannot subscribe to a closed PubSub"; stream|Error new_subscriber = pubsub.subscribe("topic"); test:assertTrue(new_subscriber is Error); diff --git a/build-config/resources/Ballerina.toml b/build-config/resources/Ballerina.toml index deea5c9..325e61f 100644 --- a/build-config/resources/Ballerina.toml +++ b/build-config/resources/Ballerina.toml @@ -6,8 +6,8 @@ authors = ["xlibb"] keywords = ["pubsub"] repository = "https://github.com/xlibb/module-pubsub" license = ["Apache-2.0"] -distribution = "2201.4.0" +distribution = "2201.10.0-20241025-103700-5c9e6a27" icon = "icon.png" -[[platform.java11.dependency]] +[[platform.java21.dependency]] path = "../native/build/libs/pubsub-native-@project.version@.jar" diff --git a/gradle.properties b/gradle.properties index b7d62b4..7d705bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ org.gradle.caching=true group=io.xlibb version=1.4.1-SNAPSHOT -ballerinaLangVersion=2201.4.0 +ballerinaLangVersion=2201.10.0-20241025-103700-5c9e6a27 checkstylePluginVersion=8.18 -spotbugsPluginVersion=4.5.1 +spotbugsPluginVersion=6.0.18 shadowJarPluginVersion=5.2.0 downloadPluginVersion=4.0.4 releasePluginVersion=2.6.0 @@ -13,14 +13,14 @@ ballerinaGradlePluginVersion=1.1.0 #stdlib dependencies # Level 01 -stdlibIoVersion=1.4.0 -stdlibTimeVersion=2.2.3 +stdlibIoVersion=1.6.2-20240928-084100-656404f +stdlibTimeVersion=2.5.1-20240930-120200-e59222b # Level 02 -stdlibLogVersion=2.6.0 +stdlibLogVersion=2.10.1-20240930-154200-5ab2aa4 # Ballerinax Observer -observeVersion=1.0.6 -observeInternalVersion=1.0.5 +observeVersion=1.3.1-20241007-161000-645452d +observeInternalVersion=1.3.1-20241015-172900-cdc3cb3 -pipeVersion=1.4.1 +pipeVersion=1.5.0-20241104-194300-4c6aa2b diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e6e589..1e2fbf0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/native/build.gradle b/native/build.gradle index 706a6e8..6e1553a 100644 --- a/native/build.gradle +++ b/native/build.gradle @@ -43,8 +43,11 @@ checkstyle { checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") spotbugsMain { - effort "max" - reportLevel "low" + def classLoader = plugins["com.github.spotbugs"].class.classLoader + def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") + def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") + effort = SpotBugsEffort.MAX + reportLevel = SpotBugsConfidence.LOW reportsDir = file("$project.buildDir/reports/spotbugs") reports { html.enabled true diff --git a/native/src/main/java/io/xlibb/pubsub/MethodCallback.java b/native/src/main/java/io/xlibb/pubsub/MethodCallback.java index 8ed7c72..7b6c213 100644 --- a/native/src/main/java/io/xlibb/pubsub/MethodCallback.java +++ b/native/src/main/java/io/xlibb/pubsub/MethodCallback.java @@ -1,22 +1,21 @@ package io.xlibb.pubsub; -import io.ballerina.runtime.api.Future; -import io.ballerina.runtime.api.async.Callback; import io.ballerina.runtime.api.values.BError; +import java.util.concurrent.CompletableFuture; + import static io.xlibb.pubsub.utils.Utils.createError; /** * Callback class for running Ballerina methods in PubSub Native code. */ -public class MethodCallback implements Callback { - private final Future future; +public class MethodCallback { + private final CompletableFuture future; - protected MethodCallback(Future future) { + protected MethodCallback(CompletableFuture future) { this.future = future; } - @Override public void notifySuccess(Object o) { if (o instanceof BError) { this.notifyFailure((BError) o); @@ -25,7 +24,6 @@ public void notifySuccess(Object o) { } } - @Override public void notifyFailure(BError bError) { BError pubsubError = createError("Failed to subscribe to topic", bError); this.future.complete(pubsubError); diff --git a/native/src/main/java/io/xlibb/pubsub/PubSub.java b/native/src/main/java/io/xlibb/pubsub/PubSub.java index 03e1a4e..a03c0ab 100644 --- a/native/src/main/java/io/xlibb/pubsub/PubSub.java +++ b/native/src/main/java/io/xlibb/pubsub/PubSub.java @@ -17,11 +17,8 @@ package io.xlibb.pubsub; import io.ballerina.runtime.api.Environment; -import io.ballerina.runtime.api.Future; -import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; -import io.ballerina.runtime.api.types.StreamType; import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.values.BArray; @@ -32,6 +29,8 @@ import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; +import java.util.concurrent.CompletableFuture; + import static io.xlibb.pubsub.utils.Utils.AUTO_CREATE_TOPICS; import static io.xlibb.pubsub.utils.Utils.CONSUME_STREAM_METHOD; import static io.xlibb.pubsub.utils.Utils.IS_CLOSED; @@ -40,6 +39,7 @@ import static io.xlibb.pubsub.utils.Utils.TIMER_FIELD_NAME; import static io.xlibb.pubsub.utils.Utils.TOPICS; import static io.xlibb.pubsub.utils.Utils.createError; +import static io.xlibb.pubsub.utils.Utils.getResult; /** * Provides a message communication model with publish/subscribe APIs. @@ -62,16 +62,19 @@ public static Object subscribe(Environment environment, BObject pubsub, BString } catch (BError bError) { return bError; } - Object[] arguments = new Object[]{timeout, true, typeParam, true}; - Future future = environment.markAsync(); - StreamType streamType = TypeCreator.createStreamType(typeParam.getDescribingType(), - TypeCreator.createUnionType(PredefinedTypes.TYPE_ERROR, - PredefinedTypes.TYPE_NULL)); + Object[] arguments = new Object[]{timeout, typeParam}; + CompletableFuture future = new CompletableFuture<>(); MethodCallback callback = new MethodCallback(future); - environment.getRuntime() - .invokeMethodAsyncConcurrently(pipe, CONSUME_STREAM_METHOD, null, null, callback, null, streamType, - arguments); - return null; + Thread.startVirtualThread(() -> { + try { + Object result = environment.getRuntime().startIsolatedWorker(pipe, CONSUME_STREAM_METHOD, null, + null, null, arguments).get(); + callback.notifySuccess(result); + } catch (BError bError) { + callback.notifyFailure(bError); + } + }); + return getResult(future); } @SuppressWarnings("unchecked") diff --git a/native/src/main/java/io/xlibb/pubsub/utils/Utils.java b/native/src/main/java/io/xlibb/pubsub/utils/Utils.java index 2b57c68..7c0b86b 100644 --- a/native/src/main/java/io/xlibb/pubsub/utils/Utils.java +++ b/native/src/main/java/io/xlibb/pubsub/utils/Utils.java @@ -21,6 +21,8 @@ import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BString; +import java.util.concurrent.CompletableFuture; + import static io.xlibb.pubsub.utils.ModuleUtils.getModule; /** @@ -48,4 +50,12 @@ public static BError createError(String message) { public static BError createError(String message, BError cause) { return ErrorCreator.createError(getModule(), ERROR_TYPE, StringUtils.fromString(message), cause, null); } + + public static Object getResult(CompletableFuture balFuture) { + try { + return balFuture.get(); + } catch (Throwable throwable) { + throw ErrorCreator.createError(throwable); + } + } }