From 8ca175b0480e00fe3ec38fcb7544fe241b265cdf Mon Sep 17 00:00:00 2001 From: William Chong Date: Mon, 31 Mar 2025 19:32:18 +0400 Subject: [PATCH 1/6] chore: use github var for kurrentdb images (#317) --- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 97 ++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 + .../{pull-requests.yml => build.yml} | 93 +++----- .github/workflows/ci.yml | 19 ++ .github/workflows/docker-repo.yml | 49 ---- .github/workflows/lts.yml | 28 +++ .github/workflows/plugins-tests.yml | 22 +- .github/workflows/previous-lts.yml | 19 ++ .../workflows/{release.yml => publish.yml} | 2 +- .github/workflows/qa.yml | 17 ++ .github/workflows/test-dispatch.yml | 22 -- .github/workflows/tests.yml | 47 ++-- README.md | 217 +++--------------- docker-compose.yml | 2 +- .../io/kurrent/dbclient/DatabaseFactory.java | 10 +- .../databases/DockerContainerDatabase.java | 21 +- 16 files changed, 294 insertions(+), 379 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml rename .github/workflows/{pull-requests.yml => build.yml} (55%) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/docker-repo.yml create mode 100644 .github/workflows/lts.yml create mode 100644 .github/workflows/previous-lts.yml rename .github/workflows/{release.yml => publish.yml} (90%) create mode 100644 .github/workflows/qa.yml delete mode 100644 .github/workflows/test-dispatch.yml diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml new file mode 100644 index 00000000..06b004be --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -0,0 +1,97 @@ +name: Bug report +description: Help us improve the Java client +labels: + - triage +body: + - type: textarea + id: current-behavior + attributes: + label: 🐛 Current behavior + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: reproduction-steps + attributes: + label: 🔍 Steps to reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to ... + 2. Click on ... + 3. Scroll down to ... + 4. See error + + You can attach screenshots by dragging and dropping, or selecting and pasting them in the text field. + validations: + required: true + - type: input + id: reproduction-links + attributes: + label: Reproducible link + description: A link to a minimal reproducible example. This could be a GitHub repository, CodeSandbox, or any other online code editor. + placeholder: e.g, github.com/company/repo + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: 💭 Expected behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true + - type: input + id: client-version + attributes: + label: Package version + description: What version of the client you're experiencing the issue with. + placeholder: e.g., kurrentdb-client 1.1.2 + validations: + required: true + - type: input + id: kurrentdb-version + attributes: + label: KurrentDB Version + description: What version of the database you are using. + placeholder: e.g., KurrentDB v24.10 + validations: + required: true + - type: input + id: connection + attributes: + label: Connection string + description: What connection string you're using. Hide and sensitive information if necessary. + placeholder: e.g., kurrentdb://admin:changeit@localhost:2113 + validations: + required: true + - type: dropdown + id: deployment-environment + attributes: + label: ☁️ Deployment Environment + description: How is KurrentDB deployed? + options: + - Single-node (Docker) + - Single-node (Bare metal/VM) + - Multi-node cluster (On-prem) + - Multi-node cluster (Cloud) + - Managed KurrentDB Cloud + - Other (please specify below) + validations: + required: true + - type: input + id: deployment-other + attributes: + label: Other Deployment Details + description: If you selected "Other," please specify your deployment setup. + placeholder: e.g., Kubernetes with custom networking + - type: input + id: os + attributes: + label: Operating system + placeholder: e.g., macOS 13.1 + - type: checkboxes + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/algolia/.github/blob/main/CODE_OF_CONDUCT.md). + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..5e587d78 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Feature Request + url: https://github.com/kurrent-io/KurrentDB-Client-Java/discussions/new?category=ideas&labels=triage&title=Feature%20request%3A%20 + about: Request a feature to add to the client + - name: Ask a Question + url: https://github.com/kurrent-io/KurrentDB-Client-Java/discussions/new?category=q-a&labels=triage + about: Ask questions and discuss with other community members. \ No newline at end of file diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/build.yml similarity index 55% rename from .github/workflows/pull-requests.yml rename to .github/workflows/build.yml index 0f1e1ec8..b13e573e 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/build.yml @@ -1,59 +1,34 @@ -name: Build and Run Tests -on: [pull_request] -jobs: - build: - name: Build - strategy: - fail-fast: false - matrix: - java: [8, 11, 17] - runs-on: ubuntu-latest - - steps: - - name: Check Out Sources - uses: actions/checkout@v4 - - - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'temurin' - - - name: Setup Gradle - uses: gradle/gradle-build-action@v3 - with: - gradle-version: 8.13 - - - name: Build - run: ./gradlew compileTest - - # Tests that do not require a database connection. - - name: Misc tests - run: ./gradlew ci --tests MiscTests - - tests: - needs: build - name: Tests - - strategy: - fail-fast: false - matrix: - version: [previous-lts, lts, latest, ci] - - uses: ./.github/workflows/tests.yml - with: - kdb_version: ${{ matrix.version }} - - plugins-tests: - needs: build - name: Plugins Tests - - strategy: - fail-fast: false - matrix: - version: [24.2.0-jammy] - - uses: ./.github/workflows/plugins-tests.yml - with: - kdb_version: ${{ matrix.version }} - secrets: inherit \ No newline at end of file +name: Build and Run Tests +on: + workflow_call: + +jobs: + build: + name: Build + strategy: + fail-fast: false + matrix: + java: [ 8, 11, 17 ] + runs-on: ubuntu-latest + + steps: + - name: Check Out Sources + uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v3 + with: + gradle-version: 8.13 + + - name: Build + run: ./gradlew compileTest + + # Tests that do not require a database connection. + - name: Misc tests + run: ./gradlew ci --tests MiscTests diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..9dba48c9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: CI +on: + pull_request: + push: + branches: + - trunk + schedule: + - cron: '0 0 * * 0' # Run every Sunday at midnight UTC + +jobs: + build: + uses: ./.github/workflows/build.yml + + ci: + name: Tests (CI) + uses: ./.github/workflows/tests.yml + with: + image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES).ci.fullname }} + secrets: inherit diff --git a/.github/workflows/docker-repo.yml b/.github/workflows/docker-repo.yml deleted file mode 100644 index 8300d406..00000000 --- a/.github/workflows/docker-repo.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Get ESDB Docker repo -on: - workflow_call: - inputs: - runtime_env: - description: The runtime environment we want to run like release or staging - type: string - default: release - - outputs: - docker_repo: - description: ESDB docker repository - value: ${{ jobs.provide_docker.outputs.docker_repo }} - - docker_container: - description: ESDB docker container - value: ${{ jobs.provide_docker.outputs.docker_container }} - -jobs: - provide_docker: - runs-on: ubuntu-latest - outputs: - docker_repo: ${{ steps.set_docker.outputs.docker_repo }} - docker_container: ${{ steps.set_docker.outputs.docker_container }} - steps: - - name: Set ESDB docker repo - id: set_docker - run: | - case ${{ inputs.runtime_env }} in - "release") - echo "docker_repo=eventstore-ce" >> $GITHUB_OUTPUT - echo "docker_container=eventstoredb-ce" >> $GITHUB_OUTPUT - ;; - - "staging") - echo "docker_repo=eventstore-staging-ce" >> $GITHUB_OUTPUT - echo "docker_container=eventstoredb-oss" >> $GITHUB_OUTPUT - ;; - - "enterprise") - echo "docker_repo=eventstore-ee" >> $GITHUB_OUTPUT - echo "docker_container=eventstoredb-commercial" >> $GITHUB_OUTPUT - ;; - - *) - echo "docker_repo=eventstore-ce" >> $GITHUB_OUTPUT - echo "docker_container=eventstoredb-ce" >> $GITHUB_OUTPUT - ;; - esac \ No newline at end of file diff --git a/.github/workflows/lts.yml b/.github/workflows/lts.yml new file mode 100644 index 00000000..c0936f87 --- /dev/null +++ b/.github/workflows/lts.yml @@ -0,0 +1,28 @@ +name: LTS +on: + pull_request: + push: + branches: + - trunk + schedule: + - cron: '0 0 * * 0' # Run every Sunday at midnight UTC + +jobs: + build: + uses: ./.github/workflows/build.yml + + lts: + name: Tests (LTS) + uses: ./.github/workflows/tests.yml + with: + image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES).lts.fullname }} + secrets: inherit + + # Will be removed in the future + plugins-tests: + name: Plugins Tests + + uses: ./.github/workflows/plugins-tests.yml + with: + image: "docker.eventstore.com/eventstore-ee/eventstoredb-commercial:24.2.0-jammy" + secrets: inherit diff --git a/.github/workflows/plugins-tests.yml b/.github/workflows/plugins-tests.yml index b9d42291..08aed4c8 100644 --- a/.github/workflows/plugins-tests.yml +++ b/.github/workflows/plugins-tests.yml @@ -3,23 +3,12 @@ name: enterprise plugins tests workflow on: workflow_call: inputs: - runtime_env: - description: The runtime environment we want to run like release or staging - type: string - default: enterprise - - kdb_version: + image: required: true type: string jobs: - provide_docker: - uses: ./.github/workflows/docker-repo.yml - with: - runtime_env: ${{ inputs.runtime_env }} - single_node: - needs: provide_docker name: Single Node strategy: @@ -57,9 +46,7 @@ jobs: - name: Execute Gradle build run: ./gradlew ci --tests ${{ matrix.test }}Tests env: - KURRENT_DOCKER_REGISTRY_ENV: docker.eventstore.com - KURRENT_DOCKER_IMAGE_ENV: ${{ needs.provide_docker.outputs.docker_repo }}/${{ needs.provide_docker.outputs.docker_container }} - KURRENT_DOCKER_TAG_ENV: ${{ inputs.kdb_version }} + KURRENTDB_IMAGE: ${{ inputs.image }} SECURE: true - uses: actions/upload-artifact@v4 @@ -70,7 +57,6 @@ jobs: if-no-files-found: error cluster: - needs: provide_docker name: Cluster strategy: @@ -95,9 +81,7 @@ jobs: - name: Set up cluster with Docker Compose run: docker compose up -d env: - CONTAINER_REGISTRY: docker.eventstore.com - CONTAINER_IMAGE: ${{ needs.provide_docker.outputs.docker_repo }}/${{ needs.provide_docker.outputs.docker_container }} - CONTAINER_IMAGE_VERSION: ${{ inputs.kdb_version }} + KURRENTDB_IMAGE: ${{ inputs.image }} - name: Generate user certificates run: docker compose --file configure-user-certs-for-tests.yml up diff --git a/.github/workflows/previous-lts.yml b/.github/workflows/previous-lts.yml new file mode 100644 index 00000000..0fd060c2 --- /dev/null +++ b/.github/workflows/previous-lts.yml @@ -0,0 +1,19 @@ +name: Previous LTS +on: + pull_request: + push: + branches: + - trunk + schedule: + - cron: '0 0 * * 0' # Run every Sunday at midnight UTC + +jobs: + build: + uses: ./.github/workflows/build.yml + + previous-lts: + name: Tests (Previous LTS) + uses: ./.github/workflows/tests.yml + with: + image: ${{ fromJSON(vars.KURRENTDB_DOCKER_IMAGES)['previous-lts'].fullname }} + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/publish.yml similarity index 90% rename from .github/workflows/release.yml rename to .github/workflows/publish.yml index 2c363d8b..ca5ea0a3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/publish.yml @@ -14,7 +14,7 @@ on: jobs: publish: - name: Publish${{ inputs.dry_run && inputs.dry_run == 'true' && ' (dry run)' || '' }} + name: Publish runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml new file mode 100644 index 00000000..55e95730 --- /dev/null +++ b/.github/workflows/qa.yml @@ -0,0 +1,17 @@ +name: QA + +on: + workflow_dispatch: + inputs: + image: + description: Docker full image name + required: true + type: string + default: "docker.kurrent.io/eventstore/eventstoredb-ee:lts" + +jobs: + test: + name: Test + uses: ./.github/workflows/tests.yml + with: + image: ${{ inputs.image }} diff --git a/.github/workflows/test-dispatch.yml b/.github/workflows/test-dispatch.yml deleted file mode 100644 index 008c72be..00000000 --- a/.github/workflows/test-dispatch.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: "Dispatch" - -on: - workflow_dispatch: - inputs: - runtime_env: - description: The runtime environment. release, staging or enterprise - type: string - default: release - - version: - description: Docker version tag - required: true - type: string - -jobs: - test: - name: Test - uses: ./.github/workflows/tests.yml - with: - kdb_version: ${{ inputs.version }} - runtime_env: ${{ inputs.runtime_env }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3be3d690..0495aefc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,22 +3,12 @@ name: tests workflow on: workflow_call: inputs: - runtime_env: - type: string - default: release - - kdb_version: + image: required: true type: string jobs: - provide_docker: - uses: ./.github/workflows/docker-repo.yml - with: - runtime_env: ${{ inputs.runtime_env }} - single_node: - needs: provide_docker name: Single node strategy: @@ -30,6 +20,13 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Login to Cloudsmith + uses: docker/login-action@v3 + with: + registry: docker.kurrent.io + username: ${{ secrets.CLOUDSMITH_CICD_USER }} + password: ${{ secrets.CLOUDSMITH_CICD_TOKEN }} + - name: Set up JDK 8 uses: actions/setup-java@v3 with: @@ -44,9 +41,7 @@ jobs: - name: Execute Gradle build run: ./gradlew ci --tests ${{ matrix.test }}Tests env: - KURRENT_DOCKER_REGISTRY_ENV: docker.eventstore.com - KURRENT_DOCKER_IMAGE_ENV: ${{ needs.provide_docker.outputs.docker_repo }}/${{ needs.provide_docker.outputs.docker_container }} - KURRENT_DOCKER_TAG_ENV: ${{ inputs.kdb_version }} + KURRENTDB_IMAGE: ${{ inputs.image }} - uses: actions/upload-artifact@v4 if: failure() @@ -56,7 +51,6 @@ jobs: if-no-files-found: error secure: - needs: provide_docker name: Secure strategy: @@ -68,6 +62,13 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Login to Cloudsmith + uses: docker/login-action@v3 + with: + registry: docker.kurrent.io + username: ${{ secrets.CLOUDSMITH_CICD_USER }} + password: ${{ secrets.CLOUDSMITH_CICD_TOKEN }} + - name: Generate certificates run: docker compose --file configure-tls-for-tests.yml up @@ -85,9 +86,7 @@ jobs: - name: Execute Gradle build run: ./gradlew ci --tests ${{ matrix.test }}Tests env: - KURRENT_DOCKER_REGISTRY_ENV: docker.eventstore.com - KURRENT_DOCKER_IMAGE_ENV: ${{ needs.provide_docker.outputs.docker_repo }}/${{ needs.provide_docker.outputs.docker_container }} - KURRENT_DOCKER_TAG_ENV: ${{ inputs.kdb_version }} + KURRENTDB_IMAGE: ${{ inputs.image }} SECURE: true - uses: actions/upload-artifact@v4 @@ -97,7 +96,6 @@ jobs: path: /tmp/esdb_logs.tar.gz cluster: - needs: provide_docker name: Cluster strategy: @@ -109,12 +107,17 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Login to Cloudsmith + uses: docker/login-action@v3 + with: + registry: docker.kurrent.io + username: ${{ secrets.CLOUDSMITH_CICD_USER }} + password: ${{ secrets.CLOUDSMITH_CICD_TOKEN }} + - name: Set up cluster with Docker Compose run: docker compose up -d env: - CONTAINER_REGISTRY: docker.eventstore.com - CONTAINER_IMAGE: ${{ needs.provide_docker.outputs.docker_repo }}/${{ needs.provide_docker.outputs.docker_container }} - CONTAINER_IMAGE_VERSION: ${{ inputs.kdb_version }} + KURRENTDB_IMAGE: ${{ inputs.image }} - name: Set up JDK 8 uses: actions/setup-java@v3 diff --git a/README.md b/README.md index 9550f295..3f1f6909 100644 --- a/README.md +++ b/README.md @@ -8,206 +8,65 @@ # KurrentDB Java Client -[![CI](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/pull-requests.yml/badge.svg)](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/pull-requests.yml) +[![CI](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/ci.yml/badge.svg)](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/ci.yml) +[![LTS](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/lts.yml/badge.svg)](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/lts.yml) +[![Previous LTS](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/previous-lts.yml/badge.svg)](https://github.com/kurrent-io/KurrentDB-Client-Java/actions/workflows/previous-lts.yml) -KurrentDB is the event-native database, where business events are immutably stored and streamed. Designed for event-sourced, event-driven, and microservices architectures. +KurrentDB is a database that's engineered for modern software applications and event-driven architectures. Its +event-native design simplifies data modeling and preserves data integrity while the integrated streaming engine solves +distributed messaging challenges and ensures data consistency. -This repository contains an [KurrentDB][kurrent] Client SDK written in Java for use with languages on the JVM. It is -compatible with Java 8 and above. - -*Note: This client is currently under active development and further API changes are expected. Feedback is very welcome.* - -## Documentation -* General documentation can be found in [KurrentDB GRPC Docs]. - -[//]: # (* The latest stable version Javadoc can be found here: https://kurrent.github.io/Kurrent-Client-Java) +This repository contains an [KurrentDB](https://kurrent.io) Client SDK written in Java for use with languages on the +JVM. It is compatible with Java 8 and above. ## Access to binaries -Kurrent, Inc publishes GA (general availability) versions to [Maven Central]. - -### Snapshot versions - -Snapshot versions are pushed on Sonatype Snapshots Repository every time a pull request is merged in the main branch `trunk`. -The snippet below shows how to use the Sonatype Snapshots Repository using the Gradle build tool. - -```gradle -repositories { - ... - maven { - url uri('https://oss.sonatype.org/content/repositories/snapshots') - } - ... -} -``` - -## Developing - -The SDK is built using [`Gradle`][gradle]. Integration tests run against a server using Docker. - -### Run tests - -Tests are written using [TestContainers](https://www.testcontainers.org/) and require [Docker](https://www.docker.com/) to be installed. - -Specific docker images can be specified via the environment variable `EVENTSTORE_IMAGE`. -## Open Telemetry - - Tracing is the only telemetry currently exported, specifically for the `Append` and `Subscribe` (Catchup and Persistent) operations. - - For more information about Open Telemetry, refer to the [official documentation](https://opentelemetry.io/docs/what-is-opentelemetry/). +Kurrent, Inc publishes GA (general availability) versions +to [Maven Central](https://search.maven.org/artifact/io.kurrent/kurrentdb-client). ## KurrentDB Server Compatibility This client is compatible with version `20.6.1` upwards. -Server setup instructions can be found in the [docs], follow the docker setup for the simplest configuration. - -## Example - -The following snippet showcases a simple example where we form a connection, then write and read events from the server. - -Note: If testing locally using `--insecure` the url should be `kurrentdb://localhost:2113?tls=false`. - -```java -class AccountCreated { - private UUID id; - private String login; - - public UUID getId() { - return id; - } - - public String getLogin() { - return login; - } - - public void setId(UUID id) { - this.id = id; - } - - public void setLogin(String login) { - this.login = login; - } -} -``` -```java -import io.kurrent.dbclient.KurrentDBClient; -import io.kurrent.dbclient.KurrentDBClientSettings; -import io.kurrent.dbclient.KurrentDBConnectionString; -import io.kurrent.dbclient.EventData; -import io.kurrent.dbclient.ReadStreamOptions; -import io.kurrent.dbclient.ResolvedEvent; -import io.kurrent.dbclient.WriteResult; -import io.kurrent.dbclient.ReadResult; - -public class Main { - public static void main(String args[]) { - KurrentDBClientSettings setts = KurrentDBConnectionString.parseOrThrow("kurrentdb://localhost:2113"); - KurrentDBClient client = KurrentDBClient.create(setts); +Server setup instructions can be found in +the [docs](https://developers.kurrent.io/server/v25.0/quick-start/installation), follow the docker setup for the +simplest configuration. - AccountCreated createdEvent = new AccountCreated(); +### Documentation - createdEvent.setId(UUID.randomUUID()); - createdEvent.setLogin("ouros"); +* [Samples](https://github.com/kurrent-io/KurrentDB-Client-Java/tree/trunk/src/test/java/io/kurrent/dbclient/samples) - EventData event = EventData - .builderAsJson("account-created", createdEvent) - .build(); - - WriteResult writeResult = client - .appendToStream("accounts", event) - .get(); - - ReadStreamOptions readStreamOptions = ReadStreamOptions.get() - .fromStart() - .notResolveLinkTos(); - - ReadResult readResult = client - .readStream("accounts", 1, readStreamOptions) - .get(); - - ResolvedEvent resolvedEvent = readResult - .getEvents() - .get(0); - - AccountCreated writtenEvent = resolvedEvent.getOriginalEvent() - .getEventDataAs(AccountCreated.class); - - // Doing something productive... - } -} -``` - -## Projections - -This client currently supports creating and getting the result of a continuous projection. - -Create a projection: -```java -KurrentDBClientSettings setts = KurrentDBConnectionString.parseOrThrow("kurrentdb://localhost:2113"); -KurrentDBProjectionManagementClient client = KurrentDBProjectionManagementClient.create(setts); - -client - .createContinuous(PROJECTION_NAME, PROJECTION_JS) - .get(); -``` - -Define a class in which to deserialize the result: -```java -public class CountResult { - - private int count; - - public int getCount() { - return count; - } - - public void setCount(final int count) { - this.count = count; - } -} -``` - -Get the result: -```java -CountResult result = client - .getResult(PROJECTION_NAME, CountResult.class) - .get(); -``` - -For further details please see [the projection management tests](src/test/java/io/kurrent/dbclient/ProjectionManagementTests.java). +## Communities -## Support +[Join our global community](https://www.kurrent.io/community) of developers. -Information on support can be found on our website: [Kurrent Support][support] +- [Discuss](https://discuss.kurrent.io/) +- [Discord (Kurrent)](https://discord.gg/Phn9pmCw3t) +- [Discord (ddd-cqrs-es)](https://discord.com/invite/sEZGSHNNbH) -## Documentation +## Contributing -Documentation for KurrentDB can be found in the [docs]. +Development is done on the `main` branch. +We attempt to do our best to ensure that the history remains clean and to do so, we generally ask contributors to squash +their commits into a set or single logical commit. -Bear in mind that this client is not yet properly documented. We are working hard on a new version of the documentation. +- [Create an issue](https://github.com/kurrent-io/KurrentDB-Client-Java/issues) +- [Documentation](https://docs.kurrent.io/) +- [Contributing guide](https://github.com/kurrent-io/KurrentDB-Client-Java/blob/main/CONTRIBUTING.md) -## Security +### Running the tests -If you find a vulnerability in our software, please contact us. You can find how to reach out us and report it at https://www.kurrent.io/security#security -Thank you very much for supporting our software. +The client is built using [`Gradle 8.13`](https://gradle.org). Integration tests run against a server using Docker. -## Communities +Tests are written using [TestContainers](https://www.testcontainers.org/) and require [Docker](https://www.docker.com/) +to be installed. -- [Discuss](https://discuss.eventstore.com/) -- [Discord (Kurrent)](https://discord.gg/Phn9pmCw3t) +Specific docker images can be specified via the environment variable `KURRENTDB_IMAGE`. -## Contributing +## More resources -All contributions to the SDK are made via GitHub Pull Requests, and must be licensed under the Apache 2.0 license. Please -review our [Contributing Guide][contributing] and [Code of Conduct][code-of-conduct] for more information. - -[kurrent]: https://kurrent.io -[gradle]: https://gradle.org -[contributing]: https://github.com/kurrent-io/KurrentDB-Client-Java/tree/master/CONTRIBUTING.md -[code-of-conduct]: https://github.com/kurrent-io/KurrentDB-Client-Java/tree/master/CODE-OF-CONDUCT.md -[support]: https://kurrent.io/support/ -[docs]: https://developers.kurrent.io/server/v25.0/quick-start/installation/ -[discuss]: https://discuss.kurrent.io/ -[Maven Central]: https://search.maven.org/artifact/io.kurrent/kurrentdb-client -[KurrentDB GRPC Docs]: https://developers.eventstore.com/clients/grpc +- [Release notes](https://kurrent.io/blog/release-notes) +- [Beginners Guide to Event Sourcing](https://kurrent.io/event-sourcing) +- [Articles](https://kurrent.io/blog) +- [Webinars](https://kurrent.io/webinars) +- [Contact us](https://kurrent.io/contact) diff --git a/docker-compose.yml b/docker-compose.yml index 726d1710..e64e7e83 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,7 +26,7 @@ services: - volumes-provisioner esdb-node1: &template - image: ${CONTAINER_REGISTRY:-docker.eventstore.com}/${CONTAINER_IMAGE:-eventstore-ce/eventstoredb-ce}:${CONTAINER_IMAGE_VERSION:-latest} + image: ${KURRENTDB_IMAGE:-docker.kurrent.io/eventstore/eventstoredb-ee:lts} env_file: - vars.env environment: diff --git a/src/test/java/io/kurrent/dbclient/DatabaseFactory.java b/src/test/java/io/kurrent/dbclient/DatabaseFactory.java index def0103a..5f17d8cc 100644 --- a/src/test/java/io/kurrent/dbclient/DatabaseFactory.java +++ b/src/test/java/io/kurrent/dbclient/DatabaseFactory.java @@ -36,14 +36,8 @@ public static Database spawnEnterpriseWithPluginsEnabled(String... pluginsToEnab private static DockerContainerDatabase.Builder singleNodeBuilder() { return DockerContainerDatabase .builder() - .registry(Optional - .ofNullable(System.getenv("KURRENT_DOCKER_REGISTRY_ENV")) - .orElse(DockerContainerDatabase.DEFAULT_REGISTRY)) .image(Optional - .ofNullable(System.getenv("KURRENT_DOCKER_IMAGE_ENV")) - .orElse(DockerContainerDatabase.DEFAULT_IMAGE)) - .version(Optional - .ofNullable(System.getenv("KURRENT_DOCKER_TAG_ENV")) - .orElse(DockerContainerDatabase.DEFAULT_VERSION)); + .ofNullable(System.getenv("KURRENTDB_IMAGE")) + .orElse(DockerContainerDatabase.DEFAULT_IMAGE)); } } diff --git a/src/test/java/io/kurrent/dbclient/databases/DockerContainerDatabase.java b/src/test/java/io/kurrent/dbclient/databases/DockerContainerDatabase.java index 91249a17..8435e70e 100644 --- a/src/test/java/io/kurrent/dbclient/databases/DockerContainerDatabase.java +++ b/src/test/java/io/kurrent/dbclient/databases/DockerContainerDatabase.java @@ -12,22 +12,16 @@ import java.util.Map; public class DockerContainerDatabase extends GenericContainer implements Database { - public static final String DEFAULT_REGISTRY = "docker.eventstore.com"; - public static final String DEFAULT_IMAGE = "eventstore-ce/eventstoredb-ce"; - public static final String DEFAULT_VERSION = "latest"; + public static final String DEFAULT_IMAGE = "docker.kurrent.io/eventstore/eventstoredb-ee:lts"; public static class Builder { - String registry; String image; - String version; boolean secure; boolean anonymous; Map env; public Builder() { - this.registry = DEFAULT_REGISTRY; this.image = DEFAULT_IMAGE; - this.version = DEFAULT_VERSION; this.env = new HashMap<>(); } @@ -36,11 +30,6 @@ public Builder secure(boolean secure) { return this; } - public Builder version(String version) { - this.version = version; - return this; - } - public Builder anonymous(boolean anonymous) { this.anonymous = anonymous; return this; @@ -50,12 +39,6 @@ public Builder image(String image) { this.image = image; return this; } - - public Builder registry(String registry) { - this.registry = registry; - return this; - } - public Builder env(String envVar, String value) { this.env.put(envVar, value); return this; @@ -70,7 +53,7 @@ public DockerContainerDatabase build() { private final ClientTracker clientTracker; public DockerContainerDatabase(Builder builder) { - super(String.format("%s/%s:%s", builder.registry, builder.image, builder.version)); + super(builder.image); addExposedPorts(1113, 2113); withEnv("EVENTSTORE_RUN_PROJECTIONS", "ALL"); From 5f09768163b1664aef38119730ad7d8af98eb418 Mon Sep 17 00:00:00 2001 From: Paulo Borges Date: Wed, 16 Apr 2025 01:52:01 -0300 Subject: [PATCH 2/6] docs: change connection string (#318) --- src/main/java/io/kurrent/dbclient/KurrentDBClientSettings.java | 2 +- .../dbclient/samples/authentication/UserCertificate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/kurrent/dbclient/KurrentDBClientSettings.java b/src/main/java/io/kurrent/dbclient/KurrentDBClientSettings.java index 8b0ae2a9..44580d66 100644 --- a/src/main/java/io/kurrent/dbclient/KurrentDBClientSettings.java +++ b/src/main/java/io/kurrent/dbclient/KurrentDBClientSettings.java @@ -7,7 +7,7 @@ import java.util.Set; /** - * Gathers all the settings related to a gRPC client with an KurrentDB database. + * Gathers all the settings related to a gRPC client with a KurrentDB database. * EventStoreDBClientSettings} can only be created when parsing a connection string. * * KurrentDBClientSettings supports a wide range of settings. If a setting is not mentioned in the connection diff --git a/src/test/java/io/kurrent/dbclient/samples/authentication/UserCertificate.java b/src/test/java/io/kurrent/dbclient/samples/authentication/UserCertificate.java index ede2d2e3..023e6295 100644 --- a/src/test/java/io/kurrent/dbclient/samples/authentication/UserCertificate.java +++ b/src/test/java/io/kurrent/dbclient/samples/authentication/UserCertificate.java @@ -8,7 +8,7 @@ public class UserCertificate { private static void tracing() { // region client-with-user-certificates KurrentDBClientSettings settings = KurrentDBConnectionString - .parseOrThrow("esdb://admin:changeit@{endpoint}?tls=true&userCertFile={pathToCaFile}&userKeyFile={pathToKeyFile}"); + .parseOrThrow("kurrentdb://admin:changeit@{endpoint}?tls=true&userCertFile={pathToCaFile}&userKeyFile={pathToKeyFile}"); KurrentDBClient client = KurrentDBClient.create(settings); // endregion client-with-user-certificates } From 36665ae991f0b9c22abf9ab03ba16920edbc4dbb Mon Sep 17 00:00:00 2001 From: William Chong Date: Wed, 16 Apr 2025 10:24:58 +0400 Subject: [PATCH 3/6] chore: improve test coverage for connection shutdown (#320) --- build.gradle | 2 + .../connection/ConnectionShutdownTests.java | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/test/java/io/kurrent/dbclient/connection/ConnectionShutdownTests.java diff --git a/build.gradle b/build.gradle index 1a6ac04d..1beb8d7d 100644 --- a/build.gradle +++ b/build.gradle @@ -131,6 +131,7 @@ tasks.register("singleNodeTests", Test) { include("**/StreamsTests.class") include("**/PersistentSubscriptionsTests.class") include("**/TelemetryTests.class") + include("**/ConnectionShutdownTests.class") } } @@ -153,6 +154,7 @@ tasks.register("clusterTests", Test) { useJUnitPlatform { include("**/StreamsTests.class") include("**/PersistentSubscriptionsTests.class") + include("**/ConnectionShutdownTests.class") } } diff --git a/src/test/java/io/kurrent/dbclient/connection/ConnectionShutdownTests.java b/src/test/java/io/kurrent/dbclient/connection/ConnectionShutdownTests.java new file mode 100644 index 00000000..0afe060e --- /dev/null +++ b/src/test/java/io/kurrent/dbclient/connection/ConnectionShutdownTests.java @@ -0,0 +1,62 @@ +package io.kurrent.dbclient.connection; + +import io.kurrent.dbclient.*; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class ConnectionShutdownTests { + @Test + @Timeout(value = 1, unit = TimeUnit.MINUTES) + public void testDatabaseCleanupWithActiveSubscription() throws Throwable { + Database testDatabase = DatabaseFactory.spawn(); + KurrentDBClient client = testDatabase.defaultClient(); + + final AtomicInteger count = new AtomicInteger(0); + final AtomicInteger retryCount = new AtomicInteger(-1); + final AtomicBoolean cancellationReceived = new AtomicBoolean(false); + final CountDownLatch cancellationLatch = new CountDownLatch(1); + final AtomicReference reconnectError = new AtomicReference<>(); + + SubscriptionListener listener = new SubscriptionListener() { + @Override + public void onEvent(Subscription subscription, ResolvedEvent event) { + count.incrementAndGet(); + } + + @Override + public void onCancelled(Subscription subscription, Throwable throwable) { + cancellationReceived.set(true); + + retryCount.incrementAndGet(); + + try { + client.subscribeToAll(this).get(10, TimeUnit.SECONDS); + } catch (Throwable ex) { + reconnectError.set(ex); + } finally { + cancellationLatch.countDown(); + } + } + }; + + client.subscribeToAll(listener).get(); + + testDatabase.dispose(); + + boolean callbackReceived = cancellationLatch.await(30, TimeUnit.SECONDS); + Assertions.assertTrue(callbackReceived); + Assertions.assertTrue(cancellationReceived.get()); + Assertions.assertTrue(count.get() > 0); + Assertions.assertEquals(2, retryCount.get()); + + Throwable ex = reconnectError.get(); + Assertions.assertInstanceOf(ConnectionShutdownException.class, ex.getCause()); + } +} From 6dfea76287b7307a127be0ae2727ae9aefd17d43 Mon Sep 17 00:00:00 2001 From: William Chong Date: Fri, 25 Apr 2025 08:47:30 +0400 Subject: [PATCH 4/6] fix: client telemetry attribute names (#321) --- src/main/java/io/kurrent/dbclient/ClientTelemetry.java | 10 +++++----- .../io/kurrent/dbclient/ClientTelemetryAttributes.java | 10 +++++----- .../io/kurrent/dbclient/ClientTelemetryConstants.java | 2 +- .../io/kurrent/dbclient/telemetry/TelemetryAware.java | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/kurrent/dbclient/ClientTelemetry.java b/src/main/java/io/kurrent/dbclient/ClientTelemetry.java index 4ed0be83..4d180053 100644 --- a/src/main/java/io/kurrent/dbclient/ClientTelemetry.java +++ b/src/main/java/io/kurrent/dbclient/ClientTelemetry.java @@ -94,7 +94,7 @@ static CompletableFuture traceAppend( SpanKind.CLIENT, null, ClientTelemetryTags.builder() - .withRequiredTag(ClientTelemetryAttributes.Kurrent.STREAM, streamId) + .withRequiredTag(ClientTelemetryAttributes.KurrentDB.STREAM, streamId) .withServerTagsFromGrpcChannel(channel) .withServerTagsFromClientSettings(settings) .withOptionalDatabaseUserTag(settings.getDefaultCredentials()) @@ -139,10 +139,10 @@ static void traceSubscribe(Runnable tracedOperation, String subscriptionId, Mana SpanKind.CONSUMER, remoteParentContext, ClientTelemetryTags.builder() - .withRequiredTag(ClientTelemetryAttributes.Kurrent.STREAM, event.getStreamId()) - .withRequiredTag(ClientTelemetryAttributes.Kurrent.SUBSCRIPTION_ID, subscriptionId) - .withRequiredTag(ClientTelemetryAttributes.Kurrent.EVENT_ID, event.getEventId().toString()) - .withRequiredTag(ClientTelemetryAttributes.Kurrent.EVENT_TYPE, event.getEventType()) + .withRequiredTag(ClientTelemetryAttributes.KurrentDB.STREAM, event.getStreamId()) + .withRequiredTag(ClientTelemetryAttributes.KurrentDB.SUBSCRIPTION_ID, subscriptionId) + .withRequiredTag(ClientTelemetryAttributes.KurrentDB.EVENT_ID, event.getEventId().toString()) + .withRequiredTag(ClientTelemetryAttributes.KurrentDB.EVENT_TYPE, event.getEventType()) .withServerTagsFromGrpcChannel(channel) .withServerTagsFromClientSettings(settings) .withOptionalDatabaseUserTag(settings.getDefaultCredentials()) diff --git a/src/main/java/io/kurrent/dbclient/ClientTelemetryAttributes.java b/src/main/java/io/kurrent/dbclient/ClientTelemetryAttributes.java index 6dceab3b..8fc30741 100644 --- a/src/main/java/io/kurrent/dbclient/ClientTelemetryAttributes.java +++ b/src/main/java/io/kurrent/dbclient/ClientTelemetryAttributes.java @@ -22,10 +22,10 @@ public static class Exceptions { public static final String STACK_TRACE = ExceptionAttributes.EXCEPTION_STACKTRACE.getKey(); } - public static class Kurrent { - public static final String STREAM = "db.kurrent.stream"; - public static final String SUBSCRIPTION_ID = "db.kurrent.subscription.id"; - public static final String EVENT_ID = "db.kurrent.event.id"; - public static final String EVENT_TYPE = "db.kurrent.event.type"; + public static class KurrentDB { + public static final String STREAM = "db.kurrentdb.stream"; + public static final String SUBSCRIPTION_ID = "db.kurrentdb.subscription.id"; + public static final String EVENT_ID = "db.kurrentdb.event.id"; + public static final String EVENT_TYPE = "db.kurrentdb.event.type"; } } diff --git a/src/main/java/io/kurrent/dbclient/ClientTelemetryConstants.java b/src/main/java/io/kurrent/dbclient/ClientTelemetryConstants.java index e7479d7c..5b5f359c 100644 --- a/src/main/java/io/kurrent/dbclient/ClientTelemetryConstants.java +++ b/src/main/java/io/kurrent/dbclient/ClientTelemetryConstants.java @@ -1,7 +1,7 @@ package io.kurrent.dbclient; public class ClientTelemetryConstants { - public static final String INSTRUMENTATION_NAME = "kurrent"; + public static final String INSTRUMENTATION_NAME = "kurrentdb"; public static class Metadata { public static final String TRACE_ID = "$traceId"; diff --git a/src/test/java/io/kurrent/dbclient/telemetry/TelemetryAware.java b/src/test/java/io/kurrent/dbclient/telemetry/TelemetryAware.java index 5c5c24ae..edf0e9d0 100644 --- a/src/test/java/io/kurrent/dbclient/telemetry/TelemetryAware.java +++ b/src/test/java/io/kurrent/dbclient/telemetry/TelemetryAware.java @@ -21,7 +21,7 @@ public interface TelemetryAware extends ConnectionAware { default void assertAppendSpanHasExpectedAttributes(ReadableSpan span, String streamName) { assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.SYSTEM, ClientTelemetryConstants.INSTRUMENTATION_NAME); assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.OPERATION, ClientTelemetryConstants.Operations.APPEND); - assertSpanAttributeEquals(span, ClientTelemetryAttributes.Kurrent.STREAM, streamName); + assertSpanAttributeEquals(span, ClientTelemetryAttributes.KurrentDB.STREAM, streamName); assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.USER, "admin"); Assertions.assertEquals(StatusCode.OK, span.toSpanData().getStatus().getStatusCode()); Assertions.assertEquals(SpanKind.CLIENT, span.getKind()); @@ -42,10 +42,10 @@ default void assertSubscriptionActivityHasExpectedAttributes(ReadableSpan span, assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.SYSTEM, ClientTelemetryConstants.INSTRUMENTATION_NAME); assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.OPERATION, ClientTelemetryConstants.Operations.SUBSCRIBE); assertSpanAttributeEquals(span, ClientTelemetryAttributes.Database.USER, "admin"); - assertSpanAttributeEquals(span, ClientTelemetryAttributes.Kurrent.STREAM, streamName); - assertSpanAttributeEquals(span, ClientTelemetryAttributes.Kurrent.SUBSCRIPTION_ID, subscriptionId); - assertSpanAttributeEquals(span, ClientTelemetryAttributes.Kurrent.EVENT_ID, eventId); - assertSpanAttributeEquals(span, ClientTelemetryAttributes.Kurrent.EVENT_TYPE, eventType); + assertSpanAttributeEquals(span, ClientTelemetryAttributes.KurrentDB.STREAM, streamName); + assertSpanAttributeEquals(span, ClientTelemetryAttributes.KurrentDB.SUBSCRIPTION_ID, subscriptionId); + assertSpanAttributeEquals(span, ClientTelemetryAttributes.KurrentDB.EVENT_ID, eventId); + assertSpanAttributeEquals(span, ClientTelemetryAttributes.KurrentDB.EVENT_TYPE, eventType); Assertions.assertEquals(StatusCode.OK, span.toSpanData().getStatus().getStatusCode()); Assertions.assertEquals(SpanKind.CONSUMER, span.getKind()); } From d0687623ae8945d115c3363e93ebefc6daf45423 Mon Sep 17 00:00:00 2001 From: William Chong Date: Fri, 25 Apr 2025 11:18:48 +0400 Subject: [PATCH 5/6] Document read reactive (#322) --- .../samples/reading_events/ReadingEvents.java | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/src/test/java/io/kurrent/dbclient/samples/reading_events/ReadingEvents.java b/src/test/java/io/kurrent/dbclient/samples/reading_events/ReadingEvents.java index 02064b36..9098358d 100644 --- a/src/test/java/io/kurrent/dbclient/samples/reading_events/ReadingEvents.java +++ b/src/test/java/io/kurrent/dbclient/samples/reading_events/ReadingEvents.java @@ -3,9 +3,12 @@ import io.kurrent.dbclient.*; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import org.reactivestreams.*; +import org.reactivestreams.Subscription; import java.util.concurrent.ExecutionException; +@SuppressWarnings("ALL") public class ReadingEvents { private static void readFromStream(KurrentDBClient client) throws ExecutionException, InterruptedException, JsonProcessingException { // region read-from-stream @@ -16,6 +19,9 @@ private static void readFromStream(KurrentDBClient client) throws ExecutionExcep ReadResult result = client.readStream("some-stream", options) .get(); + + // or using read reactive + Publisher publisher = client.readStreamReactive("some-stream", options); // endregion read-from-stream // region iterate-stream @@ -23,6 +29,31 @@ private static void readFromStream(KurrentDBClient client) throws ExecutionExcep RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion iterate-stream } @@ -36,6 +67,8 @@ private static void readFromStreamPosition(KurrentDBClient client) throws Execut ReadResult result = client.readStream("some-stream", options) .get(); + // or using read reactive + Publisher publisher = client.readStreamReactive("some-stream", options); // endregion read-from-stream-position // region iterate-stream @@ -43,6 +76,31 @@ private static void readFromStreamPosition(KurrentDBClient client) throws Execut RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion iterate-stream } @@ -55,6 +113,9 @@ private static void readStreamOverridingUserCredentials(KurrentDBClient client) ReadResult result = client.readStream("some-stream", options) .get(); + + // Or using reactive stream + Publisher publisher = client.readStreamReactive("some-stream", options); // endregion overriding-user-credentials } @@ -81,6 +142,39 @@ private static void readFromStreamPositionCheck(KurrentDBClient client) throws J RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + Publisher publisher = client.readStreamReactive("some-stream", options); + + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + Throwable innerException = throwable.getCause(); + + if (innerException instanceof StreamNotFoundException) { + return; + } + // Handle other errors + } + + @Override + public void onComplete() { + } + }); // endregion checking-for-stream-presence } @@ -97,6 +191,33 @@ private static void readFromStreamBackwards(KurrentDBClient client) throws JsonP RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + Publisher publisher = client.readStreamReactive("some-stream", options); + + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion reading-backwards } @@ -109,6 +230,8 @@ private static void readFromAllStream(KurrentDBClient client) throws JsonProcess ReadResult result = client.readAll(options) .get(); + // or using read reactive + Publisher publisher = client.readAllReactive(options); // endregion read-from-all-stream // region read-from-all-stream-iterate @@ -116,6 +239,31 @@ private static void readFromAllStream(KurrentDBClient client) throws JsonProcess RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion read-from-all-stream-iterate } @@ -128,6 +276,9 @@ private static void readAllOverridingUserCredentials(KurrentDBClient client) thr ReadResult result = client.readAll(options) .get(); + + // or using read reactive + Publisher publisher = client.readAllReactive(options); // endregion read-all-overriding-user-credentials } @@ -147,6 +298,38 @@ private static void ignoreSystemEvents(KurrentDBClient client) throws JsonProces } System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + Publisher publisher = client.readAllReactive(options); + + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + + if (recordedEvent.getEventType().startsWith("$")) { + return; + } + + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion ignore-system-events } @@ -159,6 +342,8 @@ private static void readFromAllStreamBackwards(KurrentDBClient client) throws Js ReadResult result = client.readAll(options) .get(); + // or using read reactive + Publisher publisher = client.readAllReactive(options); // endregion read-from-all-stream-backwards // region read-from-all-stream-iterate @@ -166,6 +351,31 @@ private static void readFromAllStreamBackwards(KurrentDBClient client) throws Js RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); // endregion read-from-all-stream-iterate } @@ -184,6 +394,36 @@ private static void filteringOutSystemEvents(KurrentDBClient client) throws Json } System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); } + + // or using read reactive + Publisher publisher = client.readAllReactive(options); + + publisher.subscribe(new Subscriber() { + @Override + public void onSubscribe(Subscription subscription) { + } + + @Override + public void onNext(ReadMessage readMessage) { + RecordedEvent recordedEvent = readMessage.getEvent().getOriginalEvent(); + if (!recordedEvent.getEventType().startsWith("$")) { + return; + } + try { + System.out.println(new ObjectMapper().writeValueAsString(recordedEvent.getEventData())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + public void onError(Throwable throwable) { + } + + @Override + public void onComplete() { + } + }); } private static void readFromStreamResolvingLinkTos(KurrentDBClient client) throws JsonProcessingException, ExecutionException, InterruptedException { @@ -196,6 +436,9 @@ private static void readFromStreamResolvingLinkTos(KurrentDBClient client) throw ReadResult result = client.readAll(options) .get(); + // or using read reactive + Publisher publisher = client.readAllReactive(options); + // endregion read-from-all-stream-resolving-link-Tos for (ResolvedEvent resolvedEvent : result.getEvents()) { RecordedEvent recordedEvent = resolvedEvent.getOriginalEvent(); From 26c72a23fa0bac69c68362c69f76bb242b2682b0 Mon Sep 17 00:00:00 2001 From: William Chong Date: Mon, 28 Apr 2025 10:11:04 +0400 Subject: [PATCH 6/6] Prepare 1.0.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1beb8d7d..b06e3ba9 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ tasks.withType(JavaCompile) { } group = 'io.kurrent' -version = '1.0.0' +version = '1.0.1' java { withSourcesJar()